httpd.c 9.1 KB

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