Contiki 2.6
|
00001 /* 00002 * Copyright (c) 2004, Adam Dunkels. 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions 00007 * are met: 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the Institute nor the names of its contributors 00014 * may be used to endorse or promote products derived from this software 00015 * without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 00018 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 00021 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00022 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00023 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00024 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00025 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00026 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00027 * SUCH DAMAGE. 00028 * 00029 * This file is part of the Contiki operating system. 00030 * 00031 * Author: Adam Dunkels <adam@sics.se> 00032 * 00033 * $Id: httpd.c,v 1.2 2010/10/19 18:29:05 adamdunkels Exp $ 00034 */ 00035 00036 #include <string.h> 00037 00038 #include "contiki-net.h" 00039 00040 #include "webserver-nogui.h" 00041 #include "httpd-fs.h" 00042 #include "httpd-cgi.h" 00043 #include "http-strings.h" 00044 00045 #include "httpd.h" 00046 #include "ctk/libconio_arch-small.h" 00047 00048 #define STATE_WAITING 0 00049 #define STATE_OUTPUT 1 00050 00051 #define SEND_STRING(s, str) PSOCK_SEND(s, str, (unsigned int)strlen(str)) 00052 MEMB(conns, struct httpd_state, 4); 00053 00054 #define ISO_nl 0x0a 00055 #define ISO_space 0x20 00056 #define ISO_bang 0x21 00057 #define ISO_percent 0x25 00058 #define ISO_period 0x2e 00059 #define ISO_slash 0x2f 00060 #define ISO_colon 0x3a 00061 00062 /*---------------------------------------------------------------------------*/ 00063 static unsigned short 00064 generate(void *state) 00065 { 00066 struct httpd_state *s = (struct httpd_state *)state; 00067 00068 if(s->file.len > uip_mss()) { 00069 s->len = uip_mss(); 00070 } else { 00071 s->len = s->file.len; 00072 } 00073 memcpy(uip_appdata, s->file.data, s->len); 00074 00075 return s->len; 00076 } 00077 /*---------------------------------------------------------------------------*/ 00078 static 00079 PT_THREAD(send_file(struct httpd_state *s)) 00080 { 00081 PSOCK_BEGIN(&s->sout); 00082 00083 do { 00084 PSOCK_GENERATOR_SEND(&s->sout, generate, s); 00085 s->file.len -= s->len; 00086 s->file.data += s->len; 00087 } while(s->file.len > 0); 00088 00089 PSOCK_END(&s->sout); 00090 } 00091 /*---------------------------------------------------------------------------*/ 00092 static 00093 PT_THREAD(send_part_of_file(struct httpd_state *s)) 00094 { 00095 PSOCK_BEGIN(&s->sout); 00096 00097 PSOCK_SEND(&s->sout, s->file.data, s->len); 00098 00099 PSOCK_END(&s->sout); 00100 } 00101 /*---------------------------------------------------------------------------*/ 00102 #if HTTPD_CONF_SCRIPT 00103 static void 00104 next_scriptstate(struct httpd_state *s) 00105 { 00106 char *p; 00107 00108 if((p = strchr(s->scriptptr, ISO_nl)) != NULL) { 00109 p += 1; 00110 s->scriptlen -= (unsigned short)(p - s->scriptptr); 00111 s->scriptptr = p; 00112 } else { 00113 s->scriptlen = 0; 00114 } 00115 /* char *p; 00116 p = strchr(s->scriptptr, ISO_nl) + 1; 00117 s->scriptlen -= (unsigned short)(p - s->scriptptr); 00118 s->scriptptr = p;*/ 00119 } 00120 /*---------------------------------------------------------------------------*/ 00121 static 00122 PT_THREAD(handle_script(struct httpd_state *s)) 00123 { 00124 char *ptr; 00125 00126 PT_BEGIN(&s->scriptpt); 00127 00128 while(s->file.len > 0) { 00129 00130 /* Check if we should start executing a script. */ 00131 if(*s->file.data == ISO_percent && 00132 *(s->file.data + 1) == ISO_bang) { 00133 s->scriptptr = s->file.data + 3; 00134 s->scriptlen = s->file.len - 3; 00135 if(*(s->scriptptr - 1) == ISO_colon) { 00136 httpd_fs_open(s->scriptptr + 1, &s->file); 00137 PT_WAIT_THREAD(&s->scriptpt, send_file(s)); 00138 #if HTTPD_CONF_CGI 00139 } else { 00140 PT_WAIT_THREAD(&s->scriptpt, 00141 httpd_cgi(s->scriptptr)(s, s->scriptptr)); 00142 #endif /* HTTPD_CONF_CGI */ 00143 } 00144 next_scriptstate(s); 00145 00146 /* The script is over, so we reset the pointers and continue 00147 sending the rest of the file. */ 00148 s->file.data = s->scriptptr; 00149 s->file.len = s->scriptlen; 00150 } else { 00151 /* See if we find the start of script marker in the block of HTML 00152 to be sent. */ 00153 00154 if(s->file.len > uip_mss()) { 00155 s->len = uip_mss(); 00156 } else { 00157 s->len = s->file.len; 00158 } 00159 00160 if(*s->file.data == ISO_percent) { 00161 ptr = strchr(s->file.data + 1, ISO_percent); 00162 } else { 00163 ptr = strchr(s->file.data, ISO_percent); 00164 } 00165 if(ptr != NULL && 00166 ptr != s->file.data) { 00167 s->len = (int)(ptr - s->file.data); 00168 if(s->len >= uip_mss()) { 00169 s->len = uip_mss(); 00170 } 00171 } 00172 PT_WAIT_THREAD(&s->scriptpt, send_part_of_file(s)); 00173 s->file.data += s->len; 00174 s->file.len -= s->len; 00175 } 00176 } 00177 00178 PT_END(&s->scriptpt); 00179 } 00180 #endif /* HTTPD_CONF_SCRIPT */ 00181 /*---------------------------------------------------------------------------*/ 00182 static 00183 PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr)) 00184 { 00185 char *ptr; 00186 00187 PSOCK_BEGIN(&s->sout); 00188 00189 SEND_STRING(&s->sout, statushdr); 00190 00191 ptr = strrchr(s->filename, ISO_period); 00192 if(ptr == NULL) { 00193 SEND_STRING(&s->sout, http_content_type_binary); 00194 } else if(strncmp(http_html, ptr, 5) == 0 || 00195 strncmp(http_shtml, ptr, 6) == 0) { 00196 SEND_STRING(&s->sout, http_content_type_html); 00197 #if 0 00198 } else if(strncmp(http_css, ptr, 4) == 0) { 00199 SEND_STRING(&s->sout, http_content_type_css); 00200 } else if(strncmp(http_png, ptr, 4) == 0) { 00201 SEND_STRING(&s->sout, http_content_type_png); 00202 } else if(strncmp(http_gif, ptr, 4) == 0) { 00203 SEND_STRING(&s->sout, http_content_type_gif); 00204 } else if(strncmp(http_jpg, ptr, 4) == 0) { 00205 SEND_STRING(&s->sout, http_content_type_jpg); 00206 #endif 00207 } else { 00208 SEND_STRING(&s->sout, http_content_type_plain); 00209 } 00210 PSOCK_END(&s->sout); 00211 } 00212 /*---------------------------------------------------------------------------*/ 00213 static 00214 PT_THREAD(handle_output(struct httpd_state *s)) 00215 { 00216 char *ptr; 00217 00218 PT_BEGIN(&s->outputpt); 00219 00220 if(!httpd_fs_open(s->filename, &s->file)) { 00221 httpd_fs_open(http_404_html, &s->file); 00222 PT_WAIT_THREAD(&s->outputpt, 00223 send_headers(s, 00224 http_header_404)); 00225 PT_WAIT_THREAD(&s->outputpt, 00226 send_file(s)); 00227 } else { 00228 PT_WAIT_THREAD(&s->outputpt, 00229 send_headers(s, 00230 http_header_200)); 00231 ptr = strchr(s->filename, ISO_period); 00232 #if HTTPD_CONF_SCRIPT 00233 if(ptr != NULL && strncmp(ptr, http_shtml, 6) == 0) { 00234 PT_INIT(&s->scriptpt); 00235 PT_WAIT_THREAD(&s->outputpt, handle_script(s)); 00236 } else { 00237 PT_WAIT_THREAD(&s->outputpt, 00238 send_file(s)); 00239 } 00240 #else /* HTTPD_CONF_SCRIPT */ 00241 PT_WAIT_THREAD(&s->outputpt, 00242 send_file(s)); 00243 #endif /* HTTPD_CONF_SCRIPT */ 00244 } 00245 PSOCK_CLOSE(&s->sout); 00246 PT_END(&s->outputpt); 00247 } 00248 /*---------------------------------------------------------------------------*/ 00249 static 00250 PT_THREAD(handle_input(struct httpd_state *s)) 00251 { 00252 PSOCK_BEGIN(&s->sin); 00253 00254 PSOCK_READTO(&s->sin, ISO_space); 00255 00256 if(strncmp(s->inputbuf, http_get, 4) != 0) { 00257 PSOCK_CLOSE_EXIT(&s->sin); 00258 } 00259 PSOCK_READTO(&s->sin, ISO_space); 00260 00261 if(s->inputbuf[0] != ISO_slash) { 00262 PSOCK_CLOSE_EXIT(&s->sin); 00263 } 00264 00265 if(s->inputbuf[1] == ISO_space) { 00266 strncpy(s->filename, http_index_html, sizeof(s->filename)); 00267 } else { 00268 s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0; 00269 strncpy(s->filename, &s->inputbuf[0], sizeof(s->filename)); 00270 } 00271 00272 libputs_arch(s->filename); 00273 00274 s->state = STATE_OUTPUT; 00275 00276 while(1) { 00277 PSOCK_READTO(&s->sin, ISO_nl); 00278 00279 if(strncmp(s->inputbuf, http_referer, 8) == 0) { 00280 s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0; 00281 } 00282 } 00283 00284 PSOCK_END(&s->sin); 00285 } 00286 /*---------------------------------------------------------------------------*/ 00287 static void 00288 handle_connection(struct httpd_state *s) 00289 { 00290 handle_input(s); 00291 if(s->state == STATE_OUTPUT) { 00292 handle_output(s); 00293 } 00294 } 00295 /*---------------------------------------------------------------------------*/ 00296 void 00297 httpd_appcall(void *state) 00298 { 00299 struct httpd_state *s = (struct httpd_state *)state; 00300 00301 if(uip_closed() || uip_aborted() || uip_timedout()) { 00302 if(s != NULL) { 00303 memb_free(&conns, s); 00304 } 00305 } else if(uip_connected()) { 00306 s = (struct httpd_state *)memb_alloc(&conns); 00307 if(s == NULL) { 00308 uip_abort(); 00309 return; 00310 } 00311 tcp_markconn(uip_conn, s); 00312 PSOCK_INIT(&s->sin, s->inputbuf, sizeof(s->inputbuf) - 1); 00313 PSOCK_INIT(&s->sout, s->inputbuf, sizeof(s->inputbuf) - 1); 00314 PT_INIT(&s->outputpt); 00315 s->state = STATE_WAITING; 00316 /* timer_set(&s->timer, CLOCK_SECOND * 100);*/ 00317 s->timer = 0; 00318 handle_connection(s); 00319 } else if(s != NULL) { 00320 if(uip_poll()) { 00321 ++s->timer; 00322 if(s->timer >= 20) { 00323 uip_abort(); 00324 memb_free(&conns, s); 00325 } 00326 } else { 00327 s->timer = 0; 00328 } 00329 handle_connection(s); 00330 } else { 00331 uip_abort(); 00332 } 00333 } 00334 /*---------------------------------------------------------------------------*/ 00335 void 00336 httpd_init(void) 00337 { 00338 tcp_listen(UIP_HTONS(80)); 00339 memb_init(&conns); 00340 #if HTTPD_CONF_CGI 00341 httpd_cgi_init(); 00342 #endif /* HTTPD_CONF_CGI */ 00343 } 00344 /*---------------------------------------------------------------------------*/