From 512c406b4fb3bc4054073608707ae07f65a65890 Mon Sep 17 00:00:00 2001 From: Max Christian Pohle Date: Mon, 29 Nov 2021 16:14:37 +0100 Subject: still getting this code shorter --- http_parser.c | 81 ++++++++++++++++++++++++++++++----------------------------- main.c | 2 +- main.h | 1 + 3 files changed, 43 insertions(+), 41 deletions(-) diff --git a/http_parser.c b/http_parser.c index 03d8d91..fb891cc 100644 --- a/http_parser.c +++ b/http_parser.c @@ -36,6 +36,7 @@ */ #include "main.h" +#include static inline char * handle_colon(char ** start, char ** end, char ** search) { // HTTP headers and content are separated by an empty line (which is two @@ -64,10 +65,11 @@ static inline char * handle_semicolon(char ** start, char ** end, char ** searc *end = *end + sizeof(s_multipart_form_data) + 1; *end += strspn(*end, "-"); *start = *end; - DEBUG("> Boundary found, now looking where it ends...\n"); *end += strcspn(*end, "\r\n "); *end[0] = '\0'; + + DEBUG("> Boundary found: %s\n", *start); } *search = "\r\n"; // do not search further semicolons @@ -84,11 +86,30 @@ void parse_http(size_t new_socket, char * request, size_t request_length) { // generic and only requires content length bounary checks. char * start = request; - char * end = NULL; + char * end = "\0"; char * search = "\r\n"; Http_Header http_header = {0}; + request[request_length] = '\0'; + + // {{{ Parse the request line (e.g. "POST / HTTP/1.1") + http_header.method = start; + start += strcspn(start, " "); + start[0] = '\0'; + http_header.url = ++start; + start += strcspn(start, " "); + start[0] = '\0'; + http_header.protocol = ++start; + start += strcspn(start, "\r\n"); + http_header.newline_length = strspn(start, "\r\n"); + start[0] = '\0'; + start += http_header.newline_length; + + DEBUG("%% Request line: method='%s' url='%s' protocol='%s' newline_length=%ld\n", + http_header.method, http_header.url, http_header.protocol, http_header.newline_length); + // }}} + char * name = NULL; while(NULL != (end = strpbrk(start, search))) { // TODO: try harder to break things (are SEGFAULTs possible?) @@ -96,61 +117,39 @@ void parse_http(size_t new_socket, char * request, size_t request_length) { switch(end[0]) { case ':': name = handle_colon(&start, &end, &search); - break; + break; case ';': http_header.boundary = handle_semicolon(&start, &end, &search); http_header.boundary_size = end - start; break; case '\r': // fallthrough case '\n': - // {{{ newlines are special: sometimes content parts follow and sometimes headers, guess what... end[0] = '\0'; search = ":"; // we will continue to search for headers - if(NULL == name) { - if(NULL == http_header.method) { - DEBUG("[%ld]> HTTP REQUEST LINE :: %s \n", matchlen, start); - end[0] = '\0'; - - while(NULL != (start = memchr(start, ' ', end - start))) { - if(NULL == http_header.url) - http_header.url = ++start; - else - start[0] = '\0'; - } - http_header.method = start; - http_header.newline_length = matchlen; - } else { - DEBUG("[...]\n"); // if we want to intentially skip something, we land here by setting name = NUL; - break; - } - } else { // we know that name is not NULL and can work with it + + // {{{ NAME AND VALUE OF A HEADER FIELD KNOWN + if(NULL != name) { + DEBUG("\033[32m[%ld]> '% 20s' = '%s'\033[0m\n", matchlen, name, start); + if (0 == strcasecmp("Content-Disposition", name)) { http_header.content_disposition = start; } } // }}} - - // {{{ DEBUG - DEBUG("\033[32m[%ld]> '% 20s' = '%s'\033[0m\n", matchlen, name, start); - // }}} - - // check if a http header ended (e.g. two newlines) + // {{{ END OF A HTTP HEADER (two newlines) if(matchlen > http_header.newline_length) { end += matchlen; // go behind the double line break... - //{{{ DEBUG - DEBUG("> END HEADERS, because there were %d newlines; boundary='%s'[%ld]\n", - matchlen / http_header.newline_length, - http_header.boundary, - http_header.boundary_size - ); // }}} + DEBUG("%% END HEADERS, because there were %d newlines; boundary='%s'[%ld]\n", + matchlen / http_header.newline_length, + http_header.boundary, + http_header.boundary_size + ); start = end; for(; ; ) { size_t size_remaining = (size_t) request_length - (end - request) - 1; - // {{{ DEBUG DEBUG("%ld remaining.\n", size_remaining); - // }}} matchlen = strspn(end, "-"); if(0 == strncmp(end + matchlen, http_header.boundary, http_header.boundary_size)) { @@ -170,16 +169,18 @@ void parse_http(size_t new_socket, char * request, size_t request_length) { if(!http_header.boundary || size_remaining <= 0 || NULL == (end = memchr((void*) end, '-', size_remaining))) { - // {{{ DEBUG DEBUG("EOF reached or no further '-' found\n"); - // }}} break; } // end++; } } - break; - } // if condition after a header + } // }}} if condition after a header + break; + + default: + DEBUG("Unknown char found: '%c'\n ", end[0]); + break; } // switch if(NULL == end) diff --git a/main.c b/main.c index 96cfa67..887680a 100644 --- a/main.c +++ b/main.c @@ -70,7 +70,7 @@ static void * answer_request(size_t new_socket) { fflush(output); // shutdown(new_socket, SHUT_RD); // shutdown the reading half of the connection - DEBUG("output buffer has a length of %ld bytes\n", output_buffer_length); + DEBUG("> Output buffer has a length of %ld bytes\n", output_buffer_length); // TODO: make parsing function abstract (e.g. parse(...) function point with dlsym) parse_http(new_socket, output_buffer, output_buffer_length); diff --git a/main.h b/main.h index 826ef47..a9509f0 100644 --- a/main.h +++ b/main.h @@ -73,6 +73,7 @@ static inline int verbose(const char * format, ...) { typedef struct { int newline_length; // lenght of one newline in bytes (\n has 1, CR/LF has 2) char * method; // GET/POST or something like that + char * protocol; // mostly HTTP/1.0 or HTTP/1.1 char * url; // request URL (e.g. /index.html) char * boundary; // usually looks similar to ------1234 size_t boundary_size; // size in bytes, calculated after first header complete; is an indicator for the first header -- cgit v1.2.3