diff options
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 154 |
1 files changed, 4 insertions, 150 deletions
@@ -36,23 +36,6 @@ | |||
36 | */ | 36 | */ |
37 | 37 | ||
38 | #include "main.h" | 38 | #include "main.h" |
39 | // {{{ MACROS | ||
40 | #define EWOULDBLOCK_DELAY 100 | ||
41 | #define READ_BUFFER_LENGTH 9000 // jumboframe? | ||
42 | #define POST_DATA_MAX_LENGTH 18000 | ||
43 | #define DEBUG_SLEEP_TIME 50000 | ||
44 | |||
45 | #ifndef DEBUG | ||
46 | #define DEBUG(X, ...) // (X, ...) | ||
47 | #else | ||
48 | #include <stdarg.h> | ||
49 | static inline int verbose(const char * format, ...) { | ||
50 | va_list va; va_start(va, format); usleep(DEBUG_SLEEP_TIME); return vprintf(format, va); | ||
51 | } | ||
52 | #undef DEBUG | ||
53 | #define DEBUG verbose | ||
54 | #endif | ||
55 | // }}} | ||
56 | 39 | ||
57 | static int read_everything(FILE * f_r, FILE * output) { | 40 | static int read_everything(FILE * f_r, FILE * output) { |
58 | const int read_buffer_length = READ_BUFFER_LENGTH; | 41 | const int read_buffer_length = READ_BUFFER_LENGTH; |
@@ -76,7 +59,7 @@ static int read_everything(FILE * f_r, FILE * output) { | |||
76 | return EXIT_SUCCESS; | 59 | return EXIT_SUCCESS; |
77 | } | 60 | } |
78 | 61 | ||
79 | static void * next_customer(size_t new_socket) { | 62 | static void * answer_request(size_t new_socket) { |
80 | FILE * f_r = fdopen((size_t) new_socket, "r"); | 63 | FILE * f_r = fdopen((size_t) new_socket, "r"); |
81 | 64 | ||
82 | char * output_buffer = NULL; | 65 | char * output_buffer = NULL; |
@@ -86,137 +69,8 @@ static void * next_customer(size_t new_socket) { | |||
86 | read_everything(f_r, output); // TODO: catch return value and error handling | 69 | read_everything(f_r, output); // TODO: catch return value and error handling |
87 | shutdown(new_socket, SHUT_RD); // shutdown the reading half of the connection | 70 | shutdown(new_socket, SHUT_RD); // shutdown the reading half of the connection |
88 | 71 | ||
89 | char * start = output_buffer; | 72 | // TODO: make parsing function abstract (e.g. parse(...) function point with dlsym) |
90 | char * end = NULL; | 73 | parse_http(new_socket, output_buffer, output_buffer_length); |
91 | char * search = "\r\n"; | ||
92 | |||
93 | Http_Header http_header = {0}; | ||
94 | |||
95 | char * name = NULL; | ||
96 | while(NULL != (end = strpbrk(start, search))) { // TODO: try harder to break things (are SEGFAULTs possible?) | ||
97 | |||
98 | size_t matchlen = strspn(end, search); | ||
99 | switch(end[0]) { | ||
100 | case ':': | ||
101 | end[0] = '\0'; // {{{ remember header 'names' and search for the value | ||
102 | end++; // jump over the colon | ||
103 | |||
104 | name = start; // remember, where name starts, will be important in the newline case | ||
105 | |||
106 | if (0 == strcasecmp("Content-Type", start)) { | ||
107 | search = "\r\n;"; // (more unlikely) also search for a semicolon in Content-Type: [...]; boundary=[...] | ||
108 | } else { | ||
109 | search = "\r\n"; // (likely) search for some kind of newline | ||
110 | } // }}} | ||
111 | break; | ||
112 | case ';': | ||
113 | // {{{ find the form-data boundary in the main header | ||
114 | start += strspn(start, "; "); // remove spaces and semicolons (boundary check implicit; also stops at '\0') | ||
115 | |||
116 | const char s_multipart_form_data[] = "boundary="; | ||
117 | if(NULL == http_header.boundary && 0 < strcasecmp(start, s_multipart_form_data)) | ||
118 | { | ||
119 | http_header.boundary = end + sizeof(s_multipart_form_data) + 1; | ||
120 | http_header.boundary += strspn(http_header.boundary, "-"); | ||
121 | DEBUG("> Boundary found, now looking where it ends...\n"); | ||
122 | search = "\r\n"; | ||
123 | continue; | ||
124 | } /// }}} | ||
125 | break; | ||
126 | case '\r': // fallthrough | ||
127 | case '\n': | ||
128 | // {{{ newlines are special: sometimes content parts follow and sometimes headers, guess what... | ||
129 | end[0] = '\0'; | ||
130 | search = ":"; // we will continue to search for headers | ||
131 | if(NULL == name) { | ||
132 | if(NULL == http_header.method) { | ||
133 | DEBUG("[%ld]> HTTP REQUEST LINE :: %s \n", matchlen, start); | ||
134 | end[0] = '\0'; | ||
135 | |||
136 | while(NULL != (start = memchr(start, ' ', end - start))) { | ||
137 | if(NULL == http_header.url) | ||
138 | http_header.url = ++start; | ||
139 | else | ||
140 | start[0] = '\0'; | ||
141 | } | ||
142 | http_header.method = start; | ||
143 | http_header.newline_length = matchlen; | ||
144 | } else { | ||
145 | DEBUG("[...]\n"); // if we want to intentially skip something, we land here by setting name = NUL; | ||
146 | break; | ||
147 | } | ||
148 | } else { // we know that name is not NULL and can work with it | ||
149 | if (0 == strcasecmp("Content-Disposition", name)) | ||
150 | { http_header.content_disposition = start; } | ||
151 | } // }}} | ||
152 | DEBUG("\033[32m[%ld]> '% 20s' = '%s'\033[0m\n", matchlen, name, start); | ||
153 | // {{{ check if a http header ended (e.g. two newlines) | ||
154 | if(matchlen > http_header.newline_length) { | ||
155 | DEBUG("> END HEADERS, because there were %d newlines; boundary='%s'[%ld]\n", matchlen / http_header.newline_length, http_header.boundary, http_header.boundary_size); | ||
156 | end += matchlen; | ||
157 | |||
158 | // if it was the first header, we calculate the boundary size and expect more headers to come after a boundary | ||
159 | if(http_header.boundary && http_header.boundary_size == 0) { | ||
160 | DEBUG("================================================================================\n"); | ||
161 | http_header.boundary_size = strlen(http_header.boundary); | ||
162 | // skip the first header and boundary... | ||
163 | start = end; | ||
164 | start += strspn(start, "-"); | ||
165 | start += http_header.boundary_size; | ||
166 | start += http_header.newline_length; | ||
167 | continue; | ||
168 | } else { | ||
169 | char * content_start = end; | ||
170 | while(1) | ||
171 | { | ||
172 | size_t size_remaining = (size_t) output_buffer_length - (end - output_buffer) - 1; | ||
173 | DEBUG("%ld remaining.\n", size_remaining); | ||
174 | |||
175 | if(size_remaining <= 0) { | ||
176 | DEBUG("> not even the boundary would fit in that what is left.\n"); | ||
177 | break; | ||
178 | } | ||
179 | |||
180 | if(NULL == (end = memchr((void*) end, '-', size_remaining))) { | ||
181 | DEBUG("no further '-' found\n"); | ||
182 | break; | ||
183 | } | ||
184 | |||
185 | char * content_end = end - http_header.newline_length; | ||
186 | |||
187 | end += strspn(end, "-"); | ||
188 | if(0 == strncmp(end, http_header.boundary, http_header.boundary_size)) { | ||
189 | size_t file_size = content_end - content_start; | ||
190 | DEBUG("> Content ends here, size of the last file is %ld\n", file_size); | ||
191 | |||
192 | content_start[file_size + 1] = '\0'; | ||
193 | next_part(&http_header, content_start, file_size); | ||
194 | |||
195 | end += http_header.boundary_size; | ||
196 | matchlen = strspn(end, "\r\n"); | ||
197 | DEBUG("> end is at %p, matchlen is %ld\n", end, matchlen); | ||
198 | |||
199 | |||
200 | search = ":"; | ||
201 | break; | ||
202 | } else { | ||
203 | end = end + 1; | ||
204 | } | ||
205 | } | ||
206 | } | ||
207 | break; | ||
208 | } // }}} if condition after a header | ||
209 | } // switch | ||
210 | |||
211 | if(NULL == end) | ||
212 | break; | ||
213 | else | ||
214 | start = end + matchlen; | ||
215 | } | ||
216 | |||
217 | DEBUG("> sending answer...\n"); | ||
218 | send_answer(&http_header, new_socket); | ||
219 | DEBUG("> answer sent.\n"); | ||
220 | 74 | ||
221 | fclose(f_r); | 75 | fclose(f_r); |
222 | 76 | ||
@@ -242,7 +96,7 @@ static int serve(int server_fd) | |||
242 | fcntl(new_socket, F_GETFL) | O_NONBLOCK | 96 | fcntl(new_socket, F_GETFL) | O_NONBLOCK |
243 | ); | 97 | ); |
244 | 98 | ||
245 | next_customer(new_socket); | 99 | answer_request(new_socket); |
246 | 100 | ||
247 | #ifdef VALGRIND | 101 | #ifdef VALGRIND |
248 | break; // only run once, so that valgrind can test allocations&frees | 102 | break; // only run once, so that valgrind can test allocations&frees |