diff --git a/ChangeLog b/ChangeLog index 3880149..192e595 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,10 +1,14 @@ +2012-02-12 04:05:38 +0100 Georg Hopp + + * change response to tree based header storage and make everything work. (HEAD, master) + 2012-02-12 00:05:13 +0100 Georg Hopp - * changed header hashing to use btree (GNU only). @TODO: make this conditional for other systems. Removed the qsort calls on server->fds making O(2nlogn) to O(n) (HEAD, master) + * changed header hashing to use btree (GNU only). @TODO: make this conditional for other systems. Removed the qsort calls on server->fds making O(2nlogn) to O(n) (origin/master, origin/HEAD) 2012-02-11 13:52:32 +0100 Georg Hopp - * daemonize testserver now (origin/master, origin/HEAD) + * daemonize testserver now 2012-02-11 12:47:01 +0100 Georg Hopp diff --git a/include/http/header.h b/include/http/header.h index 4777e53..afd4e72 100644 --- a/include/http/header.h +++ b/include/http/header.h @@ -11,8 +11,8 @@ CLASS(HttpHeader) { HttpHeader httpHeaderParse(char * line); // @INFO: destructive -void httpHeaderSort(const HttpHeader [], int); -char * httpHeaderGet(const HttpHeader [], int, const char *); +void httpHeaderAdd(const HttpHeader *, HttpHeader); +char * httpHeaderGet(const HttpHeader *, const char *); size_t httpHeaderSizeGet(HttpHeader); size_t httpHeaderToString(HttpHeader, char *); diff --git a/include/http/request.h b/include/http/request.h index 66a8d2d..d8b6c6f 100644 --- a/include/http/request.h +++ b/include/http/request.h @@ -15,9 +15,6 @@ CLASS(HttpRequest) { int nbody; }; -void httpHeaderAdd(HttpHeader *, HttpHeader); -char * XhttpHeaderGet(HttpHeader *, const char *); -char * httpRequestHeaderGet(HttpRequest, const char *); char httpRequestHasKeepAlive(HttpRequest); #endif /* __HTTP_REQUEST_H__ */ diff --git a/include/http/request/parser.h b/include/http/request/parser.h index 887e421..597df4b 100644 --- a/include/http/request/parser.h +++ b/include/http/request/parser.h @@ -7,6 +7,7 @@ #define HTTP_REQUEST_PARSER_READ_CHUNK 1024 + typedef enum e_HttpRequestState { HTTP_REQUEST_GARBAGE=0, HTTP_REQUEST_START, @@ -29,6 +30,11 @@ CLASS(HttpRequestParser) { HttpRequestState state; }; +size_t httpRequestParserRead(HttpRequestParser, int); +void httpRequestParserParse(HttpRequestParser); +void httpRequestParserGetRequestLine(HttpRequest, char *); +void httpRequestParserGetHeader(HttpRequest, char *); + #endif /* __HTTP_REQUEST_PARSER_H__ */ // vim: set ts=4 sw=4: diff --git a/include/http/response.h b/include/http/response.h index 1ec9287..2df595f 100644 --- a/include/http/response.h +++ b/include/http/response.h @@ -12,8 +12,7 @@ CLASS(HttpResponse) { unsigned int status; char * reason; - HttpHeader header[128]; - int nheader; + HttpHeader header; char * body; int nbody; @@ -23,7 +22,7 @@ HttpResponse httpResponse404(); void httpResponseHeaderSet(HttpResponse, const char *, const char *); size_t httpResponseSizeGet(HttpResponse); -size_t httpResponseToString(HttpResponse, char *); +char * httpResponseToString(HttpResponse, char *); #endif /* __HTTP_RESPONSE_H__ */ diff --git a/include/interface.h b/include/interface.h index 27873e7..2ffec96 100644 --- a/include/interface.h +++ b/include/interface.h @@ -6,17 +6,11 @@ #define MAX_IFACE 32 // ATTENTION: every iface_impl will use MAX_IFACE * sizeof(void*) #define IFACE(name) ((const struct i_##name const*)&i_##name##_impl) - #define INIT_IFACE(name,...) \ static const struct i_##name i_##name##_impl = {&i_##name,__VA_ARGS__} #define NUMARGS(...) (sizeof((const void*[]){__VA_ARGS__})/sizeof(void*)) - #define INIT_IMPL(...) {NUMARGS(__VA_ARGS__), 0, {__VA_ARGS__}} -#define CREATE_IMPL(...) \ - static struct iface_impl iface_impl = INIT_IMPL(__VA_ARGS__) - -#define METHOD_GET(iface,method) (iface->method) struct interface { diff --git a/src/Makefile.am b/src/Makefile.am index 574f1f2..6049974 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,13 +7,13 @@ SOCKET = socket.c socket/accept.c socket/connect.c socket/listen.c SERVER = server.c server/run.c server/close_conn.c LOGGER = logger.c logger/stderr.c logger/syslog.c REQ = http/request.c http/request/queue.c http/request/has_keep_alive.c -RESP = http/response.c http/response/header_set.c \ - http/response/404.c http/response/size_get.c \ +RESP = http/response.c http/response/404.c http/response/size_get.c \ http/response/to_string.c -HEADER = http/header.c http/header/get.c http/header/sort.c \ +HEADER = http/header.c http/header/get.c http/header/add.c http/header/sort.c \ http/header/size_get.c http/header/to_string.c PARSER = http/request/parser.c http/request/parser/get_header.c \ - http/request/parser/parse.c http/request/parser/get_request_line.c + http/request/parser/parse.c http/request/parser/get_request_line.c \ + http/request/parser/read.c AM_CFLAGS = -Wall -I ../include/ diff --git a/src/http/header/get.c b/src/http/header/get.c index 0e145d3..59ec54c 100644 --- a/src/http/header/get.c +++ b/src/http/header/get.c @@ -1,3 +1,4 @@ +#include #include #include @@ -20,20 +21,18 @@ sdbm(const unsigned char * str) static inline int -comp (const void * _a, const void * _b) +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; + HttpHeader a = (HttpHeader)_a; + HttpHeader b = (HttpHeader)_b; + return (a->hash < b->hash)? -1 : (a->hash > b->hash)? 1 : 0; } char * -httpHeaderGet(const HttpHeader header[], int nheader, const char * name) +httpHeaderGet(const HttpHeader * root, const char * name) { - unsigned long hash = sdbm((unsigned char *)name); - HttpHeader * found; - - found = bsearch(&hash, header, nheader, sizeof(HttpHeader), comp); + struct c_HttpHeader search = {sdbm((const unsigned char*)name), NULL, NULL}; + HttpHeader * found = tfind(&search, (void**)root, comp); return (NULL != found)? (*found)->value : NULL; } diff --git a/src/http/request/has_keep_alive.c b/src/http/request/has_keep_alive.c index 034c480..3256905 100644 --- a/src/http/request/has_keep_alive.c +++ b/src/http/request/has_keep_alive.c @@ -11,7 +11,7 @@ httpRequestHasKeepAlive(HttpRequest request) char * header; char * header_ptr; - header = XhttpHeaderGet(&(request->header), "connection"); + header = httpHeaderGet(&(request->header), "connection"); if (NULL == header) { return 0; diff --git a/src/http/request/header_get.c b/src/http/request/header_get.c deleted file mode 100644 index 2cf4c6e..0000000 --- a/src/http/request/header_get.c +++ /dev/null @@ -1,12 +0,0 @@ -#include -#include - -#include "http/request.h" - -char * -httpRequestHeaderGet(HttpRequest this, const char * name) -{ - return XhttpHeaderGet(&(this->header), name); -} - -// vim: set ts=4 sw=4: diff --git a/src/http/request/parser.c b/src/http/request/parser.c index 86a088f..2883d99 100644 --- a/src/http/request/parser.c +++ b/src/http/request/parser.c @@ -56,47 +56,9 @@ _clone(void * _this, void * _base) 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]; - - ssize_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); +INIT_IFACE(StreamReader, + (fptr_streamReaderRead)httpRequestParserRead); CREATE_CLASS(HttpRequestParser, NULL, IFACE(Class), IFACE(StreamReader)); // vim: set ts=4 sw=4: diff --git a/src/http/request/parser/get_header.c b/src/http/request/parser/get_header.c index f4ee69c..1785365 100644 --- a/src/http/request/parser/get_header.c +++ b/src/http/request/parser/get_header.c @@ -7,30 +7,6 @@ #include "http/header.h" #include "http/request.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) -{ - HttpHeader a = (HttpHeader)_a; - HttpHeader b = (HttpHeader)_b; - return (a->hash < b->hash)? -1 : (a->hash > b->hash)? 1 : 0; -} - void httpRequestParserGetHeader(HttpRequest request, char * line) { @@ -43,26 +19,4 @@ httpRequestParserGetHeader(HttpRequest request, char * line) httpHeaderAdd(&(request->header), new(HttpHeader, name, value)); } -void -httpHeaderAdd(HttpHeader * root, HttpHeader header) -{ - HttpHeader * found = tsearch(header, (void **)root, comp); - - if (*found != header) { - puts("uhh, duplicate header set. " - "This is not implemented right now. " - "Keep the first one found."); - delete(&header); - } -} - -char * -XhttpHeaderGet(HttpHeader * root, const char * name) -{ - struct c_HttpHeader search = {sdbm((const unsigned char*)name), NULL, NULL}; - HttpHeader * found = tfind(&search, (void **)root, comp); - - return (NULL != found)? (*found)->value : NULL; -} - // vim: set ts=4 sw=4: diff --git a/src/http/request/parser/parse.c b/src/http/request/parser/parse.c index fefe460..450b698 100644 --- a/src/http/request/parser/parse.c +++ b/src/http/request/parser/parse.c @@ -37,9 +37,6 @@ httpRequestSkip(char ** data) for (; 0 != **data && ! isalpha(**data); (*data)++); } -void httpRequestParserGetRequestLine(HttpRequest, char *); -void httpRequestParserGetHeader(HttpRequest, char *); - void httpRequestParserParse(HttpRequestParser this) { @@ -86,7 +83,7 @@ httpRequestParserParse(HttpRequestParser this) char * nbody; if (0 == this->cur_request->nbody) { - nbody = XhttpHeaderGet( + nbody = httpHeaderGet( &(this->cur_request->header), "Content-Length"); diff --git a/src/http/response.c b/src/http/response.c index 7150a29..d103881 100644 --- a/src/http/response.c +++ b/src/http/response.c @@ -1,3 +1,8 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include #include #include @@ -36,20 +41,24 @@ ctor(void * _this, va_list * params) strcpy(this->reason, reason); } +static +inline +void +tDelete(void * node) +{ + delete(&node); +} + static void dtor(void * _this) { HttpResponse this = _this; - int i; _free((void **)&(this->version)); _free((void **)&(this->reason)); - for (i=0; i<128; i++) { - if (NULL == (this->header)[i]) break; - delete(&(this->header)[i]); - } + tdestroy(this->header, tDelete); _free((void **)&(this->body)); } diff --git a/src/http/response/404.c b/src/http/response/404.c index d930354..b629265 100644 --- a/src/http/response/404.c +++ b/src/http/response/404.c @@ -7,6 +7,7 @@ #include "interface/class.h" #include "http/response.h" +#include "http/header.h" #define RESP_DATA "\n" \ @@ -28,20 +29,24 @@ httpResponse404() response = new(HttpResponse, "HTTP/1.1", 404, "Not Found"); - httpResponseHeaderSet(response, "Content-Type", "text/html"); - httpResponseHeaderSet(response, "Server", "testserver"); + httpHeaderAdd(&(response->header), + new(HttpHeader, "Content-Type", "text/html")); + httpHeaderAdd(&(response->header), + new(HttpHeader, "Server", "testserver")); response->nbody = sizeof(RESP_DATA) - 1; response->body = calloc(1, sizeof(RESP_DATA)); strcpy(response->body, RESP_DATA); sprintf(buffer, "%d", response->nbody); - httpResponseHeaderSet(response, "Content-Length", buffer); + httpHeaderAdd(&(response->header), + new(HttpHeader, "Content-Length", buffer)); t = time(NULL); tmp = localtime(&t); strftime(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", tmp); - httpResponseHeaderSet(response, "Date", buffer); + httpHeaderAdd(&(response->header), + new(HttpHeader, "Date", buffer)); return response; } diff --git a/src/http/response/header_set.c b/src/http/response/header_set.c deleted file mode 100644 index 00b259e..0000000 --- a/src/http/response/header_set.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "class.h" -#include "interface/class.h" - -#include "http/response.h" -#include "http/header.h" - -void -httpResponseHeaderSet(HttpResponse this, const char * name, const char * value) -{ - (this->header)[this->nheader++] = new(HttpHeader, name, value); -} - -// vim: set ts=4 sw=4: diff --git a/src/http/response/size_get.c b/src/http/response/size_get.c index c33b0d0..f29652f 100644 --- a/src/http/response/size_get.c +++ b/src/http/response/size_get.c @@ -1,22 +1,32 @@ +#include #include #include #include "http/response.h" #include "http/header.h" +static size_t size; + +static +inline +void +addHeaderSize(const void * node, const VISIT which, const int depth) +{ + if (endorder == which || leaf == which) { + size += httpHeaderSizeGet(*(HttpHeader *)node) + 2; + } +} + size_t httpResponseSizeGet(HttpResponse response) { - int i; - size_t size = 0; + size = 0; size += strlen(response->version) + 1; size += 4; // for status size += strlen(response->reason) + 2; - for (i=0; inheader; i++) { - size += httpHeaderSizeGet(response->header[i]) + 2; - } + twalk(response->header, addHeaderSize); size += 2; size += response->nbody; diff --git a/src/http/response/to_string.c b/src/http/response/to_string.c index 17f05b6..0a50712 100644 --- a/src/http/response/to_string.c +++ b/src/http/response/to_string.c @@ -1,16 +1,29 @@ +#include #include #include #include "http/response.h" #include "http/header.h" -size_t -httpResponseToString(HttpResponse response, char * string) +static char * string; + +void +addHeaderString(const void * node, const VISIT which, const int depth) +{ + if (endorder == which || leaf == which) { + string += httpHeaderToString(*(HttpHeader *)node, string); + *string++ = '\r'; + *string++ = '\n'; + } +} + +char * +httpResponseToString(HttpResponse response, char * _string) { - int i; - size_t size = httpResponseSizeGet(response); char status[4]; + string = _string; + snprintf(status, 4, "%d", response->status); strcpy(string, response->version); @@ -29,18 +42,14 @@ httpResponseToString(HttpResponse response, char * string) *string++ = '\r'; *string++ = '\n'; - for (i=0; inheader; i++) { - string += httpHeaderToString(response->header[i], string); - *string++ = '\r'; - *string++ = '\n'; - } + twalk(response->header, addHeaderString); *string++ = '\r'; *string++ = '\n'; memcpy(string, response->body, response->nbody); - return size; + return string; } // vim: set ts=4 sw=4: diff --git a/src/server/run.c b/src/server/run.c index 47e79b2..765741b 100644 --- a/src/server/run.c +++ b/src/server/run.c @@ -116,17 +116,15 @@ serverRun(Server this) if (httpRequestHasKeepAlive(queue->requests[j])) { (this->conns)[fd].keep_alive = 1; - httpResponseHeaderSet( - response, - "Connection", - "Keep-Alive"); + httpHeaderAdd( + &(response->header), + new(HttpHeader, "Connection", "Keep-Alive")); } else { (this->conns)[fd].keep_alive = 0; - httpResponseHeaderSet( - response, - "Connection", - "Close"); + httpHeaderAdd( + &(response->header), + new(HttpHeader, "Connection", "Close")); } delete(&(queue->requests[j]));