uIP 1.0 based webserver for LPC1114 + ENC28J60

Dependencies:   mbed TMP102

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers httpd.cpp Source File

httpd.cpp

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 extern "C" {
00059     #include "uip.h"
00060     #include "httpd.h"
00061 }
00062 //#include "httpd-fs.h"
00063 #include "httpd-cgi.h"
00064 #include "http-strings.h"
00065 
00066 #include <string.h>
00067 
00068 #define STATE_WAITING 0
00069 #define STATE_OUTPUT  1
00070 
00071 #define ISO_nl      0x0a
00072 #define ISO_space   0x20
00073 #define ISO_bang    0x21
00074 #define ISO_percent 0x25
00075 #define ISO_period  0x2e
00076 #define ISO_slash   0x2f
00077 #define ISO_colon   0x3a
00078 
00079 
00080 /*---------------------------------------------------------------------------*/
00081 static unsigned short
00082 generate_part_of_file(void *state)
00083 {
00084   struct httpd_state *s = (struct httpd_state *)state;
00085 
00086   if(s->file.len > uip_mss()) {
00087     s->len = uip_mss();
00088   } else {
00089     s->len = s->file.len;
00090   }
00091   memcpy(uip_appdata, s->file.data, s->len);
00092   
00093   return s->len;
00094 }
00095 /*---------------------------------------------------------------------------*/
00096 static
00097 PT_THREAD(send_file(struct httpd_state *s))
00098 {
00099   PSOCK_BEGIN(&s->sout);
00100   
00101   do {
00102     PSOCK_GENERATOR_SEND(&s->sout, generate_part_of_file, s);
00103     s->file.len -= s->len;
00104     s->file.data += s->len;
00105   } while(s->file.len > 0);
00106       
00107   PSOCK_END(&s->sout);
00108 }
00109 /*---------------------------------------------------------------------------*/
00110 static
00111 PT_THREAD(send_part_of_file(struct httpd_state *s))
00112 {
00113   PSOCK_BEGIN(&s->sout);
00114 
00115   PSOCK_SEND(&s->sout, s->file.data, s->len);
00116   
00117   PSOCK_END(&s->sout);
00118 }
00119 /*---------------------------------------------------------------------------*/
00120 static void
00121 next_scriptstate(struct httpd_state *s)
00122 {
00123   char *p;
00124 
00125   if((p = strchr(s->scriptptr, ISO_nl)) != NULL) {
00126     p += 1;
00127     s->scriptlen -= (unsigned short)(p - s->scriptptr);
00128     s->scriptptr = p;
00129   } else {
00130     s->scriptlen = 0;
00131   }
00132 }
00133 /*---------------------------------------------------------------------------*/
00134 static
00135 PT_THREAD(handle_script(struct httpd_state *s))
00136 {
00137   char *ptr;
00138   
00139   PT_BEGIN(&s->scriptpt);
00140 
00141 
00142   while(s->file.len > 0) {
00143 
00144     /* Check if we should start executing a script. */
00145     if(*s->file.data == ISO_percent &&
00146        *(s->file.data + 1) == ISO_bang) {
00147       s->scriptptr = s->file.data + 3;
00148       s->scriptlen = s->file.len - 3;
00149       if(*(s->scriptptr - 1) == ISO_colon) {
00150         httpd_fs_open(s->scriptptr + 1, &s->file);
00151         PT_WAIT_THREAD(&s->scriptpt, send_file(s));
00152       } else {
00153         PT_WAIT_THREAD(&s->scriptpt,
00154                        httpd_cgi(s->scriptptr)(s, s->scriptptr));
00155       }
00156       next_scriptstate(s);
00157       
00158       /* The script is over, so we reset the pointers and continue
00159          sending the rest of the file. */
00160       s->file.data = s->scriptptr;
00161       s->file.len = s->scriptlen;
00162     } else {
00163       /* See if we find the start of script marker in the block of HTML
00164          to be sent. */
00165 
00166       if(s->file.len > uip_mss()) {
00167         s->len = uip_mss();
00168       } else {
00169         s->len = s->file.len;
00170       }
00171 
00172       if(*s->file.data == ISO_percent) {
00173         ptr = strchr(s->file.data + 1, ISO_percent);
00174       } else {
00175         ptr = strchr(s->file.data, ISO_percent);
00176       }
00177       if(ptr != NULL &&
00178          ptr != s->file.data) {
00179         s->len = (int)(ptr - s->file.data);
00180         if(s->len >= uip_mss()) {
00181           s->len = uip_mss();
00182         }
00183       }
00184       PT_WAIT_THREAD(&s->scriptpt, send_part_of_file(s));
00185       s->file.data += s->len;
00186       s->file.len -= s->len;
00187       
00188     }
00189   }
00190   
00191   PT_END(&s->scriptpt);
00192 }
00193 /*---------------------------------------------------------------------------*/
00194 static
00195 PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr))
00196 {
00197   char *ptr;
00198 
00199   PSOCK_BEGIN(&s->sout);
00200 
00201   PSOCK_SEND_STR(&s->sout, statushdr);
00202 
00203   ptr = strrchr(s->filename, ISO_period);
00204   if(ptr == NULL) {
00205     PSOCK_SEND_STR(&s->sout, http_content_type_binary);
00206   } else if(strncmp(http_html, ptr, sizeof(http_html)-1) == 0 ||
00207             strncmp(http_shtml, ptr, sizeof(http_shtml)-1) == 0) {
00208     PSOCK_SEND_STR(&s->sout, http_content_type_html);
00209   } else if(strncmp(http_json, ptr, sizeof(http_json)-1) == 0) {
00210     PSOCK_SEND_STR(&s->sout, http_content_type_json);
00211   } else if(strncmp(http_xml, ptr, sizeof(http_xml)-1) == 0) {
00212     PSOCK_SEND_STR(&s->sout, http_content_type_xml);
00213   } else if(strncmp(http_css, ptr, sizeof(http_css)-1) == 0) {
00214     PSOCK_SEND_STR(&s->sout, http_content_type_css);
00215   } else if(strncmp(http_png, ptr, sizeof(http_png)-1) == 0) {
00216     PSOCK_SEND_STR(&s->sout, http_content_type_png);
00217   } else if(strncmp(http_gif, ptr, sizeof(http_gif)-1) == 0) {
00218     PSOCK_SEND_STR(&s->sout, http_content_type_gif);
00219   } else if(strncmp(http_jpg, ptr, sizeof(http_jpg)-1) == 0) {
00220     PSOCK_SEND_STR(&s->sout, http_content_type_jpg);
00221   } else {
00222     PSOCK_SEND_STR(&s->sout, http_content_type_plain);
00223   }
00224   PSOCK_END(&s->sout);
00225 }
00226 /*---------------------------------------------------------------------------*/
00227 static
00228 PT_THREAD(handle_output(struct httpd_state *s))
00229 {
00230   char *ptr;
00231   
00232   PT_BEGIN(&s->outputpt);
00233  
00234   if(!httpd_fs_open(s->filename, &s->file)) {
00235     httpd_fs_open(http_404_html, &s->file);
00236     strcpy(s->filename, http_404_html);
00237     PT_WAIT_THREAD(&s->outputpt,
00238                    send_headers(s,
00239                    http_header_404));
00240     PT_WAIT_THREAD(&s->outputpt,
00241                    send_file(s));
00242   } else {
00243     PT_WAIT_THREAD(&s->outputpt,
00244                    send_headers(s,
00245                    http_header_200));
00246     ptr = strchr(s->filename, ISO_period);
00247     if(ptr != NULL && (strncmp(ptr, http_shtml, sizeof(http_shtml)-1) == 0 ||
00248                        strncmp(ptr, http_json, sizeof(http_json)-1) == 0 || 
00249                        strncmp(ptr, http_xml, sizeof(http_xml)-1) == 0)) {
00250       PT_INIT(&s->scriptpt);
00251       PT_WAIT_THREAD(&s->outputpt, handle_script(s));
00252     } else {
00253       PT_WAIT_THREAD(&s->outputpt,
00254                      send_file(s));
00255     }
00256   }
00257   PSOCK_CLOSE(&s->sout);
00258   PT_END(&s->outputpt);
00259 }
00260 /*---------------------------------------------------------------------------*/
00261 static
00262 PT_THREAD(handle_input(struct httpd_state *s))
00263 {
00264   PSOCK_BEGIN(&s->sin);
00265 
00266   PSOCK_READTO(&s->sin, ISO_space);
00267 
00268   
00269   if(strncmp(s->inputbuf, http_get, sizeof(http_get)-1) != 0) {
00270     PSOCK_CLOSE_EXIT(&s->sin);
00271   }
00272   PSOCK_READTO(&s->sin, ISO_space);
00273 
00274   if(s->inputbuf[0] != ISO_slash) {
00275     PSOCK_CLOSE_EXIT(&s->sin);
00276   }
00277 
00278   if(s->inputbuf[1] == ISO_space) {
00279     strncpy(s->filename, http_index_html, sizeof(s->filename));
00280   } else {
00281     s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
00282     strncpy(s->filename, s->inputbuf, sizeof(s->filename));
00283   }
00284 
00285   /*  httpd_log_file(uip_conn->ripaddr, s->filename);*/
00286   
00287   s->state = STATE_OUTPUT;
00288 
00289   while(1) {
00290     PSOCK_READTO(&s->sin, ISO_nl);
00291 
00292     if(strncmp(s->inputbuf, http_referer, sizeof(http_referer)-1) == 0) {
00293       s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
00294       /*      httpd_log(&s->inputbuf[9]);*/
00295     }
00296   }
00297   
00298   PSOCK_END(&s->sin);
00299 }
00300 /*---------------------------------------------------------------------------*/
00301 static void
00302 handle_connection(struct httpd_state *s)
00303 {
00304   handle_input(s);
00305   if(s->state == STATE_OUTPUT) {
00306     handle_output(s);
00307   }
00308 }
00309 /*---------------------------------------------------------------------------*/
00310 extern "C" void
00311 httpd_appcall(void)
00312 {
00313   struct httpd_state *s = (struct httpd_state *)&(uip_conn->appstate);
00314 
00315   if(uip_closed() || uip_aborted() || uip_timedout()) {
00316   } else if(uip_connected()) {
00317     PSOCK_INIT(&s->sin, s->inputbuf, sizeof(s->inputbuf) - 1);
00318     PSOCK_INIT(&s->sout, s->inputbuf, sizeof(s->inputbuf) - 1);
00319     PT_INIT(&s->outputpt);
00320     s->state = STATE_WAITING;
00321     /*    timer_set(&s->timer, CLOCK_SECOND * 100);*/
00322     s->timer = 0;
00323     handle_connection(s);
00324   } else if(s != NULL) {
00325     if(uip_poll()) {
00326       ++s->timer;
00327       if(s->timer >= 20) {
00328         uip_abort();
00329       }
00330     } else {
00331       s->timer = 0;
00332     }
00333     handle_connection(s);
00334   } else {
00335     uip_abort();
00336   }
00337 }
00338 /*---------------------------------------------------------------------------*/
00339 /**
00340  * \brief      Initialize the web server
00341  *
00342  *             This function initializes the web server and should be
00343  *             called at system boot-up.
00344  */
00345 extern "C" void
00346 httpd_init(void)
00347 {
00348   uip_listen(UIP_HTONS(80));
00349 }
00350 /*---------------------------------------------------------------------------*/
00351 /** @} */