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