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