uIP 1.0
C:/asm/STM32-ethernet/ENC28J60prj/uip-master/apps/webserver/httpd.c
См. документацию.
00001 /**
00002  * \addtogroup apps
00003  * @{
00004  */
00005 
00006 /**
00007  * \defgroup httpd Web-сервер
00008  * @{
00009  * uIP web-сервер является очень упрощенной реализацией сервера HTTP.
00010  * Он может обрабатывать веб-страницы и файлы, размещенные прямо 
00011  * в памяти прогамм (ROM, файловая система только для чтения),
00012  * и предоставляет очень маленький язык скриптов.
00013 
00014  */
00015 
00016 /**
00017  * \file
00018  *         Web-сервер
00019  * \author
00020  *         Adam Dunkels <adam@sics.se>
00021  */
00022 
00023 
00024 /*
00025  * Copyright (c) 2004, Adam Dunkels.
00026  * Все права зарезервированы. *
00027  * Повторное распространение, использование в исходном и двоичном виде,
00028  * с модификацией или без - разрешается, если выполняются следующие
00029  * условия:
00030  * 1. Распространение исходного кода должно сохранить вышеуказанную пометку
00031  *    копирайта, этот список условий и следующую правовую оговорку.
00032  * 2. Распространение исходного кода должно сохранить вышеуказанную пометку
00033  *    копирайта, этот список условий и следующую правовую оговорку в
00034  *    документации и/или других материалах, которые будут предоставлены
00035  *    вместе с распространяемыми материалами.
00036  * 3. Имя автора не может использоваться, чтобы подтвердить или продвинуть
00037  *    продукты, написанные с использованием этого программного обеспечения
00038  *    без специального на то разрешения.
00039  *
00040  * ЭТО ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ АВТОРОМ ``КАК ЕСТЬ'', БЕЗ
00041  * КАКОЙ-ЛИБО ЛЮБОЙ РАСШИРЕННОЙ ИЛИ ПОДРАЗУМЕВАЕМОЙ ГАРАНТИИ, ВКЛЮЧАЯ,
00042  * НО НЕ ОГРАНИЧИВАЯСЬ ЭТИМ, ГАРАНТИИ ВЫСОКОГО СПРОСА И ПРИГОДНОСТИ
00043  * ДЛЯ КОНКРЕТНОЙ ЦЕЛИ. АВТОР НИ ПРИ КАКИХ УСЛОВИЯХ НЕ ОТВЕТСТВЕНЕН
00044  * ЗА ЛЮБЫЕ УБЫТКИ - ПРЯМЫЕ, КОСВЕННЫЕ, СЛУЧАЙНЫЕ, СПЕЦИАЛЬНЫЕ, ОБРАЗЦОВЫЕ
00045  * ИЛИ ПОСЛЕДОВАТЕЛЬНЫЕ (ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ЭТИМ, ТРЕБОВАНИЯ
00046  * ЗАМЕНЫ ТОВАРА ИЛИ СЕРВИСА; ПОТЕРИ ИСПОЛЬЗОВАНИЯ, ДАННЫХ ИЛИ ВЫГОДЫ;
00047  * ИЛИ ПРЕКРАЩЕНИЕ БИЗНЕСА), ОДНАКО ВЫЗВАННЫЕ ПО ЛЮБОЙ ТЕОРИИ ОТВЕТСТВЕННОСТИ,
00048  * ЛИБО В КОНТРАКТЕ, ПРЯМОЙ ОТВЕТСТВЕННОСТИ, ЛИБО В НАРУШЕНИИ ЗАКОННЫХ ПРАВ
00049  * (ВКЛЮЧАЯ ТАК ИЛИ ИНАЧЕ НЕБРЕЖНОСТЬ), ВОЗНИКАЮЩИЕ ВСЕГДА ИЗ ИСПОЛЬЗОВАНИЯ
00050  * ЭТОГО ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ, ДАЖЕ ЕСЛИ БЫЛО ПРЕДУПРЕЖДЕНИЕ О ВОЗМОЖНОСТИ
00051  * ТАКОГО ПОВРЕЖДЕНИЯ.
00052  *
00053  * Этот файл является частью стека uIP TCP/IP..
00054  *
00055  * Author: Adam Dunkels <adam@sics.se>
00056  *
00057  * $Id: httpd.c,v 1.2 2006/06/11 21:46:38 adam Exp $
00058  */
00059 
00060 #include "uip.h"
00061 #include "httpd.h"
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   p = strchr(s->scriptptr, ISO_nl) + 1;
00125   s->scriptlen -= (unsigned short)(p - s->scriptptr);
00126   s->scriptptr = p;
00127 }
00128 /*---------------------------------------------------------------------------*/
00129 static
00130 PT_THREAD(handle_script(struct httpd_state *s))
00131 {
00132   char *ptr;
00133   
00134   PT_BEGIN(&s->scriptpt);
00135 
00136 
00137   while(s->file.len > 0) {
00138     /* Проверка - нужно ли начать выполнение скрипта. */
00139     if(*s->file.data == ISO_percent &&
00140        *(s->file.data + 1) == ISO_bang) {
00141       s->scriptptr = s->file.data + 3;
00142       s->scriptlen = s->file.len - 3;
00143       if(*(s->scriptptr - 1) == ISO_colon) {
00144          httpd_fs_open(s->scriptptr + 1, &s->file);
00145          PT_WAIT_THREAD(&s->scriptpt, send_file(s));
00146       } else {
00147          PT_WAIT_THREAD(&s->scriptpt,
00148                         httpd_cgi(s->scriptptr)(s, s->scriptptr));
00149       }
00150       next_scriptstate(s);
00151       
00152       /* Скрипт закончился, так что сбросим указатели и продолжим
00153          отправлять остальную часть файла. */
00154       s->file.data = s->scriptptr;
00155       s->file.len = s->scriptlen;
00156     } else {
00157       /* Посмотрим, найден ли маркер начала скрипта в блоке HTML
00158          для отправки. */
00159       if(s->file.len > uip_mss()) {
00160          s->len = uip_mss();
00161       } else {
00162          s->len = s->file.len;
00163       }
00164       if(*s->file.data == ISO_percent) {
00165          ptr = strchr(s->file.data + 1, ISO_percent);
00166       } else {
00167          ptr = strchr(s->file.data, ISO_percent);
00168       }
00169       if(ptr != NULL &&
00170          ptr != s->file.data) {
00171          s->len = (int)(ptr - s->file.data);
00172          if(s->len >= uip_mss()) {
00173             s->len = uip_mss();
00174          }
00175       }
00176       PT_WAIT_THREAD(&s->scriptpt, send_part_of_file(s));
00177       s->file.data += s->len;
00178       s->file.len -= s->len;
00179     }
00180   }
00181   
00182   PT_END(&s->scriptpt);
00183 }
00184 /*---------------------------------------------------------------------------*/
00185 static
00186 PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr))
00187 {
00188   char *ptr;
00189 
00190   PSOCK_BEGIN(&s->sout);
00191 
00192   PSOCK_SEND_STR(&s->sout, statushdr);
00193 
00194   ptr = strrchr(s->filename, ISO_period);
00195   if(ptr == NULL) {
00196     PSOCK_SEND_STR(&s->sout, http_content_type_binary);
00197   } else if(strncmp(http_html, ptr, 5) == 0 ||
00198              strncmp(http_shtml, ptr, 6) == 0) {
00199     PSOCK_SEND_STR(&s->sout, http_content_type_html);
00200   } else if(strncmp(http_css, ptr, 4) == 0) {
00201     PSOCK_SEND_STR(&s->sout, http_content_type_css);
00202   } else if(strncmp(http_png, ptr, 4) == 0) {
00203     PSOCK_SEND_STR(&s->sout, http_content_type_png);
00204   } else if(strncmp(http_gif, ptr, 4) == 0) {
00205     PSOCK_SEND_STR(&s->sout, http_content_type_gif);
00206   } else if(strncmp(http_jpg, ptr, 4) == 0) {
00207     PSOCK_SEND_STR(&s->sout, http_content_type_jpg);
00208   } else {
00209     PSOCK_SEND_STR(&s->sout, http_content_type_plain);
00210   }
00211   PSOCK_END(&s->sout);
00212 }
00213 /*---------------------------------------------------------------------------*/
00214 static
00215 PT_THREAD(handle_output(struct httpd_state *s))
00216 {
00217   char *ptr;
00218   
00219   PT_BEGIN(&s->outputpt);
00220  
00221   if(!httpd_fs_open(s->filename, &s->file)) {
00222     httpd_fs_open(http_404_html, &s->file);
00223     strcpy(s->filename, http_404_html);
00224     PT_WAIT_THREAD(&s->outputpt,
00225                   send_headers(s,
00226                   http_header_404));
00227     PT_WAIT_THREAD(&s->outputpt,
00228                   send_file(s));
00229   } else {
00230     PT_WAIT_THREAD(&s->outputpt,
00231                   send_headers(s,
00232                   http_header_200));
00233     ptr = strchr(s->filename, ISO_period);
00234     if(ptr != NULL && strncmp(ptr, http_shtml, 6) == 0) {
00235       PT_INIT(&s->scriptpt);
00236       PT_WAIT_THREAD(&s->outputpt, handle_script(s));
00237     } else {
00238       PT_WAIT_THREAD(&s->outputpt,
00239                      send_file(s));
00240     }
00241   }
00242   PSOCK_CLOSE(&s->sout);
00243   PT_END(&s->outputpt);
00244 }
00245 /*---------------------------------------------------------------------------*/
00246 static
00247 PT_THREAD(handle_input(struct httpd_state *s))
00248 {
00249   PSOCK_BEGIN(&s->sin);
00250 
00251   PSOCK_READTO(&s->sin, ISO_space);
00252 
00253   
00254   if(strncmp(s->inputbuf, http_get, 4) != 0) {
00255     PSOCK_CLOSE_EXIT(&s->sin);
00256   }
00257   PSOCK_READTO(&s->sin, ISO_space);
00258 
00259   if(s->inputbuf[0] != ISO_slash) {
00260     PSOCK_CLOSE_EXIT(&s->sin);
00261   }
00262 
00263   if(s->inputbuf[1] == ISO_space) {
00264     strncpy(s->filename, http_index_html, sizeof(s->filename));
00265   } else {
00266     s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
00267     strncpy(s->filename, &s->inputbuf[0], sizeof(s->filename));
00268   }
00269 
00270   /*  httpd_log_file(uip_conn->ripaddr, s->filename);*/
00271   
00272   s->state = STATE_OUTPUT;
00273 
00274   while(1) {
00275     PSOCK_READTO(&s->sin, ISO_nl);
00276 
00277     if(strncmp(s->inputbuf, http_referer, 8) == 0) {
00278       s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
00279       /*      httpd_log(&s->inputbuf[9]);*/
00280     }
00281   }
00282   
00283   PSOCK_END(&s->sin);
00284 }
00285 /*---------------------------------------------------------------------------*/
00286 static void
00287 handle_connection(struct httpd_state *s)
00288 {
00289   handle_input(s);
00290   if(s->state == STATE_OUTPUT) {
00291     handle_output(s);
00292   }
00293 }
00294 /*---------------------------------------------------------------------------*/
00295 void
00296 httpd_appcall(void)
00297 {
00298   struct httpd_state *s = (struct httpd_state *)&(uip_conn->appstate);
00299 
00300   if(uip_closed() || uip_aborted() || uip_timedout()) {
00301   } else if(uip_connected()) {
00302     PSOCK_INIT(&s->sin, s->inputbuf, sizeof(s->inputbuf) - 1);
00303     PSOCK_INIT(&s->sout, s->inputbuf, sizeof(s->inputbuf) - 1);
00304     PT_INIT(&s->outputpt);
00305     s->state = STATE_WAITING;
00306     /*    timer_set(&s->timer, CLOCK_SECOND * 100);*/
00307     s->timer = 0;
00308     handle_connection(s);
00309   } else if(s != NULL) {
00310     if(uip_poll()) {
00311       ++s->timer;
00312       if(s->timer >= 20) {
00313          uip_abort();
00314       }
00315     } else {
00316       s->timer = 0;
00317     }
00318     handle_connection(s);
00319   } else {
00320     uip_abort();
00321   }
00322 }
00323 /*---------------------------------------------------------------------------*/
00324 /**
00325  * \brief      Инициализация web-сервера
00326  *
00327  *             Эта функция инициализирует web-сервер и она должна быть
00328  *             вызвана при загрузке системы.
00329  */
00330 void
00331 httpd_init(void)
00332 {
00333   uip_listen(HTONS(80));
00334 }
00335 /*---------------------------------------------------------------------------*/
00336 /** @} */