summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
authorMax Christian Pohle2021-11-24 01:22:54 +0100
committerMax Christian Pohle2021-11-24 01:22:54 +0100
commitdb864e290ba1ec4acd74371b150e7770585ef284 (patch)
tree80f2ba16e4520bc1f4bfe28eac7fdb747c58710e /main.c
parent21ab0292a9c07d2377047969a4d530a15e465907 (diff)
downloadohmycgi-db864e290ba1ec4acd74371b150e7770585ef284.tar.bz2
ohmycgi-db864e290ba1ec4acd74371b150e7770585ef284.zip
Made the implementation more generic again
Diffstat (limited to 'main.c')
-rw-r--r--main.c154
1 files changed, 4 insertions, 150 deletions
diff --git a/main.c b/main.c
index c1a7c30..8eb6f40 100644
--- a/main.c
+++ b/main.c
@@ -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>
49static 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
57static int read_everything(FILE * f_r, FILE * output) { 40static 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
79static void * next_customer(size_t new_socket) { 62static 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
..