From abd69d0a2057d2d52f8794925854a82984d5135c Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Mon, 20 Feb 2012 07:55:06 +0100 Subject: [PATCH] disconnect on invalid request line --- ChangeLog | 8 ++- include/cbuf.h | 1 + include/http/message.h | 3 ++ include/http/request.h | 6 +++ src/Makefile.am | 8 +-- src/cbuf/empty.c | 10 ++++ src/http/message/get_version.c | 28 ++++++++++ src/http/message/has_valid_version.c | 32 ++++++++++++ src/http/request/has_valid_method.c | 31 +++++++++++ src/http/request/parser/get_request_line.c | 61 +++++++--------------- src/http/request/parser/parse.c | 19 ++++--- 11 files changed, 149 insertions(+), 58 deletions(-) create mode 100644 src/cbuf/empty.c create mode 100644 src/http/message/get_version.c create mode 100644 src/http/message/has_valid_version.c create mode 100644 src/http/request/has_valid_method.c diff --git a/ChangeLog b/ChangeLog index 8061ada..466b416 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,10 +1,14 @@ +2012-02-20 07:55:06 +0100 Georg Hopp + + * disconnect on invalid request line (HEAD, master) + 2012-02-19 20:12:40 +0100 Georg Hopp - * now incomplete requests should no longer block the complete server. Tested with \'echo -en "GET / HTTP\r\nConn" | nc -w 600 localhost 11212\' and then doing requests from my browser. @TODO: cleanup those stuff, check if a not correctly response reading would block the server. (HEAD, master) + * now incomplete requests should no longer block the complete server. Tested with \'echo -en "GET / HTTP\r\nConn" | nc -w 600 localhost 11212\' and then doing requests from my browser. @TODO: cleanup those stuff, check if a not correctly response reading would block the server. (origin/master, origin/HEAD) 2012-02-19 18:28:30 +0100 Georg Hopp - * increase writebuffer size a lot. (origin/master, origin/HEAD) + * increase writebuffer size a lot. 2012-02-19 18:15:55 +0100 Georg Hopp diff --git a/include/cbuf.h b/include/cbuf.h index 0c2a7e4..aeb5815 100644 --- a/include/cbuf.h +++ b/include/cbuf.h @@ -45,6 +45,7 @@ ssize_t cbufWrite(Cbuf, int fd); char * cbufGetLine(Cbuf); char * cbufGetData(Cbuf, size_t); char * cbufSetData(Cbuf, const void *, size_t); +void cbufEmpty(Cbuf); char * cbufGetRead(Cbuf this); char * cbufGetWrite(Cbuf this); diff --git a/include/http/message.h b/include/http/message.h index 876360d..677b87b 100644 --- a/include/http/message.h +++ b/include/http/message.h @@ -26,6 +26,9 @@ char httpMessageHasKeepAlive(HttpMessage); size_t httpMessageHeaderSizeGet(HttpMessage); char * httpMessageHeaderToString(HttpMessage, char *); +int httpMessageGetVersion(HttpMessage, int *, int *); +int httpMessageHasValidVersion(HttpMessage); + #endif // __HTTP_MESSAGE__ // vim: set ts=4 sw=4: diff --git a/include/http/request.h b/include/http/request.h index a0472ab..6e606fa 100644 --- a/include/http/request.h +++ b/include/http/request.h @@ -4,6 +4,10 @@ #include "class.h" #include "http/message.h" +#define N_HTTP_METHOD 8 + +char * http_method[N_HTTP_METHOD]; + CLASS(HttpRequest) { EXTENDS(HttpMessage); @@ -11,6 +15,8 @@ CLASS(HttpRequest) { char * uri; }; +int httpRequestHasValidMethod(HttpRequest); + #endif /* __HTTP_REQUEST_H__ */ // vim: set ts=4 sw=4: diff --git a/src/Makefile.am b/src/Makefile.am index 2d2256a..0c3791b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,10 +13,12 @@ CB = cbuf.c cbuf/read.c cbuf/write.c \ cbuf/get_line.c cbuf/set_data.c cbuf/get_data.c \ cbuf/addr_index.c cbuf/get_free.c cbuf/get_read.c cbuf/get_write.c \ cbuf/inc_read.c cbuf/inc_write.c cbuf/is_empty.c cbuf/memchr.c \ - cbuf/skip_non_alpha.c cbuf/is_locked.c cbuf/lock.c cbuf/release.c + cbuf/skip_non_alpha.c cbuf/is_locked.c cbuf/lock.c cbuf/release.c \ + cbuf/empty.c MSG = http/message.c http/message/queue.c http/message/has_keep_alive.c \ - http/message/header_size_get.c http/message/header_to_string.c -REQ = http/request.c + http/message/header_size_get.c http/message/header_to_string.c \ + http/message/get_version.c http/message/has_valid_version.c +REQ = http/request.c http/request/has_valid_method.c RESP = http/response.c \ http/response/404.c \ http/response/image.c \ diff --git a/src/cbuf/empty.c b/src/cbuf/empty.c new file mode 100644 index 0000000..b7429fc --- /dev/null +++ b/src/cbuf/empty.c @@ -0,0 +1,10 @@ +#include "cbuf.h" + +void +cbufEmpty(Cbuf this) +{ + this->bused = 0; + this->read = this->write; +} + +// vim: set ts=4 sw=4: diff --git a/src/http/message/get_version.c b/src/http/message/get_version.c new file mode 100644 index 0000000..32b18df --- /dev/null +++ b/src/http/message/get_version.c @@ -0,0 +1,28 @@ +#include +#include + +#include "http/message.h" + +int +httpMessageGetVersion(HttpMessage this, int * major, int * minor) +{ + char * major_ptr = this->version + 5; + char * minor_ptr = strchr(major_ptr, '.') + 1; + char version[] = "\0\0\0"; + + if (NULL == minor_ptr || + ((minor_ptr - major_ptr - 1) > 2) || + strlen(minor_ptr) > 2) + return -1; + + memcpy(version, major_ptr, minor_ptr - major_ptr - 1); + *major = atoi(version); + + memset(version, 0, 3); + strcpy(version, minor_ptr); + *minor = atoi(version); + + return ((*major)<<7)|(*minor); +} + +// vim: set ts=4 sw=4: diff --git a/src/http/message/has_valid_version.c b/src/http/message/has_valid_version.c new file mode 100644 index 0000000..af66092 --- /dev/null +++ b/src/http/message/has_valid_version.c @@ -0,0 +1,32 @@ +#include + +#include "http/message.h" + +int +httpMessageHasValidVersion(HttpMessage this) +{ + int major; + int minor; + + if (NULL == this->version) + return 0; + + if (8 > strlen(this->version)) + return 0; + + if (0 > httpMessageGetVersion(this, &major, &minor)) + return 0; + + if (0 != memcmp("HTTP/", this->version, sizeof("HTTP/")-1)) + return 0; + + if (1 != major) + return 0; + + if (0 > minor || 1 < minor) + return 0; + + return 1; +} + +// vim: set ts=4 sw=4: diff --git a/src/http/request/has_valid_method.c b/src/http/request/has_valid_method.c new file mode 100644 index 0000000..10a4150 --- /dev/null +++ b/src/http/request/has_valid_method.c @@ -0,0 +1,31 @@ +#include + +#include "http/request.h" + +char * http_method[N_HTTP_METHOD] = { + "OPTIONS", + "GET", + "HEAD", + "POST", + "PUT", + "DELETE", + "TRACE", + "CONNECT"}; + +int +httpRequestHasValidMethod(HttpRequest this) +{ + int i; + + if (NULL == this->method) + return 0; + + for (i=0; imethod)) + break; + } + + return (i != N_HTTP_METHOD); +} + +// vim: set ts=4 sw=4: diff --git a/src/http/request/parser/get_request_line.c b/src/http/request/parser/get_request_line.c index 5b556fd..f77c967 100644 --- a/src/http/request/parser/get_request_line.c +++ b/src/http/request/parser/get_request_line.c @@ -39,57 +39,32 @@ char * method[N_METHODS] = { ssize_t httpRequestParserGetRequestLine(HttpRequestParser this, char * cr) { - HttpRequest request = this->cur_request; + char * method, * uri, * version; HttpMessage message = (HttpMessage)request; - char * space1, * space2; - size_t len = cr - this->buffer->buffer - this->buffer->bstart; - int i; - space1 = memchr( - this->buffer->buffer + this->buffer->bstart, - ' ', len); + method = line; + uri = strchr(line, ' '); - if (NULL == space1) { - return -1; - } + if (NULL == uri) + return; - len = cr - space1; - space2 = memchr(space1 + 1, ' ', len); + *uri++ = 0; + for (; *uri == ' ' && *uri != 0; uri++); - if (NULL == space2) { - return -1; - } + version = strchr(uri, ' '); - len = space1 - this->buffer->buffer - this->buffer->bstart; - request->method = calloc(1, len + 1); - memcpy(request->method, - this->buffer->buffer + this->buffer->bstart, - len); + if (NULL == version) + return; - for (i= 0; i< N_METHODS; i++) { - if (0 == memcmp(method[i], request->method, MIN_SIZE(method[i], len))) { - break; - } - } + *version++ = 0; + for (; *version == ' ' && *version != 0; version++); - if (i == N_METHODS) { - return -1; - } - - len = space2 - space1 - 1; - request->uri = calloc(1, len + 1); - memcpy(request->uri, space1 + 1, len); - - len = cr - space2 - 1; - message->version = calloc(1, len + 1); - memcpy(message->version, space2 + 1, len); - - if (len+1 != sizeof("HTTP/1.1") || - 0 != memcmp("HTTP/1.", message->version, len-1)) { - return -1; - } - - return 1; //* @TODO: return something useful here + request->method = malloc(strlen(method) + 1); + strcpy(request->method, method); + request->uri = malloc(strlen(uri) + 1); + strcpy(request->uri, uri); + message->version = malloc(strlen(version) + 1); + strcpy(message->version, version); } // vim: set ts=4 sw=4: diff --git a/src/http/request/parser/parse.c b/src/http/request/parser/parse.c index b24bbd0..358c0aa 100644 --- a/src/http/request/parser/parse.c +++ b/src/http/request/parser/parse.c @@ -83,18 +83,17 @@ httpRequestParserParse(HttpRequestParser this, int fd) break; } - if (0 > httpRequestParserGetRequestLine(this, line_end)) { - ret = -1; - cont = 0; - break; + httpRequestParserGetRequestLine(this->cur_request, line); + if (! httpRequestHasValidMethod(this->cur_request)) { + cbufRelease(this->buffer); + this->ourLock = FALSE; + return -1; } - - len = line_end - this->buffer->buffer - this->buffer->bstart + 2; - this->buffer->bstart += len; - if (this->buffer->bstart >= this->buffer->bsize) { - this->buffer->bstart -= this->buffer->bsize; + if (! httpMessageHasValidVersion((HttpMessage)this->cur_request)) { + cbufRelease(this->buffer); + this->ourLock = FALSE; + return -1; } - this->buffer->bused -= len; this->state = HTTP_REQUEST_REQUEST_LINE_DONE; break;