1 /** 2 * \addtogroup apps 3 * @{ 4 */ 5 6 /** 7 * \defgroup httpd Web server 8 * @{ 9 * The uIP web server is a very simplistic implementation of an HTTP 10 * server. It can serve web pages and files from a read-only ROM 11 * filesystem, and provides a very small scripting language. 12 13 */ 14 15 /** 16 * \file 17 * Web server 18 * \author 19 * Adam Dunkels <[email protected]> 20 */ 21 22 23 /* 24 * Copyright (c) 2004, Adam Dunkels. 25 * All rights reserved. 26 * 27 * Redistribution and use in source and binary forms, with or without 28 * modification, are permitted provided that the following conditions 29 * are met: 30 * 1. Redistributions of source code must retain the above copyright 31 * notice, this list of conditions and the following disclaimer. 32 * 2. Redistributions in binary form must reproduce the above copyright 33 * notice, this list of conditions and the following disclaimer in the 34 * documentation and/or other materials provided with the distribution. 35 * 3. Neither the name of the Institute nor the names of its contributors 36 * may be used to endorse or promote products derived from this software 37 * without specific prior written permission. 38 * 39 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 40 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 42 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 43 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 44 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 45 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 47 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 48 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 49 * SUCH DAMAGE. 50 * 51 * This file is part of the uIP TCP/IP stack. 52 * 53 * Author: Adam Dunkels <[email protected]> 54 * 55 * $Id: httpd.c,v 1.2 2006/06/11 21:46:38 adam Exp $ 56 */ 57 58 #include "uip.h" 59 #include "httpd.h" 60 #include "httpd-fs.h" 61 #include "httpd-cgi.h" 62 #include "http-strings.h" 63 64 #include <string.h> 65 66 #define STATE_WAITING 0 67 #define STATE_OUTPUT 1 68 69 #define ISO_nl 0x0a 70 #define ISO_space 0x20 71 #define ISO_bang 0x21 72 #define ISO_percent 0x25 73 #define ISO_period 0x2e 74 #define ISO_slash 0x2f 75 #define ISO_colon 0x3a 76 77 78 /*---------------------------------------------------------------------------*/ 79 static unsigned short 80 generate_part_of_file(void *state) 81 { 82 struct httpd_state *s = (struct httpd_state *)state; 83 84 if(s->file.len > uip_mss()) { 85 s->len = uip_mss(); 86 } else { 87 s->len = s->file.len; 88 } 89 memcpy(uip_appdata, s->file.data, s->len); 90 91 return s->len; 92 } 93 /*---------------------------------------------------------------------------*/ 94 static 95 PT_THREAD(send_file(struct httpd_state *s)) 96 { 97 PSOCK_BEGIN(&s->sout); 98 99 do { 100 PSOCK_GENERATOR_SEND(&s->sout, generate_part_of_file, s); 101 s->file.len -= s->len; 102 s->file.data += s->len; 103 } while(s->file.len > 0); 104 105 PSOCK_END(&s->sout); 106 } 107 /*---------------------------------------------------------------------------*/ 108 static 109 PT_THREAD(send_part_of_file(struct httpd_state *s)) 110 { 111 PSOCK_BEGIN(&s->sout); 112 113 PSOCK_SEND(&s->sout, s->file.data, s->len); 114 115 PSOCK_END(&s->sout); 116 } 117 /*---------------------------------------------------------------------------*/ 118 static void 119 next_scriptstate(struct httpd_state *s) 120 { 121 char *p; 122 p = strchr(s->scriptptr, ISO_nl) + 1; 123 s->scriptlen -= (unsigned short)(p - s->scriptptr); 124 s->scriptptr = p; 125 } 126 /*---------------------------------------------------------------------------*/ 127 static 128 PT_THREAD(handle_script(struct httpd_state *s)) 129 { 130 char *ptr; 131 132 PT_BEGIN(&s->scriptpt); 133 134 135 while(s->file.len > 0) { 136 137 /* Check if we should start executing a script. */ 138 if(*s->file.data == ISO_percent && 139 *(s->file.data + 1) == ISO_bang) { 140 s->scriptptr = s->file.data + 3; 141 s->scriptlen = s->file.len - 3; 142 if(*(s->scriptptr - 1) == ISO_colon) { 143 httpd_fs_open(s->scriptptr + 1, &s->file); 144 PT_WAIT_THREAD(&s->scriptpt, send_file(s)); 145 } else { 146 PT_WAIT_THREAD(&s->scriptpt, 147 httpd_cgi(s->scriptptr)(s, s->scriptptr)); 148 } 149 next_scriptstate(s); 150 151 /* The script is over, so we reset the pointers and continue 152 sending the rest of the file. */ 153 s->file.data = s->scriptptr; 154 s->file.len = s->scriptlen; 155 } else { 156 /* See if we find the start of script marker in the block of HTML 157 to be sent. */ 158 159 if(s->file.len > uip_mss()) { 160 s->len = uip_mss(); 161 } else { 162 s->len = s->file.len; 163 } 164 165 if(*s->file.data == ISO_percent) { 166 ptr = strchr(s->file.data + 1, ISO_percent); 167 } else { 168 ptr = strchr(s->file.data, ISO_percent); 169 } 170 if(ptr != NULL && 171 ptr != s->file.data) { 172 s->len = (int)(ptr - s->file.data); 173 if(s->len >= uip_mss()) { 174 s->len = uip_mss(); 175 } 176 } 177 PT_WAIT_THREAD(&s->scriptpt, send_part_of_file(s)); 178 s->file.data += s->len; 179 s->file.len -= s->len; 180 181 } 182 } 183 184 PT_END(&s->scriptpt); 185 } 186 /*---------------------------------------------------------------------------*/ 187 static 188 PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr)) 189 { 190 char *ptr; 191 192 PSOCK_BEGIN(&s->sout); 193 194 PSOCK_SEND_STR(&s->sout, statushdr); 195 196 ptr = strrchr(s->filename, ISO_period); 197 if(ptr == NULL) { 198 PSOCK_SEND_STR(&s->sout, http_content_type_binary); 199 } else if(strncmp(http_html, ptr, 5) == 0 || 200 strncmp(http_shtml, ptr, 6) == 0) { 201 PSOCK_SEND_STR(&s->sout, http_content_type_html); 202 } else if(strncmp(http_css, ptr, 4) == 0) { 203 PSOCK_SEND_STR(&s->sout, http_content_type_css); 204 } else if(strncmp(http_png, ptr, 4) == 0) { 205 PSOCK_SEND_STR(&s->sout, http_content_type_png); 206 } else if(strncmp(http_gif, ptr, 4) == 0) { 207 PSOCK_SEND_STR(&s->sout, http_content_type_gif); 208 } else if(strncmp(http_jpg, ptr, 4) == 0) { 209 PSOCK_SEND_STR(&s->sout, http_content_type_jpg); 210 } else { 211 PSOCK_SEND_STR(&s->sout, http_content_type_plain); 212 } 213 PSOCK_END(&s->sout); 214 } 215 /*---------------------------------------------------------------------------*/ 216 static 217 PT_THREAD(handle_output(struct httpd_state *s)) 218 { 219 char *ptr; 220 221 PT_BEGIN(&s->outputpt); 222 223 if(!httpd_fs_open(s->filename, &s->file)) { 224 httpd_fs_open(http_404_html, &s->file); 225 strcpy(s->filename, http_404_html); 226 PT_WAIT_THREAD(&s->outputpt, 227 send_headers(s, 228 http_header_404)); 229 PT_WAIT_THREAD(&s->outputpt, 230 send_file(s)); 231 } else { 232 PT_WAIT_THREAD(&s->outputpt, 233 send_headers(s, 234 http_header_200)); 235 ptr = strchr(s->filename, ISO_period); 236 if(ptr != NULL && strncmp(ptr, http_shtml, 6) == 0) { 237 PT_INIT(&s->scriptpt); 238 PT_WAIT_THREAD(&s->outputpt, handle_script(s)); 239 } else { 240 PT_WAIT_THREAD(&s->outputpt, 241 send_file(s)); 242 } 243 } 244 PSOCK_CLOSE(&s->sout); 245 PT_END(&s->outputpt); 246 } 247 /*---------------------------------------------------------------------------*/ 248 static 249 PT_THREAD(handle_input(struct httpd_state *s)) 250 { 251 PSOCK_BEGIN(&s->sin); 252 253 PSOCK_READTO(&s->sin, ISO_space); 254 255 256 if(strncmp(s->inputbuf, http_get, 4) != 0) { 257 PSOCK_CLOSE_EXIT(&s->sin); 258 } 259 PSOCK_READTO(&s->sin, ISO_space); 260 261 if(s->inputbuf[0] != ISO_slash) { 262 PSOCK_CLOSE_EXIT(&s->sin); 263 } 264 265 if(s->inputbuf[1] == ISO_space) { 266 strncpy(s->filename, http_index_html, sizeof(s->filename)); 267 } else { 268 s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0; 269 strncpy(s->filename, &s->inputbuf[0], sizeof(s->filename)); 270 } 271 272 /* httpd_log_file(uip_conn->ripaddr, s->filename);*/ 273 274 s->state = STATE_OUTPUT; 275 276 while(1) { 277 PSOCK_READTO(&s->sin, ISO_nl); 278 279 if(strncmp(s->inputbuf, http_referer, 8) == 0) { 280 s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0; 281 /* httpd_log(&s->inputbuf[9]);*/ 282 } 283 } 284 285 PSOCK_END(&s->sin); 286 } 287 /*---------------------------------------------------------------------------*/ 288 static void 289 handle_connection(struct httpd_state *s) 290 { 291 handle_input(s); 292 if(s->state == STATE_OUTPUT) { 293 handle_output(s); 294 } 295 } 296 /*---------------------------------------------------------------------------*/ 297 void 298 httpd_appcall(void) 299 { 300 struct httpd_state *s = (struct httpd_state *)&(uip_conn->appstate); 301 302 if(uip_closed() || uip_aborted() || uip_timedout()) { 303 } else if(uip_connected()) { 304 PSOCK_INIT(&s->sin, s->inputbuf, sizeof(s->inputbuf) - 1); 305 PSOCK_INIT(&s->sout, s->inputbuf, sizeof(s->inputbuf) - 1); 306 PT_INIT(&s->outputpt); 307 s->state = STATE_WAITING; 308 /* timer_set(&s->timer, CLOCK_SECOND * 100);*/ 309 s->timer = 0; 310 handle_connection(s); 311 } else if(s != NULL) { 312 if(uip_poll()) { 313 ++s->timer; 314 if(s->timer >= 20) { 315 uip_abort(); 316 } 317 } else { 318 s->timer = 0; 319 } 320 handle_connection(s); 321 } else { 322 uip_abort(); 323 } 324 } 325 /*---------------------------------------------------------------------------*/ 326 /** 327 * \brief Initialize the web server 328 * 329 * This function initializes the web server and should be 330 * called at system boot-up. 331 */ 332 void 333 httpd_init(void) 334 { 335 uip_listen(HTONS(80)); 336 } 337 /*---------------------------------------------------------------------------*/ 338 /** @} */ 339