Server 0.0.1
HTTP/REST server implementation

include/http/parser.h File Reference

#include "class.h"
#include "http/message.h"
#include "http/message/queue.h"
#include "cbuf.h"
#include "stream.h"
#include "commons.h"
Include dependency graph for parser.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  HttpParser

Defines

#define PARSER_MAX_BUF   131072

Typedefs

typedef enum e_HttpMessageState HttpMessageState

Enumerations

enum  e_HttpMessageState {
  HTTP_MESSAGE_GARBAGE = 0, HTTP_MESSAGE_START, HTTP_MESSAGE_INTRO_DONE, HTTP_MESSAGE_HEADERS_DONE,
  HTTP_MESSAGE_DONE
}

Functions

ssize_t httpParserParse (void *, Stream)
void httpParserRequestVars (HttpParser)
void httpParserHeader (HttpParser, const char *, const char *)
void httpParserNewMessage (HttpParser, const char *, const char *lend)
size_t httpParserBody (HttpParser, const char *, size_t)
void httpParserPostVars (HttpParser)

Detailed Description

Parse requests from an input stream.

Author:
Georg Hopp

Copyright © 2012 Georg Hopp

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.

Definition in file parser.h.


Define Documentation

#define PARSER_MAX_BUF   131072

Definition at line 35 of file parser.h.


Typedef Documentation


Enumeration Type Documentation

Enumerator:
HTTP_MESSAGE_GARBAGE 
HTTP_MESSAGE_START 
HTTP_MESSAGE_INTRO_DONE 
HTTP_MESSAGE_HEADERS_DONE 
HTTP_MESSAGE_DONE 

Definition at line 38 of file parser.h.


Function Documentation

size_t httpParserBody ( HttpParser  ,
const char *  ,
size_t   
)

Definition at line 34 of file p_body.c.

{
        size_t      len     = 0;
        HttpMessage current = this->current;

        if (current->dbody < current->nbody) {
                len = MIN(current->nbody - current->dbody, nbuf);

                memcpy(current->body, buf, len);

                current->dbody += len;
        }

        return len;
}

Here is the caller graph for this function:

void httpParserHeader ( HttpParser  ,
const char *  ,
const char *   
)

Definition at line 35 of file p_header.c.

{
        const char * name    = line;
        char *       value   = memchr(line, ':', lend - line);
        size_t       nname   = (value++) - name;
        HttpMessage  current = this->current;

        if (NULL == value) {
                return;
        }

        for (; *value == ' ' && value < lend; value++);

        if (value == lend) {
                return;
        }

        if (0 == strncasecmp("content-length", name, nname-1)) {
                current->nbody = strtoul(value, NULL, 10);
                if (0 < this->current->nbody) {
                        current->body  = malloc(current->nbody);
                }
                current->dbody = 0;
        }

        if (0 == strncasecmp("cookie", name, nname-1)) {
                HttpRequest request = (HttpRequest)this->current;
                char *  pair = value;
                ssize_t togo = lend - value;

                while(NULL != pair && 0 < togo) {
                        char * key    = pair;
                        char * eqsign;
                        char * val;
                        size_t nval;

                        for (; *key == ' ' && key < lend; key++, togo--);
                        eqsign = memchr(key, '=', togo);

                        if (NULL == eqsign) {
                                break;
                        }

                        togo -= (eqsign - key);
                        pair  = memchr(eqsign, ';', togo);

                        if (NULL == pair) {
                                pair = (char *)lend;
                        }

                        nval = pair-eqsign-1;
                        val  = (0 != nval)? eqsign+1 : NULL;

                        hashAdd(request->cookies,
                                        new(HashValue, key, eqsign-key, val, nval));

                        pair++;
                        togo -= (pair - eqsign);
                }
        }

        hashAdd(current->header,
                        new(HttpHeader, name, nname, value, lend - value));
}

Here is the call graph for this function:

Here is the caller graph for this function:

void httpParserNewMessage ( HttpParser  ,
const char *  ,
const char *  lend 
)

Definition at line 28 of file new_message.c.

{
        const char * part1, * part2, * part3;
        size_t       len1, len2, len3;

        part1 = line;
        part2 = memchr(line, ' ', lend - line);

        if (NULL == part2) return;

        len1 = part2 - part1;
        for (; *part2 == ' ' && *part2 != 0; part2++);

        part3 = memchr(part2, ' ', lend - part2);

        if (NULL == part3) return;

        len2 = part3 - part2;
        for (; *part3 == ' ' && *part3 != 0; part3++);

        len3 = lend - part3;

        this->current = httpGetMessage(part1, len1, part2, len2, part3, len3);
}

Here is the call graph for this function:

Here is the caller graph for this function:

ssize_t httpParserParse ( void *  ,
Stream   
)

do we have form data??

> then parse them...

enqueue current request

prepare for next request

Definition at line 40 of file parse.c.

{
        HttpParser this = _this;
        int        cont = 1;
        ssize_t    read;
        char *     line;
        char *     line_end;

        if (cbufIsLocked(this->buffer)) {
                if (FALSE == this->ourLock)
                        return 0;
        }
        else {
                cbufLock(this->buffer);
                this->ourLock = TRUE;
        }

        if (NULL != this->incomplete) {
                cbufSetData(this->buffer, this->incomplete, this->isize);
                free(this->incomplete);
                this->incomplete = NULL;
        }

        if (0 > (read = cbufRead(this->buffer, st))) {
                return read;
        }

        while (cont) {
                switch(this->state) {
                        case HTTP_MESSAGE_GARBAGE:
                                cbufSkipNonAlpha(this->buffer);
                                if (! cbufIsEmpty(this->buffer)) {
                                        this->state = HTTP_MESSAGE_START;
                                }
                                else {
                                        cbufRelease(this->buffer);
                                        this->ourLock = FALSE;
                                        cont          = 0;
                                }

                                break;

                        case HTTP_MESSAGE_START:
                                if (NULL == (line = cbufGetLine(this->buffer, &line_end))) {
                                        if (! cbufIsEmpty(this->buffer)) {
                                                this->isize = this->buffer->bused;
                                                this->incomplete = malloc(this->isize);
                                                memcpy(this->incomplete,
                                                                cbufGetData(this->buffer, this->isize),
                                                                this->isize);
                                        }
                                        cbufRelease(this->buffer);
                                        this->ourLock = FALSE;
                                        cont = 0;
                                        break;
                                }
                                
                                httpParserNewMessage(this, line, line_end);
                                if (NULL == this->current) {
                                        cbufRelease(this->buffer);
                                        this->ourLock = FALSE;
                                        return -1;
                                }
                                httpParserRequestVars(this);

                                this->state = HTTP_MESSAGE_INTRO_DONE;
                                break;

                        case HTTP_MESSAGE_INTRO_DONE:
                                if (NULL == (line = cbufGetLine(this->buffer, &line_end))) {
                                        if (! cbufIsEmpty(this->buffer)) {
                                                this->isize = this->buffer->bused;
                                                this->incomplete = malloc(this->isize);
                                                memcpy(this->incomplete,
                                                                cbufGetData(this->buffer, this->isize),
                                                                this->isize);
                                        }
                                        cbufRelease(this->buffer);
                                        this->ourLock = FALSE;
                                        cont = 0;
                                        break;
                                }

                                if (0 == strlen(line)) {
                                        this->state = HTTP_MESSAGE_HEADERS_DONE;
                                        break;
                                }

                                httpParserHeader(this, line, line_end);
                                break;

                        case HTTP_MESSAGE_HEADERS_DONE:
                                if (this->current->dbody == this->current->nbody) {
                                        this->state = HTTP_MESSAGE_DONE;
                                        break;
                                }

                                if (cbufIsEmpty(this->buffer)) {
                                        cbufRelease(this->buffer);
                                        this->ourLock = FALSE;
                                        cont = 0;
                                        break;
                                }

                                cbufIncRead(
                                                this->buffer,
                                                httpParserBody(
                                                        this,
                                                        cbufGetRead(this->buffer),
                                                        this->buffer->bused));
                                break;

                        case HTTP_MESSAGE_DONE:
                                {
                                        HttpHeader enc = hashGet(
                                                        this->current->header,
                                                        CSTRA("content-type"));

                                        if (NULL != enc && 0 == strncasecmp(
                                                                "application/x-www-form-urlencoded",
                                                                enc->value[0],
                                                                MIN(sizeof("application/x-www-form-urlencoded")-1,
                                                                        enc->nvalue[0]))) {
                                                httpParserPostVars(this);
                                        }

                                this->queue->msgs[(this->queue->nmsgs)++] = this->current;
                                this->current                             = NULL;

                                this->state = HTTP_MESSAGE_GARBAGE;
                                }
                                break;

                        default:
                                break;
                }
        }

        return this->queue->nmsgs;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void httpParserPostVars ( HttpParser  this)
Todo:
this is very similar to other pair parsing things... key1=val1<delim>key2=val2<delim>...keyn=valn Generalize this!!!!

Definition at line 37 of file p_post_vars.c.

{
        HttpRequest request = (HttpRequest)this->current;
        char *      pair    = this->current->body;
        ssize_t     togo    = this->current->nbody;

        while(NULL != pair && 0 < togo) {
                char * key    = pair;
                char * eqsign = memchr(key, '=', togo);
                char * value;
                size_t nvalue;

                if (NULL == eqsign) {
                        return;
                }

                togo -= (eqsign - key);
                pair  = memchr(eqsign, '&', togo);

                if (NULL == pair) {
                        pair = &(this->current->body[this->current->nbody]);
                }

                nvalue = pair-eqsign-1;
                value  = (0 != nvalue)? eqsign+1 : NULL;

                hashAdd(request->post,
                                new(HashValue, key, eqsign-key, value, nvalue));

                pair++;
                togo -= (pair - eqsign);
        }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void httpParserRequestVars ( HttpParser  )

Definition at line 33 of file p_request_vars.c.

{
        HttpRequest request = (HttpRequest)this->current;
        char *      delim   = strchr(request->uri, '?');

        if (NULL == delim) {
                delim = request->uri + strlen(request->uri);
        }

        request->path = malloc(delim - request->uri + 1);
        request->path[delim - request->uri] = 0;
        memcpy(request->path, request->uri, delim - request->uri);

        while(NULL != delim && 0 != *delim) {
                char * key    = delim + 1;
                char * eqsign = strchr(key, '=');
                char * value;
                size_t nvalue;

                if (NULL == eqsign) {
                        return;
                }

                delim  = strchr(eqsign, '&');

                if (NULL == delim) {
                        delim = key + strlen(key);
                }

                nvalue = delim-eqsign-1;
                value  = (0 != nvalue)? eqsign+1 : NULL;

                hashAdd(request->get,
                                new(HashValue, key, eqsign-key, value, nvalue));
        }
}

Here is the call graph for this function:

Here is the caller graph for this function:

 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines