even better way of doing query string in httpd
[clinton/Smoothieware.git] / src / libs / Network / uip / webserver / httpd.c
1 #pragma GCC diagnostic ignored "-Wredundant-decls"
2 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
3 #pragma GCC diagnostic ignored "-Wcast-align"
4 #pragma GCC diagnostic ignored "-Wcast-qual"
5 #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
6
7 /**
8 * \addtogroup apps
9 * @{
10 */
11
12 /**
13 * \defgroup httpd Web server
14 * @{
15 * The uIP web server is a very simplistic implementation of an HTTP
16 * server. It can serve web pages and files from a read-only ROM
17 * filesystem, and provides a very small scripting language.
18
19 */
20
21 /**
22 * \file
23 * Web server
24 * \author
25 * Adam Dunkels <adam@sics.se>
26 */
27
28
29 /*
30 * Copyright (c) 2004, Adam Dunkels.
31 * All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. Neither the name of the Institute nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 *
57 * This file is part of the uIP TCP/IP stack.
58 *
59 * Author: Adam Dunkels <adam@sics.se>
60 *
61 * $Id: httpd.c,v 1.2 2006/06/11 21:46:38 adam Exp $
62 */
63
64 #include <stdio.h>
65
66 #include "uip.h"
67 #include "httpd.h"
68 #include "httpd-fs.h"
69 #include "http-strings.h"
70
71 #include <string.h>
72 #include "stdio.h"
73 #include "stdlib.h"
74
75 #include "CommandQueue.h"
76 #include "CallbackStream.h"
77
78 #include "c-fifo.h"
79
80 #define STATE_WAITING 0
81 #define STATE_HEADERS 1
82 #define STATE_BODY 2
83 #define STATE_OUTPUT 3
84 #define STATE_UPLOAD 4
85
86 #define GET 1
87 #define POST 2
88 #define OPTIONS 3
89
90 #define ISO_nl 0x0a
91 #define ISO_space 0x20
92 #define ISO_bang 0x21
93 #define ISO_percent 0x25
94 #define ISO_period 0x2e
95 #define ISO_slash 0x2f
96 #define ISO_colon 0x3a
97
98 //#define DEBUG_PRINTF printf
99 #define DEBUG_PRINTF(...)
100
101 extern const char *get_query_string();
102
103 // this callback gets the results of a command, line by line. need to check if
104 // we need to stall the upstream sender return 0 if stalled 1 if ok to keep
105 // providing more -1 if the connection has closed or is not in output state.
106 // need to see which connection to send to based on state and add result to
107 // that fifo for each connection. NOTE this will not get called if the
108 // connection has been closed and the stream will get deleted when the last
109 // command has been executed
110 static int command_result(const char *str, void *state)
111 {
112 struct httpd_state *s = (struct httpd_state *)state;
113 if (s == NULL) {
114 // connection was closed so discard, this should never happen
115 DEBUG_PRINTF("ERROR: command result for closed state %d\n", (int)state);
116 return -1;
117 }
118
119 if (str == NULL) {
120 DEBUG_PRINTF("End of command (%p)\n", state);
121 fifo_push(s->fifo, NULL);
122
123 } else {
124 if (fifo_size(s->fifo) < 10) {
125 DEBUG_PRINTF("Got command result (%p): %s", state, str);
126 fifo_push(s->fifo, strdup(str));
127 return 1;
128 } else {
129 DEBUG_PRINTF("command result fifo is full (%p)\n", state);
130 return 0;
131 }
132 }
133 return 1;
134 }
135
136 static void create_callback_stream(struct httpd_state *s)
137 {
138 // need to create a callback stream here, but do one per connection pass
139 // the state to the callback, also create the fifo for the command results
140 s->fifo = new_fifo();
141 s->pstream = new_callback_stream(command_result, s);
142 }
143
144 // Used to save files to SDCARD during upload
145 static FILE *fd;
146 static char *output_filename = NULL;
147 static int file_cnt = 0;
148 static int open_file(const char *fn)
149 {
150 if (output_filename != NULL) free(output_filename);
151 output_filename = malloc(strlen(fn) + 5);
152 strcpy(output_filename, "/sd/");
153 strcat(output_filename, fn);
154 fd = fopen(output_filename, "w");
155 if (fd == NULL) {
156 free(output_filename);
157 output_filename = NULL;
158 return 0;
159 }
160 return 1;
161 }
162
163 static int close_file()
164 {
165 free(output_filename);
166 output_filename = NULL;
167 fclose(fd);
168 return 1;
169 }
170
171 static int save_file(uint8_t *buf, unsigned int len)
172 {
173 if (fwrite(buf, 1, len, fd) == len) {
174 file_cnt += len;
175 return 1;
176
177 } else {
178 close_file();
179 return 0;
180 }
181 }
182
183 static int fs_open(struct httpd_state *s)
184 {
185 if (strncmp(s->filename, "/sd/", 4) == 0) {
186 DEBUG_PRINTF("Opening file %s\n", s->filename);
187 s->fd = fopen(s->filename, "r");
188 if (s->fd == NULL) {
189 DEBUG_PRINTF("Failed to open: %s\n", s->filename);
190 return 0;
191 }
192 return 1;
193
194 } else {
195 s->fd = NULL;
196 return httpd_fs_open(s->filename, &s->file);
197 }
198 }
199
200 /*---------------------------------------------------------------------------*/
201 static PT_THREAD(send_command_response(struct httpd_state *s))
202 {
203 PSOCK_BEGIN(&s->sout);
204
205 do {
206 PSOCK_WAIT_UNTIL( &s->sout, fifo_size(s->fifo) > 0 );
207 s->strbuf = fifo_pop(s->fifo);
208 if (s->strbuf != NULL) {
209 // send it
210 DEBUG_PRINTF("Sending response: %s", s->strbuf);
211 // TODO send as much as we can in one packet
212 PSOCK_SEND_STR(&s->sout, s->strbuf);
213 // free the strdup
214 free(s->strbuf);
215 }else if(--s->command_count <= 0) {
216 // when all commands have completed exit
217 break;
218 }
219 } while (1);
220
221 PSOCK_END(&s->sout);
222 }
223
224 /*---------------------------------------------------------------------------*/
225 static unsigned short generate_part_of_file(void *state)
226 {
227 struct httpd_state *s = (struct httpd_state *)state;
228
229 if (s->file.len > uip_mss()) {
230 s->len = uip_mss();
231 } else {
232 s->len = s->file.len;
233 }
234 memcpy(uip_appdata, s->file.data, s->len);
235
236 return s->len;
237 }
238 /*---------------------------------------------------------------------------*/
239 static unsigned short generate_part_of_sd_file(void *state)
240 {
241 struct httpd_state *s = (struct httpd_state *)state;
242
243 int len = fread(uip_appdata, 1, uip_mss(), s->fd);
244 if (len <= 0) {
245 // we need to send something
246 strcpy(uip_appdata, "\r\n");
247 len = 2;
248 s->len = 0;
249 } else {
250 s->len = len;
251 }
252 return len;
253 }
254 /*---------------------------------------------------------------------------*/
255 static
256 PT_THREAD(send_file(struct httpd_state *s))
257 {
258 PSOCK_BEGIN(&s->sout);
259
260 do {
261 PSOCK_GENERATOR_SEND(&s->sout, generate_part_of_file, s);
262 s->file.len -= s->len;
263 s->file.data += s->len;
264 } while (s->file.len > 0);
265
266 PSOCK_END(&s->sout);
267 }
268
269 /*---------------------------------------------------------------------------*/
270 static PT_THREAD(send_sd_file(struct httpd_state *s))
271 {
272 PSOCK_BEGIN(&s->sout);
273
274 do {
275 PSOCK_GENERATOR_SEND(&s->sout, generate_part_of_sd_file, s);
276 } while (s->len > 0);
277
278 fclose(s->fd);
279 s->fd = NULL;
280
281 PSOCK_END(&s->sout);
282 }
283
284 /*---------------------------------------------------------------------------*/
285 static PT_THREAD(send_headers_3(struct httpd_state *s, const char *statushdr, char send_content_type))
286 {
287 char *ptr;
288
289 PSOCK_BEGIN(&s->sout);
290
291 PSOCK_SEND_STR(&s->sout, statushdr);
292 PSOCK_SEND_STR(&s->sout, http_header_all);
293
294 if (send_content_type) {
295 ptr = strrchr(s->filename, ISO_period);
296 if (ptr == NULL) {
297 PSOCK_SEND_STR(&s->sout, http_content_type_plain); // http_content_type_binary);
298 } else if (strncmp(http_html, ptr, 5) == 0) {
299 PSOCK_SEND_STR(&s->sout, http_content_type_html);
300 } else if (strncmp(http_css, ptr, 4) == 0) {
301 PSOCK_SEND_STR(&s->sout, http_content_type_css);
302 } else if (strncmp(http_png, ptr, 4) == 0) {
303 PSOCK_SEND_STR(&s->sout, http_content_type_png);
304 } else if (strncmp(http_gif, ptr, 4) == 0) {
305 PSOCK_SEND_STR(&s->sout, http_content_type_gif);
306 } else if (strncmp(http_jpg, ptr, 4) == 0) {
307 PSOCK_SEND_STR(&s->sout, http_content_type_jpg);
308 } else {
309 PSOCK_SEND_STR(&s->sout, http_content_type_plain);
310 }
311 }
312 PSOCK_END(&s->sout);
313 }
314 static PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr))
315 {
316 return send_headers_3(s, statushdr, 1);
317 }
318 /*---------------------------------------------------------------------------*/
319 static
320 PT_THREAD(handle_output(struct httpd_state *s))
321 {
322 char qstr[132];
323 PT_BEGIN(&s->outputpt);
324
325 if (s->method == OPTIONS) {
326 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_preflight));
327 PSOCK_SEND_STR(&s->sout, "OK\r\n");
328 }
329 else if (s->method == POST) {
330 if (strcmp(s->filename, "/command") == 0) {
331 DEBUG_PRINTF("Executed command post\n");
332 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_200));
333 // send response as we get it
334 PT_WAIT_THREAD(&s->outputpt, send_command_response(s));
335
336 } else if (strcmp(s->filename, "/command_silent") == 0) {
337 DEBUG_PRINTF("Executed silent command post\n");
338 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_200));
339
340 } else if (strcmp(s->filename, "/upload") == 0) {
341 DEBUG_PRINTF("upload output: %d\n", s->uploadok);
342 if (s->uploadok == 0) {
343 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_503));
344 PSOCK_SEND_STR(&s->sout, "FAILED\r\n");
345 } else {
346 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_200));
347 PSOCK_SEND_STR(&s->sout, "OK\r\n");
348 }
349
350 } else {
351 DEBUG_PRINTF("Unknown POST: %s\n", s->filename);
352 httpd_fs_open(http_404_html, &s->file);
353 strcpy(s->filename, http_404_html);
354 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_404));
355 PT_WAIT_THREAD(&s->outputpt, send_file(s));
356 }
357
358 } else {
359 // Presume method GET
360
361 if (strcmp(s->filename, "/query") == 0) { // query short cut
362 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_200));
363 strncpy(qstr, get_query_string(), sizeof(qstr) - 1);
364 PSOCK_SEND_STR(&s->sout, qstr);
365
366 } else if (!fs_open(s)) { // Note this has the side effect of opening the file
367 DEBUG_PRINTF("404 file not found\n");
368 httpd_fs_open(http_404_html, &s->file);
369 strcpy(s->filename, http_404_html);
370 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_404));
371 PT_WAIT_THREAD(&s->outputpt, send_file(s));
372
373 } else if (s->cache_page) {
374 if (s->fd != NULL) {
375 // if it was an sd file then we need to close it
376 fclose(s->fd);
377 s->fd = NULL;
378 }
379 // tell it it has not changed
380 DEBUG_PRINTF("304 Not Modified\n");
381 PT_WAIT_THREAD(&s->outputpt, send_headers_3(s, http_header_304, 0));
382
383 } else {
384 DEBUG_PRINTF("sending file %s\n", s->filename);
385 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_200));
386 if (s->fd != NULL) {
387 // send from sd card
388 PT_WAIT_THREAD(&s->outputpt, send_sd_file(s));
389
390 } else {
391 // send from FLASH
392 PT_WAIT_THREAD(&s->outputpt, send_file(s));
393 }
394 }
395 }
396
397 PSOCK_CLOSE(&s->sout);
398 PT_END(&s->outputpt);
399 }
400
401 /*---------------------------------------------------------------------------*/
402 // this forces us to yield every other call as we read all data everytime
403 static char has_newdata(struct httpd_state *s)
404 {
405 if (s->upload_state == 1) {
406 /* All data in uip_appdata buffer already consumed. */
407 s->upload_state = 0;
408 return 0;
409 } else if (uip_newdata()) {
410 /* There is new data that has not been consumed. */
411 return 1;
412 } else {
413 /* There is no new data. */
414 return 0;
415 }
416 }
417
418 /*
419 * handle the uploaded data, as there may be part of that buffer still in the last packet buffer
420 * write that first from the buf/len parameters
421 */
422 static PT_THREAD(handle_uploaded_data(struct httpd_state *s, uint8_t *buf, int len))
423 {
424 PT_BEGIN(&s->inputpt);
425
426 DEBUG_PRINTF("Uploading file: %s, %d\n", s->upload_name, s->content_length);
427
428 // The body is the raw data to be stored to the file
429 if (!open_file(s->upload_name)) {
430 DEBUG_PRINTF("failed to open file\n");
431 s->uploadok = 0;
432 PT_EXIT(&s->inputpt);
433 }
434
435 DEBUG_PRINTF("opened file: %s\n", s->upload_name);
436
437 if (len > 0) {
438 // write the first part of the buffer
439 if (!save_file(buf, len)) {
440 DEBUG_PRINTF("initial write failed\n");
441 s->uploadok = 0;
442 PT_EXIT(&s->inputpt);
443 }
444 s->content_length -= len;
445 }
446
447 s->upload_state = 1; // first time through we need to yield to get new data
448
449 // save the entire input buffer
450 while (s->content_length > 0) {
451 PT_WAIT_UNTIL(&s->inputpt, has_newdata(s));
452 s->upload_state = 1;
453
454 u8_t *readptr = (u8_t *)uip_appdata;
455 int readlen = uip_datalen();
456 //DEBUG_PRINTF("read %d bytes of data\n", readlen);
457
458 if (readlen > 0) {
459 if (!save_file(readptr, readlen)) {
460 DEBUG_PRINTF("write failed\n");
461 s->uploadok = 0;
462 PT_EXIT(&s->inputpt);
463 }
464 s->content_length -= readlen;
465 }
466 }
467
468 close_file();
469 s->uploadok = 1;
470 DEBUG_PRINTF("finished upload\n");
471
472 PT_END(&s->inputpt);
473 }
474 /*---------------------------------------------------------------------------*/
475 static
476 PT_THREAD(handle_input(struct httpd_state *s))
477 {
478 PSOCK_BEGIN(&s->sin);
479
480 PSOCK_READTO(&s->sin, ISO_space);
481
482 if (strncmp(s->inputbuf, http_get, 3) == 0) {
483 s->method = GET;
484 } else if (strncmp(s->inputbuf, http_post, 4) == 0) {
485 s->method = POST;
486 } else if (strncmp(s->inputbuf, http_options, 7) == 0) {
487 s->method = OPTIONS;
488 } else {
489 DEBUG_PRINTF("Unexpected method: %s\n", s->inputbuf);
490 PSOCK_CLOSE_EXIT(&s->sin);
491 }
492
493 DEBUG_PRINTF("Method: %s\n", s->method == POST ? "POST" : (s->method == GET ? "GET" : "OPTIONS"));
494
495 PSOCK_READTO(&s->sin, ISO_space);
496
497 if (s->inputbuf[0] != ISO_slash) {
498 PSOCK_CLOSE_EXIT(&s->sin);
499 }
500
501 if (s->inputbuf[1] == ISO_space) {
502 strncpy(s->filename, http_index_html, sizeof(s->filename));
503 } else {
504 s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
505 strncpy(s->filename, &s->inputbuf[0], sizeof(s->filename));
506 }
507
508 DEBUG_PRINTF("filename: %s\n", s->filename);
509
510 /* httpd_log_file(uip_conn->ripaddr, s->filename);*/
511
512 s->state = STATE_HEADERS;
513 s->content_length = 0;
514 s->cache_page = 0;
515 while (1) {
516 if (s->state == STATE_HEADERS) {
517 // read the headers of the request
518 PSOCK_READTO(&s->sin, ISO_nl);
519 s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
520 if (s->inputbuf[0] == '\r') {
521 DEBUG_PRINTF("end of headers\n");
522 if (s->method == OPTIONS) {
523 s->state = STATE_OUTPUT;
524 break;
525 } else if (s->method == GET) {
526 s->state = STATE_OUTPUT;
527 break;
528 } else if (s->method == POST) {
529 if (strcmp(s->filename, "/upload") == 0) {
530 s->state = STATE_UPLOAD;
531 } else {
532 s->state = STATE_BODY;
533 }
534 }
535 } else {
536 DEBUG_PRINTF("reading header: %s\n", s->inputbuf);
537 // handle headers here
538 if (strncmp(s->inputbuf, http_content_length, sizeof(http_content_length) - 1) == 0) {
539 s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
540 s->content_length = atoi(&s->inputbuf[sizeof(http_content_length) - 1]);
541 DEBUG_PRINTF("Content length= %s, %d\n", &s->inputbuf[sizeof(http_content_length) - 1], s->content_length);
542
543 } else if (strncmp(s->inputbuf, "X-Filename: ", 11) == 0) {
544 s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
545 strncpy(s->upload_name, &s->inputbuf[12], sizeof(s->upload_name) - 1);
546 DEBUG_PRINTF("Upload name= %s\n", s->upload_name);
547
548 } else if (strncmp(s->inputbuf, http_cache_control, sizeof(http_cache_control) - 1) == 0) {
549 s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
550 s->cache_page = strncmp(http_no_cache, &s->inputbuf[sizeof(http_cache_control) - 1], sizeof(http_no_cache) - 1) != 0;
551 DEBUG_PRINTF("cache page= %d\n", s->cache_page);
552 }
553 }
554
555 } else if (s->state == STATE_BODY) {
556 if (s->method == POST && strcmp(s->filename, "/command") == 0) {
557 // create a callback stream and fifo for the results as it is a command
558 create_callback_stream(s);
559
560 } else if (s->method == POST && strcmp(s->filename, "/command_silent") == 0) {
561 // stick the command on the command queue specifying null output stream
562 s->pstream = NULL;
563
564 } else { // unknown POST
565 DEBUG_PRINTF("Unknown Post URL: %s\n", s->filename);
566 s->state = STATE_OUTPUT;
567 break;
568 }
569 s->command_count= 0;
570 // read the Body of the request, each line is a command
571 if (s->content_length > 0) {
572 DEBUG_PRINTF("start reading body %d...\n", s->content_length);
573 while (s->content_length > 2) {
574 PSOCK_READTO(&s->sin, ISO_nl);
575 s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
576 s->content_length -= PSOCK_DATALEN(&s->sin);
577 // stick the command on the command queue, with this connections stream output
578 DEBUG_PRINTF("Adding command: %s, left: %d\n", s->inputbuf, s->content_length);
579 network_add_command(s->inputbuf, s->pstream);
580 s->command_count++; // count number of command lines we submit
581 }
582 DEBUG_PRINTF("Read body done\n");
583 s->state = STATE_OUTPUT;
584
585 } else {
586 s->state = STATE_OUTPUT;
587 }
588 break;
589
590 } else if (s->state == STATE_UPLOAD) {
591 PSOCK_WAIT_THREAD(&s->sin, handle_uploaded_data(s, PSOCK_GET_START_OF_REST_OF_BUFFER(&s->sin), PSOCK_GET_LENGTH_OF_REST_OF_BUFFER(&s->sin)));
592 PSOCK_MARK_BUFFER_READ(&s->sin);
593 s->state = STATE_OUTPUT;
594 break;
595
596 } else {
597 DEBUG_PRINTF("WTF State: %d", s->state);
598 break;
599 }
600 }
601
602 PSOCK_END(&s->sin);
603 }
604 /*---------------------------------------------------------------------------*/
605 static void
606 handle_connection(struct httpd_state *s)
607 {
608 if (s->state != STATE_OUTPUT) {
609 handle_input(s);
610 }
611 if (s->state == STATE_OUTPUT) {
612 handle_output(s);
613 }
614 }
615 /*---------------------------------------------------------------------------*/
616 void
617 httpd_appcall(void)
618 {
619 struct httpd_state *s = (struct httpd_state *)(uip_conn->appstate);
620
621 if (uip_connected()) {
622 s = malloc(sizeof(struct httpd_state));
623 if (s == NULL) {
624 DEBUG_PRINTF("Connection: Out of memory\n");
625 uip_abort();
626 return;
627 }
628 uip_conn->appstate = s;
629 DEBUG_PRINTF("Connection: %d.%d.%d.%d:%d\n",
630 uip_ipaddr1(uip_conn->ripaddr), uip_ipaddr2(uip_conn->ripaddr),
631 uip_ipaddr3(uip_conn->ripaddr), uip_ipaddr4(uip_conn->ripaddr),
632 HTONS(uip_conn->rport));
633
634 PSOCK_INIT(&s->sin, s->inputbuf, sizeof(s->inputbuf) - 1);
635 PSOCK_INIT(&s->sout, s->inputbuf, sizeof(s->inputbuf) - 1);
636 PT_INIT(&s->outputpt);
637 PT_INIT(&s->inputpt);
638 s->state = STATE_WAITING;
639 /* timer_set(&s->timer, CLOCK_SECOND * 100);*/
640 s->timer = 0;
641 s->fd = NULL;
642 s->strbuf = NULL;
643 s->fifo = NULL;
644 s->pstream = NULL;
645 }
646
647 if (s == NULL) {
648 DEBUG_PRINTF("ERROR no state context: %d\n", uip_flags);
649 uip_abort();
650 return;
651 }
652
653 // check for timeout on connection here so we can cleanup if we abort
654 if (uip_poll()) {
655 ++s->timer;
656 if (s->timer >= 20 * 2) { // we have a 0.5 second poll and we want 20 second timeout
657 DEBUG_PRINTF("Timer expired, aborting\n");
658 uip_abort();
659 }
660 } else {
661 s->timer = 0;
662 }
663
664 if (uip_closed() || uip_aborted() || uip_timedout()) {
665 DEBUG_PRINTF("Closing connection: %d\n", HTONS(uip_conn->rport));
666 if (s->fd != NULL) fclose(fd); // clean up
667 if (s->strbuf != NULL) free(s->strbuf);
668 if (s->pstream != NULL) {
669 // free these if they were allocated
670 delete_fifo(s->fifo);
671 delete_callback_stream(s->pstream); // this will mark it as closed and will get deleted when no longer needed
672 }
673 free(s) ;
674 uip_conn->appstate = NULL;
675
676 } else {
677 handle_connection(s);
678 }
679 }
680
681 /*---------------------------------------------------------------------------*/
682 /**
683 * \brief Initialize the web server
684 *
685 * This function initializes the web server and should be
686 * called at system boot-up.
687 */
688 void httpd_init(void)
689 {
690 uip_listen(HTONS(80));
691 }
692 /*---------------------------------------------------------------------------*/
693 /** @} */