15 changed files with 487 additions and 339 deletions
-
6ChangeLog
-
18include/http/header.h
-
11include/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