/* * Copyright (c) 2009, 2016 Jeffrey Armstrong * Copyright (c) 2001-2005, Adam Dunkels. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This file is part of the uIP TCP/IP stack. * */ #include "httpd.h" #include "uip.h" #include "httpd-fs.h" #include "http-str.h" #include #include #define STATE_WAITING 0 #define STATE_OUTPUT 1 #define ISO_nl 0x0a #define ISO_space 0x20 #define ISO_bang 0x21 #define ISO_percent 0x25 #define ISO_period 0x2e #define ISO_slash 0x2f #define ISO_colon 0x3a static unsigned short generate_part_of_file(void *state) { struct httpd_state *s = (struct httpd_state *)state; if(s->file.len > uip_mss()) { s->len = uip_mss(); } else { s->len = s->file.len; } fread(uip_appdata,sizeof(char),s->len,s->file.fp); if(s->len >= s->file.len) fclose(s->file.fp); return s->len; } static PT_THREAD(send_file(struct httpd_state *s)) { PSOCK_BEGIN(&s->sout); do { PSOCK_GENERATOR_SEND(&s->sout, generate_part_of_file, s); s->file.len -= s->len; } while(s->file.len > 0); PSOCK_END(&s->sout); } static PT_THREAD(send_part_of_file(struct httpd_state *s)) { PSOCK_BEGIN(&s->sout); PSOCK_SEND(&s->sout, uip_appdata, s->len); PSOCK_END(&s->sout); } static PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr)) { char *ptr; PSOCK_BEGIN(&s->sout); PSOCK_SEND_STR(&s->sout, statushdr); if(s->compressed) PSOCK_SEND_STR(&s->sout, http_content_encode); ptr = strrchr(s->filename, ISO_period); if(ptr == NULL) { PSOCK_SEND_STR(&s->sout, http_content_type_binary); } else if(strncmp(http_html, ptr, 5) == 0 || strncmp(http_shtml, ptr, 6) == 0 || strncmp(http_htm, ptr, 4) == 0 || strncmp(http_hgz, ptr, 4) == 0) { PSOCK_SEND_STR(&s->sout, http_content_type_html); } else if(strncmp(http_css, ptr, 4) == 0 || strncmp(http_cgz, ptr, 4) == 0) { PSOCK_SEND_STR(&s->sout, http_content_type_css); } else if(strncmp(http_png, ptr, 4) == 0) { PSOCK_SEND_STR(&s->sout, http_content_type_png); } else if(strncmp(http_gif, ptr, 4) == 0) { PSOCK_SEND_STR(&s->sout, http_content_type_gif); } else if(strncmp(http_jpg, ptr, 4) == 0) { PSOCK_SEND_STR(&s->sout, http_content_type_jpg); } else if(strncmp(http_rss, ptr, 4) == 0 || strncmp(http_rgz, ptr, 4) == 0) { PSOCK_SEND_STR(&s->sout, http_content_type_rss); } else { PSOCK_SEND_STR(&s->sout, http_content_type_plain); } PSOCK_END(&s->sout); } static PT_THREAD(handle_output(struct httpd_state *s)) { char *ptr; time_t ltime; PT_BEGIN(&s->outputpt); printf("%s requested - ", s->filename); if(s->compressed == 1 && compressed_available(s->filename) == 1) compressed_name(s->filename); else s->compressed = 0; ltime = time(NULL); printf("using %s - %s", s->filename, ctime(<ime)); if(httpd_fs_open(s->filename, &s->file) < 0) { strcpy(s->filename, FILE_404); PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_404)); if(httpd_fs_open(s->filename, &s->file)) PT_WAIT_THREAD(&s->outputpt, send_file(s)); } else { PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_200)); /* ptr = strchr(s->filename, ISO_period); */ PT_WAIT_THREAD(&s->outputpt, send_file(s)); } PSOCK_CLOSE(&s->sout); PT_END(&s->outputpt); } static PT_THREAD(handle_input(struct httpd_state *s)) { int i; PSOCK_BEGIN(&s->sin); PSOCK_READTO(&s->sin, ISO_space); if(strncmp(s->inputbuf, http_get, 4) != 0) { PSOCK_CLOSE_EXIT(&s->sin); } PSOCK_READTO(&s->sin, ISO_space); if(s->inputbuf[0] != ISO_slash) { PSOCK_CLOSE_EXIT(&s->sin); } if(s->inputbuf[1] == ISO_space) { strncpy(s->filename, http_index_html, sizeof(s->filename)); } else { s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0; strncpy(s->filename, &s->inputbuf[0], sizeof(s->filename)); } /* httpd_log_file(uip_conn->ripaddr, s->filename);*/ s->compressed = 0; while(1) { PSOCK_READTO(&s->sin, ISO_nl); if(strncmp(s->inputbuf, http_referer, 8) == 0) { s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0; /* httpd_log(&s->inputbuf[9]);*/ } else if(strncmp(s->inputbuf, http_accept_encode, 17) == 0) { i = 17; while(s->inputbuf[i] != ISO_nl) { if(strncmp(&s->inputbuf[i], http_gzip, 4) == 0) { s->compressed = 1; break; } i++; } } else if(PSOCK_DATALEN(&s->sin) < 3) { break; } } s->state = STATE_OUTPUT; PSOCK_END(&s->sin); } static void handle_connection(struct httpd_state *s) { handle_input(s); if(s->state == STATE_OUTPUT) { handle_output(s); } } void httpd_appcall(void) { struct httpd_state *s = (struct httpd_state *)&(uip_conn->appstate); if(uip_closed() || uip_aborted() || uip_timedout()) { } else if(uip_connected()) { PSOCK_INIT(&s->sin, s->inputbuf, sizeof(s->inputbuf) - 1); PSOCK_INIT(&s->sout, s->inputbuf, sizeof(s->inputbuf) - 1); PT_INIT(&s->outputpt); s->state = STATE_WAITING; /* timer_set(&s->timer, CLOCK_SECOND * 100);*/ s->timer = 0; handle_connection(s); } else if(s != NULL) { if(uip_poll()) { ++s->timer; if(s->timer >= 20) { uip_abort(); } } else { s->timer = 0; } handle_connection(s); } else { uip_abort(); } } void httpd_init(void) { uip_listen(HTONS(80)); }