diff options
| -rw-r--r-- | http_parser.c | 81 | ||||
| -rw-r--r-- | main.c | 2 | ||||
| -rw-r--r-- | 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 @@ | |||
| 36 | */ | 36 | */ |
| 37 | 37 | ||
| 38 | #include "main.h" | 38 | #include "main.h" |
| 39 | #include <string.h> | ||
| 39 | 40 | ||
| 40 | static inline char * handle_colon(char ** start, char ** end, char ** search) { | 41 | static inline char * handle_colon(char ** start, char ** end, char ** search) { |
| 41 | // HTTP headers and content are separated by an empty line (which is two | 42 | // 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 | |||
| 64 | *end = *end + sizeof(s_multipart_form_data) + 1; | 65 | *end = *end + sizeof(s_multipart_form_data) + 1; |
| 65 | *end += strspn(*end, "-"); | 66 | *end += strspn(*end, "-"); |
| 66 | *start = *end; | 67 | *start = *end; |
| 67 | DEBUG("> Boundary found, now looking where it ends...\n"); | ||
| 68 | 68 | ||
| 69 | *end += strcspn(*end, "\r\n "); | 69 | *end += strcspn(*end, "\r\n "); |
| 70 | *end[0] = '\0'; | 70 | *end[0] = '\0'; |
| 71 | |||
| 72 | DEBUG("> Boundary found: %s\n", *start); | ||
| 71 | } | 73 | } |
| 72 | 74 | ||
| 73 | *search = "\r\n"; // do not search further semicolons | 75 | *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) { | |||
| 84 | // generic and only requires content length bounary checks. | 86 | // generic and only requires content length bounary checks. |
| 85 | 87 | ||
| 86 | char * start = request; | 88 | char * start = request; |
| 87 | char * end = NULL; | 89 | char * end = "\0"; |
| 88 | char * search = "\r\n"; | 90 | char * search = "\r\n"; |
| 89 | 91 | ||
| 90 | Http_Header http_header = {0}; | 92 | Http_Header http_header = {0}; |
| 91 | 93 | ||
| 94 | request[request_length] = '\0'; | ||
| 95 | |||
| 96 | // {{{ Parse the request line (e.g. "POST / HTTP/1.1") | ||
| 97 | http_header.method = start; | ||
| 98 | start += strcspn(start, " "); | ||
| 99 | start[0] = '\0'; | ||
| 100 | http_header.url = ++start; | ||
| 101 | start += strcspn(start, " "); | ||
| 102 | start[0] = '\0'; | ||
| 103 | http_header.protocol = ++start; | ||
| 104 | start += strcspn(start, "\r\n"); | ||
| 105 | http_header.newline_length = strspn(start, "\r\n"); | ||
| 106 | start[0] = '\0'; | ||
| 107 | start += http_header.newline_length; | ||
| 108 | |||
| 109 | DEBUG("%% Request line: method='%s' url='%s' protocol='%s' newline_length=%ld\n", | ||
| 110 | http_header.method, http_header.url, http_header.protocol, http_header.newline_length); | ||
| 111 | // }}} | ||
| 112 | |||
| 92 | char * name = NULL; | 113 | char * name = NULL; |
| 93 | while(NULL != (end = strpbrk(start, search))) { // TODO: try harder to break things (are SEGFAULTs possible?) | 114 | while(NULL != (end = strpbrk(start, search))) { // TODO: try harder to break things (are SEGFAULTs possible?) |
| 94 | 115 | ||
| @@ -96,61 +117,39 @@ void parse_http(size_t new_socket, char * request, size_t request_length) { | |||
| 96 | switch(end[0]) { | 117 | switch(end[0]) { |
| 97 | case ':': | 118 | case ':': |
| 98 | name = handle_colon(&start, &end, &search); | 119 | name = handle_colon(&start, &end, &search); |
| 99 | break; | 120 | break; |
| 100 | case ';': | 121 | case ';': |
| 101 | http_header.boundary = handle_semicolon(&start, &end, &search); | 122 | http_header.boundary = handle_semicolon(&start, &end, &search); |
| 102 | http_header.boundary_size = end - start; | 123 | http_header.boundary_size = end - start; |
| 103 | break; | 124 | break; |
| 104 | case '\r': // fallthrough | 125 | case '\r': // fallthrough |
| 105 | case '\n': | 126 | case '\n': |
| 106 | // {{{ newlines are special: sometimes content parts follow and sometimes headers, guess what... | ||
| 107 | end[0] = '\0'; | 127 | end[0] = '\0'; |
| 108 | search = ":"; // we will continue to search for headers | 128 | search = ":"; // we will continue to search for headers |
| 109 | if(NULL == name) { | 129 | |
| 110 | if(NULL == http_header.method) { | 130 | // {{{ NAME AND VALUE OF A HEADER FIELD KNOWN |
| 111 | DEBUG("[%ld]> HTTP REQUEST LINE :: %s \n", matchlen, start); | 131 | if(NULL != name) { |
| 112 | end[0] = '\0'; | 132 | DEBUG("\033[32m[%ld]> '% 20s' = '%s'\033[0m\n", matchlen, name, start); |
| 113 | 133 | ||
| 114 | while(NULL != (start = memchr(start, ' ', end - start))) { | ||
| 115 | if(NULL == http_header.url) | ||
| 116 | http_header.url = ++start; | ||
| 117 | else | ||
| 118 | start[0] = '\0'; | ||
| 119 | } | ||
| 120 | http_header.method = start; | ||
| 121 | http_header.newline_length = matchlen; | ||
| 122 | } else { | ||
| 123 | DEBUG("[...]\n"); // if we want to intentially skip something, we land here by setting name = NUL; | ||
| 124 | break; | ||
| 125 | } | ||
| 126 | } else { // we know that name is not NULL and can work with it | ||
| 127 | if (0 == strcasecmp("Content-Disposition", name)) | 134 | if (0 == strcasecmp("Content-Disposition", name)) |
| 128 | { http_header.content_disposition = start; } | 135 | { http_header.content_disposition = start; } |
| 129 | } // }}} | 136 | } // }}} |
| 130 | 137 | // {{{ END OF A HTTP HEADER (two newlines) | |
| 131 | // {{{ DEBUG | ||
| 132 | DEBUG("\033[32m[%ld]> '% 20s' = '%s'\033[0m\n", matchlen, name, start); | ||
| 133 | // }}} | ||
| 134 | |||
| 135 | // check if a http header ended (e.g. two newlines) | ||
| 136 | if(matchlen > http_header.newline_length) { | 138 | if(matchlen > http_header.newline_length) { |
| 137 | end += matchlen; // go behind the double line break... | 139 | end += matchlen; // go behind the double line break... |
| 138 | 140 | ||
| 139 | //{{{ DEBUG | 141 | DEBUG("%% END HEADERS, because there were %d newlines; boundary='%s'[%ld]\n", |
| 140 | DEBUG("> END HEADERS, because there were %d newlines; boundary='%s'[%ld]\n", | 142 | matchlen / http_header.newline_length, |
| 141 | matchlen / http_header.newline_length, | 143 | http_header.boundary, |
| 142 | http_header.boundary, | 144 | http_header.boundary_size |
| 143 | http_header.boundary_size | 145 | ); |
| 144 | ); // }}} | ||
| 145 | 146 | ||
| 146 | start = end; | 147 | start = end; |
| 147 | for(; ; ) | 148 | for(; ; ) |
| 148 | { | 149 | { |
| 149 | size_t size_remaining = (size_t) request_length - (end - request) - 1; | 150 | size_t size_remaining = (size_t) request_length - (end - request) - 1; |
| 150 | 151 | ||
| 151 | // {{{ DEBUG | ||
| 152 | DEBUG("%ld remaining.\n", size_remaining); | 152 | DEBUG("%ld remaining.\n", size_remaining); |
| 153 | // }}} | ||
| 154 | 153 | ||
| 155 | matchlen = strspn(end, "-"); | 154 | matchlen = strspn(end, "-"); |
| 156 | if(0 == strncmp(end + matchlen, http_header.boundary, http_header.boundary_size)) { | 155 | 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) { | |||
| 170 | if(!http_header.boundary | 169 | if(!http_header.boundary |
| 171 | || size_remaining <= 0 | 170 | || size_remaining <= 0 |
| 172 | || NULL == (end = memchr((void*) end, '-', size_remaining))) { | 171 | || NULL == (end = memchr((void*) end, '-', size_remaining))) { |
| 173 | // {{{ DEBUG | ||
| 174 | DEBUG("EOF reached or no further '-' found\n"); | 172 | DEBUG("EOF reached or no further '-' found\n"); |
| 175 | // }}} | ||
| 176 | break; | 173 | break; |
| 177 | } | 174 | } |
| 178 | // end++; | 175 | // end++; |
| 179 | } | 176 | } |
| 180 | } | 177 | } |
| 181 | break; | 178 | } // }}} if condition after a header |
| 182 | } // if condition after a header | 179 | break; |
| 180 | |||
| 181 | default: | ||
| 182 | DEBUG("Unknown char found: '%c'\n ", end[0]); | ||
| 183 | break; | ||
| 183 | } // switch | 184 | } // switch |
| 184 | 185 | ||
| 185 | if(NULL == end) | 186 | if(NULL == end) |
| @@ -70,7 +70,7 @@ static void * answer_request(size_t new_socket) { | |||
| 70 | fflush(output); | 70 | fflush(output); |
| 71 | // shutdown(new_socket, SHUT_RD); // shutdown the reading half of the connection | 71 | // shutdown(new_socket, SHUT_RD); // shutdown the reading half of the connection |
| 72 | 72 | ||
| 73 | DEBUG("output buffer has a length of %ld bytes\n", output_buffer_length); | 73 | DEBUG("> Output buffer has a length of %ld bytes\n", output_buffer_length); |
| 74 | 74 | ||
| 75 | // TODO: make parsing function abstract (e.g. parse(...) function point with dlsym) | 75 | // TODO: make parsing function abstract (e.g. parse(...) function point with dlsym) |
| 76 | parse_http(new_socket, output_buffer, output_buffer_length); | 76 | parse_http(new_socket, output_buffer, output_buffer_length); |
| @@ -73,6 +73,7 @@ static inline int verbose(const char * format, ...) { | |||
| 73 | typedef struct { | 73 | typedef struct { |
| 74 | int newline_length; // lenght of one newline in bytes (\n has 1, CR/LF has 2) | 74 | int newline_length; // lenght of one newline in bytes (\n has 1, CR/LF has 2) |
| 75 | char * method; // GET/POST or something like that | 75 | char * method; // GET/POST or something like that |
| 76 | char * protocol; // mostly HTTP/1.0 or HTTP/1.1 | ||
| 76 | char * url; // request URL (e.g. /index.html) | 77 | char * url; // request URL (e.g. /index.html) |
| 77 | char * boundary; // usually looks similar to ------1234 | 78 | char * boundary; // usually looks similar to ------1234 |
| 78 | size_t boundary_size; // size in bytes, calculated after first header complete; is an indicator for the first header | 79 | size_t boundary_size; // size in bytes, calculated after first header complete; is an indicator for the first header |
