uIP 1.0
|
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 /** @} */