summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.c96
1 files changed, 42 insertions, 54 deletions
diff --git a/main.c b/main.c
index 2a01a4e..3388a36 100644
--- a/main.c
+++ b/main.c
@@ -36,13 +36,13 @@ static inline int verbose(const char * format, ...) {
36// }}} 36// }}}
37 37
38typedef struct { 38typedef struct {
39 int newline_length; // lenght of one newline in bytes (\n has 1, CR/LF has 2) 39 int newline_length; // lenght of one newline in bytes (\n has 1, CR/LF has 2)
40 char * method; 40 char * method; // GET/POST or something like that
41 char * boundary; 41 char * url; // request URL (e.g. /index.html)
42 size_t boundary_size; 42 char * boundary; // usually looks similar to ------1234
43 char * content_type; 43 size_t boundary_size; // size in bytes, calculated after first header complete; is an indicator for the first header
44 char * content_disposition; 44 char * content_type; // sometimes 'text/html', also sometimes 'text/html; boundary=------1234'
45 char * url; 45 char * content_disposition; // includes file names of uploaded files or field names with form-data (e.g. curl -F)
46} Http_Header; 46} Http_Header;
47 47
48void send_answer(int fd_socket, Http_Header * http_header) { 48void send_answer(int fd_socket, Http_Header * http_header) {
@@ -57,24 +57,11 @@ void send_answer(int fd_socket, Http_Header * http_header) {
57 fstat(file, &stat); 57 fstat(file, &stat);
58 sendfile (fileno(f), file, NULL, stat.st_size); 58 sendfile (fileno(f), file, NULL, stat.st_size);
59 } else { 59 } else {
60 fprintf(f, "could not open file \"%s\"\n", &http_header->url[1]); 60 if(http_header->url) // TODO: too dangerous to check that here, that is too late.
61 fprintf(f, "could not open file \"%s\"\n", &http_header->url[1]);
61 } 62 }
62 63
63 fclose(f); 64 fclose(f);
64
65 // fputs("<html>", f);
66 // fputs("<head>", f);
67 // fputs("<title>test</title>", f);
68 // fputs("<style>label { display:block }</style>", f);
69 // fputs("</head>", f);
70 // fputs("<form action=\"/\" method=\"post\" enctype=\"multipart/form-data\">", f);
71 // fputs("<label>Line1<br/>\n", f);
72 // fputs("<textarea type=\"text\" name=\"text\"></textarea>", f);
73 // fputs("</label><br/>\n", f);
74 // fputs("<input type=\"file\" name=\"okay\" value=\"ok\" />", f);
75 // fputs("<input type=\"submit\" name=\"okay\" value=\"ok\" />", f);
76 // fputs("</form>", f);
77 // fputs("</html>", f);
78} 65}
79 66
80int read_everything(FILE * f_r, FILE * output) { 67int read_everything(FILE * f_r, FILE * output) {
@@ -106,10 +93,8 @@ void * next_customer(size_t new_socket) {
106 size_t output_buffer_length = 0; 93 size_t output_buffer_length = 0;
107 FILE * output = open_memstream(&output_buffer, &output_buffer_length); 94 FILE * output = open_memstream(&output_buffer, &output_buffer_length);
108 95
109 DEBUG("\n\n########################################## Content Reader [%d]\n", f_r); 96 read_everything(f_r, output); // TODO: catch return value and error handling
110 read_everything(f_r, output);
111 shutdown(new_socket, SHUT_RD); // shutdown the reading half of the connection 97 shutdown(new_socket, SHUT_RD); // shutdown the reading half of the connection
112 DEBUG("\n\n########################################## Content Parser\n");
113 98
114 char * start = output_buffer; 99 char * start = output_buffer;
115 char * end = NULL; 100 char * end = NULL;
@@ -118,24 +103,25 @@ void * next_customer(size_t new_socket) {
118 Http_Header http_header = {0}; 103 Http_Header http_header = {0};
119 104
120 char * name = NULL; 105 char * name = NULL;
121 while(NULL != (end = strpbrk(start, search))) { 106 while(NULL != (end = strpbrk(start, search))) { // TODO: try harder to break things (are SEGFAULTs possible?)
122 107
123 size_t matchlen = strspn(end, search); 108 size_t matchlen = strspn(end, search);
124 switch(end[0]) { 109 switch(end[0]) {
125 case ':': 110 case ':':
126 end[0] = '\0'; // {{{ remember header 'names' and search for the value 111 end[0] = '\0'; // {{{ remember header 'names' and search for the value
127 end++; 112 end++; // jump over the colon
128 113
129 name = start; 114 name = start; // remember, where name starts, will be important in the newline case
130 115
131 if (0 == strcasecmp("Content-Type", start)) { 116 if (0 == strcasecmp("Content-Type", start)) {
132 search = "\r\n;"; 117 search = "\r\n;"; // (more unlikely) also search for a semicolon in Content-Type: [...]; boundary=[...]
133 } else { 118 } else {
134 search = "\r\n"; 119 search = "\r\n"; // (likely) search for some kind of newline
135 } // }}} 120 } // }}}
136 break; 121 break;
137 case ';': 122 case ';':
138 start += strspn(start, "; "); // {{{ find the form-data boundary in the main header 123 // {{{ find the form-data boundary in the main header
124 start += strspn(start, "; "); // remove spaces and semicolons (boundary check implicit; also stops at '\0')
139 125
140 const char s_multipart_form_data[] = "boundary="; 126 const char s_multipart_form_data[] = "boundary=";
141 if(NULL == http_header.boundary && 0 < strcasecmp(start, s_multipart_form_data)) 127 if(NULL == http_header.boundary && 0 < strcasecmp(start, s_multipart_form_data))
@@ -248,14 +234,14 @@ void * next_customer(size_t new_socket) {
248 234
249int serve(int server_fd) 235int serve(int server_fd)
250{ 236{
251 struct sockaddr_in address; 237 struct sockaddr_in address;
252 socklen_t address_len = sizeof(address); 238 socklen_t address_len = sizeof(address);
253 DEBUG("waiting for connections on server file descriptor %d", server_fd); 239 DEBUG("> Waiting for connections on server file descriptor %d\n", server_fd);
254 240
255 size_t new_socket = -1; 241 size_t new_socket = -1;
256 while(-1 != (new_socket = accept(server_fd, (struct sockaddr*) &address, &address_len))) 242 while(-1 != (new_socket = accept(server_fd, (struct sockaddr*) &address, &address_len)))
257 { 243 {
258 DEBUG("> Client %ld is connected via port %d", new_socket, address.sin_port); 244 DEBUG("> Client %ld is connected via port %d\n", new_socket, address.sin_port);
259 245
260 // set non blocking mode... 246 // set non blocking mode...
261 fcntl( 247 fcntl(
@@ -269,33 +255,35 @@ int serve(int server_fd)
269#ifdef VALGRIND 255#ifdef VALGRIND
270 break; // only run once, so that valgrind can test allocations&frees 256 break; // only run once, so that valgrind can test allocations&frees
271#endif 257#endif
272 } 258 }
273 259
274 err(errno, "error serving"); 260 err(errno, "error serving");
275 close(server_fd); 261 close(server_fd);
276} 262}
277 263
278#define PORT 8080 264int main(const int argc, char const * argv[]) {
279int main(int argc, char const *argv[]) 265 int server_fd = -1, opt = 1;
280{ 266
281 int server_fd = -1, opt = 1; 267 int port = atoi(argc > 1 ? argv[1] : "8080");
268 0 == port ? port = 8080 : port;
282 269
283 struct sockaddr_in address = { 270
284 .sin_family = AF_INET, 271 struct sockaddr_in address = {
285 .sin_addr.s_addr = INADDR_ANY, 272 .sin_family = AF_INET,
286 .sin_port = htons(PORT) 273 .sin_addr.s_addr = INADDR_ANY,
274 .sin_port = htons(port)
287 }; 275 };
288 276
289 // I <3 C 277 // I <3 C
290 0 == (server_fd = socket(AF_INET, SOCK_STREAM, 0)) 278 0 == (server_fd = socket(AF_INET, SOCK_STREAM, 0))
291 ? err(errno, NULL) 279 ? err(errno, NULL)
292 : setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)) 280 : setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))
293 ? err(errno, "setsockopt failed on socket with fileno %d", server_fd) 281 ? err(errno, "setsockopt failed on socket with fileno %d", server_fd)
294 : bind(server_fd, (struct sockaddr*) &address, sizeof(address)) 282 : bind(server_fd, (struct sockaddr*) &address, sizeof(address))
295 ? err(errno, NULL) 283 ? err(errno, NULL)
296 : listen(server_fd, SOMAXCONN) 284 : listen(server_fd, SOMAXCONN)
297 ? err(errno, NULL) 285 ? err(errno, NULL)
298 : serve(server_fd) 286 : serve(server_fd)
299 ? err(errno, NULL) 287 ? err(errno, NULL)
300 : exit(EXIT_SUCCESS) 288 : exit(EXIT_SUCCESS)
301 ; return EXIT_FAILURE; 289 ; return EXIT_FAILURE;
..