# apps/webserver/httpd.c

Go to the documentation of this file.

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