diff --git a/ChangeLog b/ChangeLog index 96cad48..2bfe4ae 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,10 @@ +2012-02-10 19:57:57 +0100 Georg Hopp + + * started a response handler and changed serverRun to use it for its response (HEAD, master) + 2012-02-10 12:42:04 +0100 Georg Hopp - * fixed bug at server destructor (HEAD, master) + * fixed bug at server destructor (origin/master, origin/HEAD) 2012-02-10 09:59:41 +0100 Georg Hopp @@ -12,7 +16,7 @@ 2012-02-10 08:14:31 +0100 Georg Hopp - * now only use keep-alive.... (origin/master, origin/HEAD) + * now only use keep-alive.... 2012-02-10 06:36:43 +0100 Georg Hopp diff --git a/TODO b/TODO new file mode 100644 index 0000000..36521bd --- /dev/null +++ b/TODO @@ -0,0 +1,2 @@ +VERY BIG TODO: +- give a contructor a way to fail, so that no object will be created at all diff --git a/include/http/header.h b/include/http/header.h index 0b9696c..4777e53 100644 --- a/include/http/header.h +++ b/include/http/header.h @@ -10,8 +10,11 @@ CLASS(HttpHeader) { }; HttpHeader httpHeaderParse(char * line); // @INFO: destructive -void httpHeaderSort(const HttpHeader [], int); -char * httpHeaderGet(const HttpHeader [], int, const char *); + +void httpHeaderSort(const HttpHeader [], int); +char * httpHeaderGet(const HttpHeader [], int, const char *); +size_t httpHeaderSizeGet(HttpHeader); +size_t httpHeaderToString(HttpHeader, char *); #endif // __HTTP_HEADER_H__ diff --git a/include/http/request.h b/include/http/request.h index 09d864e..4ae6a5d 100644 --- a/include/http/request.h +++ b/include/http/request.h @@ -16,8 +16,8 @@ CLASS(HttpRequest) { int nbody; }; -char * -httpRequestHeaderGet(HttpRequest this, const char * name); +char * httpRequestHeaderGet(HttpRequest, const char *); +char httpRequestHasKeepAlive(HttpRequest); #endif /* __HTTP_REQUEST_H__ */ diff --git a/include/http/response.h b/include/http/response.h index f708d37..1ec9287 100644 --- a/include/http/response.h +++ b/include/http/response.h @@ -1,22 +1,29 @@ #ifndef __HTTP_RESPONSE_H__ #define __HTTP_RESPONSE_H__ +#include + #include "class.h" +#include "http/header.h" + CLASS(HttpResponse) { - char * http_version; - char * status; - char * reson; + char * version; + unsigned int status; + char * reason; - HttpHeader header[128]; - int nheader; + HttpHeader header[128]; + int nheader; - char * body; - int nbody; + char * body; + int nbody; }; -char * -httpRequestHeaderGet(HttpRequest this, const char * name); +HttpResponse httpResponse404(); + +void httpResponseHeaderSet(HttpResponse, const char *, const char *); +size_t httpResponseSizeGet(HttpResponse); +size_t httpResponseToString(HttpResponse, char *); #endif /* __HTTP_RESPONSE_H__ */ diff --git a/include/server.h b/include/server.h index 7df30a6..e732518 100644 --- a/include/server.h +++ b/include/server.h @@ -43,7 +43,7 @@ CLASS(Server) { char keep_alive; - char wbuf[2048]; + char * wbuf; char * rbuf; unsigned int rpos; unsigned int wpos; diff --git a/src/Makefile.am b/src/Makefile.am index b2f7eee..574f1f2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,20 +1,26 @@ ACLOCAL_AMFLAGS = -I m4 AUTOMAKE_OPTIONS = subdir-objects -CLASS = class.c interface.c interface/class.c +IFACE = interface/class.c interface/stream_reader.c interface/logger.c +CLASS = class.c interface.c 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 interface/logger.c -HTTP = interface/stream_reader.c http/request/parser.c http/request.c \ - http/request/queue.c http/header.c http/header/get.c \ - http/header/sort.c http/request/parser/get_header.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 \ + http/response/to_string.c +HEADER = http/header.c http/header/get.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 + AM_CFLAGS = -Wall -I ../include/ bin_PROGRAMS = testserver testserver_SOURCES = testserver.c \ - $(CLASS) $(SOCKET) $(SERVER) $(LOGGER) $(HTTP) \ - signalHandling.c daemonize.c + $(IFACE) $(CLASS) $(SOCKET) $(SERVER) $(LOGGER) $(REQ) \ + $(RESP) $(HEADER) $(PARSER) signalHandling.c daemonize.c testserver_CFLAGS = -Wall -I ../include/ diff --git a/src/http/header/size_get.c b/src/http/header/size_get.c new file mode 100644 index 0000000..8ff8453 --- /dev/null +++ b/src/http/header/size_get.c @@ -0,0 +1,16 @@ +#include + +#include "http/header.h" + +size_t +httpHeaderSizeGet(HttpHeader header) +{ + size_t size = 0; + + size += strlen(header->name) + 2; + size += strlen(header->value); + + return size; +} + +// vim: set ts=4 sw=4: diff --git a/src/http/header/to_string.c b/src/http/header/to_string.c new file mode 100644 index 0000000..e58c5e1 --- /dev/null +++ b/src/http/header/to_string.c @@ -0,0 +1,21 @@ +#include + +#include "http/header.h" + +size_t +httpHeaderToString(HttpHeader header, char * string) +{ + size_t size = httpHeaderSizeGet(header); + + strcpy(string, header->name); + string += strlen(string); + + *string++ = ':'; + *string++ = ' '; + + strcpy(string, header->value); + + return size; +} + +// vim: set ts=4 sw=4: diff --git a/src/http/request/has_keep_alive.c b/src/http/request/has_keep_alive.c new file mode 100644 index 0000000..332fe61 --- /dev/null +++ b/src/http/request/has_keep_alive.c @@ -0,0 +1,31 @@ +#include +#include + +#include "http/request.h" +#include "http/header.h" + + +char +httpRequestHasKeepAlive(HttpRequest request) +{ + char * header; + char * header_ptr; + + header = httpHeaderGet(request->header, request->nheader, "connection"); + + if (NULL == header) { + return 0; + } + + for (header_ptr = header; 0 != *header_ptr; header_ptr++) { + *header_ptr = tolower(*header_ptr); + } + + if (0 == strcmp(header, "keep-alive")) { + return 1; + } + + return 0; +} + +// vim: set ts=4 sw=4: diff --git a/src/http/response.c b/src/http/response.c new file mode 100644 index 0000000..7150a29 --- /dev/null +++ b/src/http/response.c @@ -0,0 +1,60 @@ +#include +#include + +#include "class.h" +#include "interface/class.h" + +#include "http/response.h" + + +static +void +_free(void ** data) +{ + if (NULL != *data) { + free(*data); + } +} + +static +void +ctor(void * _this, va_list * params) +{ + char * version; + char * reason; + + HttpResponse this = _this; + + version = va_arg(* params, char *); + this->status = va_arg(* params, unsigned int); + reason = va_arg(* params, char *); + + this->version = calloc(1, strlen(version)+1); + strcpy(this->version, version); + + this->reason = calloc(1, strlen(reason)+1); + strcpy(this->reason, reason); +} + +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]); + } + + _free((void **)&(this->body)); +} + +INIT_IFACE(Class, ctor, dtor, NULL); +CREATE_CLASS(HttpResponse, NULL, IFACE(Class)); + +// vim: set ts=4 sw=4: diff --git a/src/http/response/404.c b/src/http/response/404.c new file mode 100644 index 0000000..d930354 --- /dev/null +++ b/src/http/response/404.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include + +#include "class.h" +#include "interface/class.h" + +#include "http/response.h" + + +#define RESP_DATA "\n" \ + "\n" \ + "\n" \ + "404 - Not Found" \ + "

404 - Not Found

" \ + "" + + +HttpResponse +httpResponse404() +{ + time_t t; + struct tm * tmp; + char buffer[200]; + HttpResponse response; + + response = new(HttpResponse, "HTTP/1.1", 404, "Not Found"); + + httpResponseHeaderSet(response, "Content-Type", "text/html"); + httpResponseHeaderSet(response, "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); + + t = time(NULL); + tmp = localtime(&t); + strftime(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", tmp); + httpResponseHeaderSet(response, "Date", buffer); + + return response; +} + +// vim: set ts=4 sw=4: diff --git a/src/http/response/header_set.c b/src/http/response/header_set.c new file mode 100644 index 0000000..00b259e --- /dev/null +++ b/src/http/response/header_set.c @@ -0,0 +1,13 @@ +#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 new file mode 100644 index 0000000..c33b0d0 --- /dev/null +++ b/src/http/response/size_get.c @@ -0,0 +1,27 @@ +#include +#include + +#include "http/response.h" +#include "http/header.h" + +size_t +httpResponseSizeGet(HttpResponse response) +{ + int i; + size_t 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; + } + + size += 2; + size += response->nbody; + + return size; +} + +// vim: set ts=4 sw=4: diff --git a/src/http/response/to_string.c b/src/http/response/to_string.c new file mode 100644 index 0000000..17f05b6 --- /dev/null +++ b/src/http/response/to_string.c @@ -0,0 +1,46 @@ +#include +#include + +#include "http/response.h" +#include "http/header.h" + +size_t +httpResponseToString(HttpResponse response, char * string) +{ + int i; + size_t size = httpResponseSizeGet(response); + char status[4]; + + snprintf(status, 4, "%d", response->status); + + strcpy(string, response->version); + string += strlen(string); + + *string++ = ' '; + + strcpy(string, status); + string += strlen(string); + + *string++ = ' '; + + strcpy(string, response->reason); + string += strlen(string); + + *string++ = '\r'; + *string++ = '\n'; + + for (i=0; inheader; i++) { + string += httpHeaderToString(response->header[i], string); + *string++ = '\r'; + *string++ = '\n'; + } + + *string++ = '\r'; + *string++ = '\n'; + + memcpy(string, response->body, response->nbody); + + return size; +} + +// vim: set ts=4 sw=4: diff --git a/src/server.c b/src/server.c index 3e26b30..7b73cd4 100644 --- a/src/server.c +++ b/src/server.c @@ -36,14 +36,14 @@ dtor(void * _this) Server this = _this; int i; - printf("nfds: %d\n", this->nfds); - for (i=1; infds; i++) { /* * @TODO do some finalization...buffer handling...etc. */ delete(&(this->conns[(this->fds)[i].fd]).sock); delete(&(this->conns[(this->fds)[i].fd]).reader); + if (this->conns[(this->fds)[i].fd].wbuf) + free(this->conns[(this->fds)[i].fd].wbuf); } delete(&this->sock); diff --git a/src/server/run.c b/src/server/run.c index 58bd24f..69d598d 100644 --- a/src/server/run.c +++ b/src/server/run.c @@ -18,7 +18,7 @@ #include "http/request.h" #include "http/request/parser.h" #include "http/request/queue.h" -#include "http/header.h" +#include "http/response.h" //* until here #undef MAX @@ -81,73 +81,36 @@ serverRun(Server this) ((HttpRequestParser)(this->conns)[fd].reader)->request_queue; for (j=0; jnrequests; j++) { - HttpRequest request = queue->requests[j]; - char * header; - char * header_ptr; - - //if (NULL != request->body) { - // puts("==REQUEST BODY=="); - // puts(request->body); - //} - - header = httpHeaderGet( - request->header, - request->nheader, - "connection"); - - if (NULL != header) { - for (header_ptr = header; - 0 != *header_ptr; - header_ptr++) { - *header_ptr = tolower(*header_ptr); - } - - if (0 == strcmp(header, "keep-alive")) { - (this->conns)[fd].keep_alive = 1; - } - } + HttpRequest request = queue->requests[j]; + HttpResponse response; + /** * @TODO: for now simply remove request and send not found. * Make this sane. */ + response = httpResponse404(); - delete(&request); - - /** - * @TODO: the complete response stuff have to be removed here. - */ - time_t t; - struct tm * tmp; - char timestr[200]; - -#define RESP_HEAD "HTTP/1.1 404 Not Found\r\n" \ - "Content-Type: text/html\r\n" \ - "Content-Length: %lu\r\n" \ - "Date: %s\r\n" \ - "Server: testserver\r\n" - -#define RESP_DATA "\n" \ - "\n" \ - "\n" \ - "404 - Not Found" \ - "

404 - Not Found

" \ - "" - - t = time(NULL); - tmp = localtime(&t); - strftime(timestr, sizeof(timestr), "%a, %d %b %Y %T %Z", tmp); - - /** - * @TODO: just to send an answer and be able to make some - * apache benchs i do it here...this definetly MUST BE moved - */ - if ((this->conns)[fd].keep_alive) { - sprintf((this->conns)[fd].wbuf, RESP_HEAD "Connection: Keep-Alive\r\n\r\n" RESP_DATA, sizeof(RESP_DATA) - 1, timestr); + if (httpRequestHasKeepAlive(request)) { + httpResponseHeaderSet( + response, + "Connection", + "Keep-Alive"); } else { - sprintf((this->conns)[fd].wbuf, RESP_HEAD "Connection: close\r\n\r\n" RESP_DATA, sizeof(RESP_DATA) - 1, timestr); + httpResponseHeaderSet( + response, + "Connection", + "Close"); } + + delete(&request); + + (this->conns)[fd].wbuf = calloc( + 1, httpResponseSizeGet(response) + 1); + httpResponseToString(response, (this->conns)[fd].wbuf); + + delete(&response); + (this->fds)[i].events |= POLLOUT; } @@ -180,6 +143,8 @@ serverRun(Server this) else { serverCloseConn(this, i); } + free((this->conns)[fd].wbuf); + (this->conns)[fd].wbuf = NULL; } else { memmove((this->conns)[fd].wbuf,