15 changed files with 487 additions and 339 deletions
-
6ChangeLog
-
18include/http/header.h
-
19include/http/request.h
-
23include/http/response.h
-
5src/Makefile.am
-
69src/http/header.c
-
41src/http/header/get.c
-
19src/http/header/sort.c
-
6src/http/request.c
-
100src/http/request/parser.c
-
18src/http/request/parser/get_header.c
-
29src/http/request/parser/get_request_line.c
-
150src/http/request/parser/parse.c
-
0src/http/request/queue.c
-
323src/http/request_parser.c
@ -0,0 +1,18 @@ |
|||||
|
#ifndef __HTTP_HEADER_H__ |
||||
|
#define __HTTP_HEADER_H__ |
||||
|
|
||||
|
#include "class.h" |
||||
|
|
||||
|
CLASS(HttpHeader) { |
||||
|
unsigned long hash; |
||||
|
char * name; |
||||
|
char * value; |
||||
|
}; |
||||
|
|
||||
|
HttpHeader httpHeaderParse(char * line); // @INFO: destructive |
||||
|
void httpHeaderSort(const HttpHeader [], int); |
||||
|
char * httpHeaderGet(const HttpHeader [], int, const char *); |
||||
|
|
||||
|
#endif // __HTTP_HEADER_H__ |
||||
|
|
||||
|
// vim: set ts=4 sw=4: |
||||
@ -0,0 +1,23 @@ |
|||||
|
#ifndef __HTTP_RESPONSE_H__ |
||||
|
#define __HTTP_RESPONSE_H__ |
||||
|
|
||||
|
#include "class.h" |
||||
|
|
||||
|
CLASS(HttpResponse) { |
||||
|
char * http_version; |
||||
|
char * status; |
||||
|
char * reson; |
||||
|
|
||||
|
HttpHeader header[128]; |
||||
|
int nheader; |
||||
|
|
||||
|
char * body; |
||||
|
int nbody; |
||||
|
}; |
||||
|
|
||||
|
char * |
||||
|
httpRequestHeaderGet(HttpRequest this, const char * name); |
||||
|
|
||||
|
#endif /* __HTTP_RESPONSE_H__ */ |
||||
|
|
||||
|
// vim: set ts=4 sw=4: |
||||
@ -0,0 +1,69 @@ |
|||||
|
#include <stdlib.h> |
||||
|
#include <string.h> |
||||
|
#include <ctype.h> |
||||
|
|
||||
|
#include "class.h" |
||||
|
#include "interface/class.h" |
||||
|
|
||||
|
#include "http/header.h" |
||||
|
|
||||
|
/** |
||||
|
* SDBM hashing algorithm: |
||||
|
* |
||||
|
* this algorithm was created for sdbm (a public-domain reimplementation of |
||||
|
* ndbm) database library. it was found to do well in scrambling bits, |
||||
|
* causing better distribution of the keys and fewer splits. it also happens |
||||
|
* to be a good general hashing function with good distribution. the actual |
||||
|
* function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below |
||||
|
* is the faster version used in gawk. [there is even a faster, duff-device |
||||
|
* version] the magic constant 65599 was picked out of thin air while |
||||
|
* experimenting with different constants, and turns out to be a prime. this |
||||
|
* is one of the algorithms used in berkeley db (see sleepycat) and elsewhere. |
||||
|
*/ |
||||
|
static |
||||
|
inline |
||||
|
unsigned long |
||||
|
sdbm(unsigned char * str) |
||||
|
{ |
||||
|
unsigned long hash = 0; |
||||
|
int c; |
||||
|
|
||||
|
while ((c = tolower(*str++))) |
||||
|
hash = c + (hash << 6) + (hash << 16) - hash; |
||||
|
|
||||
|
return hash; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
void |
||||
|
ctor(void * _this, va_list * params) { |
||||
|
HttpHeader this = _this; |
||||
|
char * name; |
||||
|
char * value; |
||||
|
|
||||
|
name = va_arg(* params, char *); |
||||
|
value = va_arg(* params, char *); |
||||
|
|
||||
|
this->name = malloc(strlen(name) + 1); |
||||
|
strcpy(this->name, name); |
||||
|
|
||||
|
this->hash = sdbm((unsigned char *)name); |
||||
|
|
||||
|
this->value = malloc(strlen(value) + 1); |
||||
|
strcpy(this->value, value); |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
void |
||||
|
dtor(void * _this) |
||||
|
{ |
||||
|
HttpHeader this = _this; |
||||
|
|
||||
|
free(this->name); |
||||
|
free(this->value); |
||||
|
} |
||||
|
|
||||
|
INIT_IFACE(Class, ctor, dtor, NULL); |
||||
|
CREATE_CLASS(HttpHeader, NULL, IFACE(Class)); |
||||
|
|
||||
|
// vim: set ts=4 sw=4: |
||||
@ -0,0 +1,41 @@ |
|||||
|
#include <stdlib.h> |
||||
|
#include <ctype.h> |
||||
|
|
||||
|
#include "http/header.h" |
||||
|
|
||||
|
static |
||||
|
inline |
||||
|
unsigned long |
||||
|
sdbm(const unsigned char * str) |
||||
|
{ |
||||
|
unsigned long hash = 0; |
||||
|
int c; |
||||
|
|
||||
|
while ((c = tolower(*str++))) |
||||
|
hash = c + (hash << 6) + (hash << 16) - hash; |
||||
|
|
||||
|
return hash; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
inline |
||||
|
int |
||||
|
comp (const void * _a, const void * _b) |
||||
|
{ |
||||
|
unsigned long a = *(unsigned long *)_a; |
||||
|
const HttpHeader b = *(const HttpHeader *)_b; |
||||
|
return (a < b->hash)? -1 : (a > b->hash)? 1 : 0; |
||||
|
} |
||||
|
|
||||
|
char * |
||||
|
httpHeaderGet(const HttpHeader header[], int nheader, const char * name) |
||||
|
{ |
||||
|
unsigned long hash = sdbm((unsigned char *)name); |
||||
|
HttpHeader found; |
||||
|
|
||||
|
found = bsearch(&hash, header, nheader, sizeof(HttpHeader), comp); |
||||
|
|
||||
|
return (NULL != found)? found->value : NULL; |
||||
|
} |
||||
|
|
||||
|
// vim: set ts=4 sw=4: |
||||
@ -0,0 +1,19 @@ |
|||||
|
#include "http/header.h" |
||||
|
|
||||
|
static |
||||
|
inline |
||||
|
int |
||||
|
comp (const void * _a, const void * _b) |
||||
|
{ |
||||
|
const HttpHeader a = *(const HttpHeader *)_a; |
||||
|
const HttpHeader b = *(const HttpHeader *)_b; |
||||
|
return (a->hash < b->hash)? -1 : (a->hash > b->hash)? 1 : 0; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
httpHeaderSort(const HttpHeader header[], int nheader) |
||||
|
{ |
||||
|
qsort(header, nheader, sizeof(HttpHeader), comp); |
||||
|
} |
||||
|
|
||||
|
// vim: set ts=4 sw=4: |
||||
@ -0,0 +1,100 @@ |
|||||
|
#include <string.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <sys/types.h> |
||||
|
|
||||
|
#include "class.h" |
||||
|
#include "http/request_parser.h" |
||||
|
#include "interface/class.h" |
||||
|
#include "interface/stream_reader.h" |
||||
|
#include "http/request.h" |
||||
|
#include "http/request_queue.h" |
||||
|
|
||||
|
void httpRequestParserParse(HttpRequestParser); |
||||
|
|
||||
|
static |
||||
|
void |
||||
|
ctor(void * _this, va_list * params) |
||||
|
{ |
||||
|
HttpRequestParser this = _this; |
||||
|
|
||||
|
this->request_queue = new(HttpRequestQueue); |
||||
|
|
||||
|
this->buffer = malloc(HTTP_REQUEST_PARSER_READ_CHUNK); |
||||
|
this->buffer[0] = 0; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
void |
||||
|
dtor(void * _this) |
||||
|
{ |
||||
|
HttpRequestParser this = _this; |
||||
|
|
||||
|
free(this->buffer); |
||||
|
delete(&(this->request_queue)); |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
void |
||||
|
_clone(void * _this, void * _base) |
||||
|
{ |
||||
|
HttpRequestParser this = _this; |
||||
|
HttpRequestParser base = _base; |
||||
|
size_t chunks; |
||||
|
|
||||
|
/** |
||||
|
* every parser has its own queue... |
||||
|
*/ |
||||
|
this->request_queue = new(HttpRequestQueue); |
||||
|
this->buffer_used = base->buffer_used; |
||||
|
|
||||
|
chunks = this->buffer_used / HTTP_REQUEST_PARSER_READ_CHUNK; |
||||
|
chunks++; |
||||
|
|
||||
|
this->buffer = malloc(chunks * HTTP_REQUEST_PARSER_READ_CHUNK); |
||||
|
memcpy(this->buffer, base->buffer, this->buffer_used); |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
size_t |
||||
|
get_data(void * _this, int fd) |
||||
|
{ |
||||
|
HttpRequestParser this = _this; |
||||
|
size_t remaining, chunks; |
||||
|
char buffer[1024]; |
||||
|
|
||||
|
size_t size = read(fd, buffer, 1024); |
||||
|
|
||||
|
if (0 < size) { |
||||
|
remaining = this->buffer_used % HTTP_REQUEST_PARSER_READ_CHUNK; |
||||
|
chunks = this->buffer_used / HTTP_REQUEST_PARSER_READ_CHUNK; |
||||
|
|
||||
|
/** |
||||
|
* because a division always rounds down |
||||
|
* chunks holds exactly the currently allocated chunks if |
||||
|
* remaining equals 0 but there is no space left. |
||||
|
* Else chunks holds the actually allocated amount of chunks |
||||
|
* minus 1. |
||||
|
* For this reason chunks always has to be increased by 1. |
||||
|
*/ |
||||
|
chunks++; |
||||
|
|
||||
|
if (size >= remaining) { |
||||
|
this->buffer = |
||||
|
realloc(this->buffer, chunks * HTTP_REQUEST_PARSER_READ_CHUNK); |
||||
|
} |
||||
|
|
||||
|
memcpy(this->buffer + this->buffer_used, buffer, size); |
||||
|
this->buffer_used += size; |
||||
|
this->buffer[this->buffer_used] = 0; |
||||
|
|
||||
|
httpRequestParserParse(this); |
||||
|
} |
||||
|
|
||||
|
return size; |
||||
|
} |
||||
|
|
||||
|
INIT_IFACE(Class, ctor, dtor, _clone); |
||||
|
INIT_IFACE(StreamReader, get_data); |
||||
|
CREATE_CLASS(HttpRequestParser, NULL, IFACE(Class), IFACE(StreamReader)); |
||||
|
|
||||
|
// vim: set ts=4 sw=4: |
||||
@ -0,0 +1,18 @@ |
|||||
|
#include "class.h" |
||||
|
#include "interface/class.h" |
||||
|
#include "http/header.h" |
||||
|
#include "http/request.h" |
||||
|
|
||||
|
void |
||||
|
httpRequestParserGetHeader(HttpRequest request, char * line) |
||||
|
{ |
||||
|
char * name = line; |
||||
|
char * value = strchr(line, ':'); |
||||
|
|
||||
|
*value = 0; |
||||
|
for (; *value == ' ' && *value != 0; value++); |
||||
|
|
||||
|
(request->header)[request->nheader++] = new(HttpHeader, name, value); |
||||
|
} |
||||
|
|
||||
|
// vim: set ts=4 sw=4: |
||||
@ -0,0 +1,29 @@ |
|||||
|
#include <string.h> |
||||
|
|
||||
|
#include "http/request.h" |
||||
|
|
||||
|
|
||||
|
void |
||||
|
httpRequestParserGetRequestLine(HttpRequest request, char * line) |
||||
|
{ |
||||
|
char * method, * uri, * version; |
||||
|
|
||||
|
method = line; |
||||
|
|
||||
|
uri = strchr(line, ' '); |
||||
|
*uri++ = 0; |
||||
|
for (; *uri == ' ' && *uri != 0; uri++); |
||||
|
|
||||
|
version = strchr(uri, ' '); |
||||
|
*version++ = 0; |
||||
|
for (; *version == ' ' && *version != 0; version++); |
||||
|
|
||||
|
request->method = malloc(strlen(method) + 1); |
||||
|
strcpy(request->method, method); |
||||
|
request->uri = malloc(strlen(uri) + 1); |
||||
|
strcpy(request->uri, uri); |
||||
|
request->version = malloc(strlen(version) + 1); |
||||
|
strcpy(request->version, method); |
||||
|
} |
||||
|
|
||||
|
// vim: set ts=4 sw=4: |
||||
@ -0,0 +1,150 @@ |
|||||
|
#include <stdlib.h> |
||||
|
#include <string.h> |
||||
|
#include <unistd.h> |
||||
|
#include <ctype.h> |
||||
|
|
||||
|
#include "http/request_parser.h" |
||||
|
#include "interface/class.h" |
||||
|
|
||||
|
|
||||
|
#define REMAINS(pars,done) \ |
||||
|
((pars)->buffer_used - ((done) - (pars)->buffer)) |
||||
|
|
||||
|
|
||||
|
static |
||||
|
inline |
||||
|
char * |
||||
|
httpRequestParserGetLine(char ** data) |
||||
|
{ |
||||
|
char * line_end = strstr(*data, "\r\n"); |
||||
|
char * ret = *data; |
||||
|
|
||||
|
if (NULL == line_end) { |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
*line_end = 0; |
||||
|
*data = line_end + 2; |
||||
|
|
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
inline |
||||
|
void |
||||
|
httpRequestSkip(char ** data) |
||||
|
{ |
||||
|
for (; 0 != **data && ! isalpha(**data); (*data)++); |
||||
|
} |
||||
|
|
||||
|
void httpRequestParserGetRequestLine(HttpRequest, char *); |
||||
|
|
||||
|
void |
||||
|
httpRequestParserParse(HttpRequestParser this) |
||||
|
{ |
||||
|
static HttpRequest request = NULL; |
||||
|
static char * data; // static pointer to unprocessed data |
||||
|
char * line; |
||||
|
int cont = 1; |
||||
|
|
||||
|
while(cont) { |
||||
|
switch(this->state) { |
||||
|
case HTTP_REQUEST_GARBAGE: |
||||
|
data = this->buffer; // initialize static pointer |
||||
|
httpRequestSkip(&data); |
||||
|
request = new(HttpRequest); |
||||
|
|
||||
|
this->state = HTTP_REQUEST_START; |
||||
|
break; |
||||
|
|
||||
|
case HTTP_REQUEST_START: |
||||
|
if (NULL == (line = httpRequestParserGetLine(&data))) { |
||||
|
cont = 0; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
httpRequestParserGetRequestLine(request, line); |
||||
|
|
||||
|
this->state = HTTP_REQUEST_REQUEST_LINE_DONE; |
||||
|
break; |
||||
|
|
||||
|
case HTTP_REQUEST_REQUEST_LINE_DONE: |
||||
|
if (NULL == (line = httpRequestParserGetLine(&data))) { |
||||
|
cont = 0; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if (0 == strlen(line)) { |
||||
|
this->state = HTTP_REQUEST_HEADERS_DONE; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
httpRequestParserGetHeader(request, line); |
||||
|
break; |
||||
|
|
||||
|
case HTTP_REQUEST_HEADERS_DONE: |
||||
|
httpHeaderSort(request->header, request->nheader); |
||||
|
|
||||
|
{ |
||||
|
char * nbody; |
||||
|
|
||||
|
if (0 == request->nbody) { |
||||
|
nbody = httpHeaderGet( |
||||
|
request->header, |
||||
|
request->nheader, |
||||
|
"Content-Length"); |
||||
|
|
||||
|
if (NULL == nbody) { |
||||
|
this->state = HTTP_REQUEST_DONE; |
||||
|
break; |
||||
|
} |
||||
|
else { |
||||
|
request->nbody = atoi(nbody); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (REMAINS(this, data) >= request->nbody) { |
||||
|
request->body = calloc(1, request->nbody + 1); |
||||
|
memcpy(request->body, data, request->nbody); |
||||
|
data += request->nbody; |
||||
|
this->state = HTTP_REQUEST_DONE; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
break; |
||||
|
|
||||
|
case HTTP_REQUEST_DONE: |
||||
|
/** |
||||
|
* enqueue current request |
||||
|
*/ |
||||
|
this->request_queue->requests[(this->request_queue->nrequests)++] = |
||||
|
request; |
||||
|
|
||||
|
/** |
||||
|
* remove processed stuff from input buffer. |
||||
|
*/ |
||||
|
memmove(this->buffer, data, REMAINS(this, data)); |
||||
|
|
||||
|
this->buffer_used -= data - this->buffer; |
||||
|
|
||||
|
/** |
||||
|
* dont continue loop if input buffer is empty |
||||
|
*/ |
||||
|
if (0 == this->buffer_used) { |
||||
|
cont = 0; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* prepare for next request |
||||
|
*/ |
||||
|
this->state = HTTP_REQUEST_GARBAGE; |
||||
|
|
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// vim: set ts=4 sw=4: |
||||
@ -1,323 +0,0 @@ |
|||||
#include <stdlib.h> |
|
||||
#include <string.h> |
|
||||
#include <stdlib.h> |
|
||||
#include <stdio.h> |
|
||||
#include <unistd.h> |
|
||||
#include <ctype.h> |
|
||||
#include <sys/types.h> |
|
||||
|
|
||||
#include "class.h" |
|
||||
#include "http/request_parser.h" |
|
||||
#include "interface/class.h" |
|
||||
#include "interface/stream_reader.h" |
|
||||
#include "http/request.h" |
|
||||
#include "http/request_queue.h" |
|
||||
|
|
||||
static |
|
||||
void |
|
||||
httpRequestParserParse(HttpRequestParser); |
|
||||
|
|
||||
static |
|
||||
void |
|
||||
ctor(void * _this, va_list * params) |
|
||||
{ |
|
||||
HttpRequestParser this = _this; |
|
||||
|
|
||||
this->request_queue = new(HttpRequestQueue); |
|
||||
|
|
||||
this->buffer = malloc(HTTP_REQUEST_PARSER_READ_CHUNK); |
|
||||
this->buffer[0] = 0; |
|
||||
} |
|
||||
|
|
||||
static |
|
||||
void |
|
||||
dtor(void * _this) |
|
||||
{ |
|
||||
HttpRequestParser this = _this; |
|
||||
|
|
||||
free(this->buffer); |
|
||||
delete(&(this->request_queue)); |
|
||||
} |
|
||||
|
|
||||
static |
|
||||
void |
|
||||
_clone(void * _this, void * _base) |
|
||||
{ |
|
||||
HttpRequestParser this = _this; |
|
||||
HttpRequestParser base = _base; |
|
||||
size_t chunks; |
|
||||
|
|
||||
/** |
|
||||
* every parser has its own queue... |
|
||||
*/ |
|
||||
this->request_queue = new(HttpRequestQueue); |
|
||||
this->buffer_used = base->buffer_used; |
|
||||
|
|
||||
chunks = this->buffer_used / HTTP_REQUEST_PARSER_READ_CHUNK; |
|
||||
chunks++; |
|
||||
|
|
||||
this->buffer = malloc(chunks * HTTP_REQUEST_PARSER_READ_CHUNK); |
|
||||
memcpy(this->buffer, base->buffer, this->buffer_used); |
|
||||
} |
|
||||
|
|
||||
static |
|
||||
size_t |
|
||||
get_data(void * _this, int fd) |
|
||||
{ |
|
||||
HttpRequestParser this = _this; |
|
||||
size_t remaining, chunks; |
|
||||
char buffer[1024]; |
|
||||
|
|
||||
size_t size = read(fd, buffer, 1024); |
|
||||
|
|
||||
if (0 < size) { |
|
||||
remaining = this->buffer_used % HTTP_REQUEST_PARSER_READ_CHUNK; |
|
||||
chunks = this->buffer_used / HTTP_REQUEST_PARSER_READ_CHUNK; |
|
||||
|
|
||||
/** |
|
||||
* because a division always rounds down |
|
||||
* chunks holds exactly the currently allocated chunks if |
|
||||
* remaining equals 0 but there is no space left. |
|
||||
* Else chunks holds the actually allocated amount of chunks |
|
||||
* minus 1. |
|
||||
* For this reason chunks always has to be increased by 1. |
|
||||
*/ |
|
||||
chunks++; |
|
||||
|
|
||||
if (size >= remaining) { |
|
||||
this->buffer = |
|
||||
realloc(this->buffer, chunks * HTTP_REQUEST_PARSER_READ_CHUNK); |
|
||||
} |
|
||||
|
|
||||
memcpy(this->buffer + this->buffer_used, buffer, size); |
|
||||
this->buffer_used += size; |
|
||||
this->buffer[this->buffer_used] = 0; |
|
||||
|
|
||||
httpRequestParserParse(this); |
|
||||
} |
|
||||
|
|
||||
return size; |
|
||||
} |
|
||||
|
|
||||
INIT_IFACE(Class, ctor, dtor, _clone); |
|
||||
INIT_IFACE(StreamReader, get_data); |
|
||||
CREATE_CLASS(HttpRequestParser, NULL, IFACE(Class), IFACE(StreamReader)); |
|
||||
|
|
||||
static |
|
||||
inline |
|
||||
char * |
|
||||
httpRequestLineGet(char ** data) |
|
||||
{ |
|
||||
char * line_end = strstr(*data, "\r\n"); |
|
||||
char * ret = *data; |
|
||||
|
|
||||
if (NULL == line_end) { |
|
||||
return NULL; |
|
||||
} |
|
||||
|
|
||||
*line_end = 0; |
|
||||
*data = line_end + 2; |
|
||||
|
|
||||
return ret; |
|
||||
} |
|
||||
|
|
||||
static |
|
||||
inline |
|
||||
void |
|
||||
httpRequestSkip(char ** data) |
|
||||
{ |
|
||||
for (; 0 != **data && ! isalpha(**data); (*data)++); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* SDBM hashing algorithm: |
|
||||
* |
|
||||
* this algorithm was created for sdbm (a public-domain reimplementation of |
|
||||
* ndbm) database library. it was found to do well in scrambling bits, |
|
||||
* causing better distribution of the keys and fewer splits. it also happens |
|
||||
* to be a good general hashing function with good distribution. the actual |
|
||||
* function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below |
|
||||
* is the faster version used in gawk. [there is even a faster, duff-device |
|
||||
* version] the magic constant 65599 was picked out of thin air while |
|
||||
* experimenting with different constants, and turns out to be a prime. this |
|
||||
* is one of the algorithms used in berkeley db (see sleepycat) and elsewhere. |
|
||||
*/ |
|
||||
static |
|
||||
inline |
|
||||
unsigned long |
|
||||
sdbm(unsigned char * str) |
|
||||
{ |
|
||||
unsigned long hash = 0; |
|
||||
int c; |
|
||||
|
|
||||
while ((c = tolower(*str++))) |
|
||||
hash = c + (hash << 6) + (hash << 16) - hash; |
|
||||
|
|
||||
return hash; |
|
||||
} |
|
||||
|
|
||||
static |
|
||||
inline |
|
||||
int |
|
||||
comp (const void * _a, const void * _b) |
|
||||
{ |
|
||||
const struct HttpRequestHeader * a = _a; |
|
||||
const struct HttpRequestHeader * b = _b; |
|
||||
return (a->hash < b->hash)? -1 : (a->hash > b->hash)? 1 : 0; |
|
||||
} |
|
||||
|
|
||||
static |
|
||||
void |
|
||||
httpRequestParserParse(HttpRequestParser this) |
|
||||
{ |
|
||||
static HttpRequest request = NULL; |
|
||||
static char * data; // static pointer to unprocessed data |
|
||||
char * line; |
|
||||
int cont = 1; |
|
||||
static int header_idx; |
|
||||
|
|
||||
while(cont) { |
|
||||
switch(this->state) { |
|
||||
case HTTP_REQUEST_GARBAGE: |
|
||||
data = this->buffer; // initialize static pointer |
|
||||
httpRequestSkip(&data); |
|
||||
request = new(HttpRequest); |
|
||||
|
|
||||
this->state = HTTP_REQUEST_START; |
|
||||
break; |
|
||||
|
|
||||
case HTTP_REQUEST_START: |
|
||||
if (NULL == (line = httpRequestLineGet(&data))) { |
|
||||
cont = 0; |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
{ |
|
||||
char * delim = strchr(line, ' '); |
|
||||
|
|
||||
if (NULL != delim) { |
|
||||
*delim = 0; |
|
||||
request->method = malloc(strlen(line) + 1); |
|
||||
strcpy(request->method, line); |
|
||||
line = delim + 1; |
|
||||
|
|
||||
for (; *line == ' ' && *line != 0; line++); |
|
||||
|
|
||||
if (0 != *line) { |
|
||||
delim = strchr(line, ' '); |
|
||||
|
|
||||
if (NULL != delim) { |
|
||||
*delim = 0; |
|
||||
request->uri = malloc(strlen(line) + 1); |
|
||||
strcpy(request->uri, line); |
|
||||
line = delim + 1; |
|
||||
|
|
||||
for (; *line == ' ' && *line != 0; line++); |
|
||||
|
|
||||
if (0 != *line) { |
|
||||
request->http_version = malloc(strlen(line) + 1); |
|
||||
strcpy(request->http_version, line); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
header_idx = 0; |
|
||||
this->state = HTTP_REQUEST_REQUEST_LINE_DONE; |
|
||||
break; |
|
||||
|
|
||||
case HTTP_REQUEST_REQUEST_LINE_DONE: |
|
||||
if (NULL == (line = httpRequestLineGet(&data))) { |
|
||||
cont = 0; |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
if (0 == strlen(line)) { |
|
||||
this->state = HTTP_REQUEST_HEADERS_DONE; |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
{ |
|
||||
char * delim = strchr(line, ':'); |
|
||||
|
|
||||
*delim = 0; |
|
||||
(request->header)[header_idx].name = malloc(strlen(line) + 1); |
|
||||
strcpy((request->header)[header_idx].name, line); |
|
||||
(request->header)[header_idx].hash = sdbm((unsigned char *)line); |
|
||||
|
|
||||
line = delim + 1; |
|
||||
for (; *line == ' ' && *line != 0; line++); |
|
||||
|
|
||||
(request->header)[header_idx].value = malloc(strlen(line) + 1); |
|
||||
strcpy((request->header)[header_idx].value, line); |
|
||||
|
|
||||
header_idx++; |
|
||||
request->nheader++; |
|
||||
} |
|
||||
|
|
||||
break; |
|
||||
|
|
||||
case HTTP_REQUEST_HEADERS_DONE: |
|
||||
/** |
|
||||
* @TODO: here comes the body handling |
|
||||
*/ |
|
||||
qsort( |
|
||||
request->header, |
|
||||
request->nheader, |
|
||||
sizeof(struct HttpRequestHeader), |
|
||||
comp); |
|
||||
|
|
||||
{ |
|
||||
char * bodylen; |
|
||||
|
|
||||
bodylen = httpRequestHeaderGet(request, "Content-Length"); |
|
||||
|
|
||||
if (NULL != bodylen) { |
|
||||
request->nbody = atoi(bodylen); |
|
||||
request->body = calloc(1, request->nbody + 1); |
|
||||
memcpy(request->body, data, request->nbody); |
|
||||
data += request->nbody; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
this->state = HTTP_REQUEST_DONE; |
|
||||
break; |
|
||||
|
|
||||
case HTTP_REQUEST_DONE: |
|
||||
/** |
|
||||
* enqueue current request |
|
||||
*/ |
|
||||
this->request_queue->requests[(this->request_queue->nrequests)++] = |
|
||||
request; |
|
||||
|
|
||||
/** |
|
||||
* remove processed stuff from input buffer. |
|
||||
*/ |
|
||||
memmove(this->buffer, |
|
||||
data, |
|
||||
this->buffer_used - (data - this->buffer) + 1); |
|
||||
|
|
||||
this->buffer_used -= data - this->buffer; |
|
||||
|
|
||||
/** |
|
||||
* dont continue loop if input buffer is empty |
|
||||
*/ |
|
||||
if (0 == this->buffer_used) { |
|
||||
cont = 0; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* prepare for next request |
|
||||
*/ |
|
||||
this->state = HTTP_REQUEST_GARBAGE; |
|
||||
|
|
||||
break; |
|
||||
|
|
||||
default: |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// vim: set ts=4 sw=4: |
|
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue