]> git.sur5r.net Git - freertos/blob - Demo/Common/ethernet/FreeTCPIP/apps/httpd/httpd.c
Tidy up SuperH port a bit ready for release.
[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         do\r
100         {\r
101                 PSOCK_GENERATOR_SEND( &s->sout, generate_part_of_file, s );\r
102                 s->file.len -= s->len;\r
103                 s->file.data += s->len;\r
104         } while( s->file.len > 0 );\r
105 \r
106         PSOCK_END( &s->sout );\r
107 }\r
108 \r
109 /*---------------------------------------------------------------------------*/\r
110 static PT_THREAD( send_part_of_file ( struct httpd_state *s ) )\r
111 {\r
112         PSOCK_BEGIN( &s->sout );\r
113 \r
114         PSOCK_SEND( &s->sout, s->file.data, s->len );\r
115 \r
116         PSOCK_END( &s->sout );\r
117 }\r
118 \r
119 /*---------------------------------------------------------------------------*/\r
120 static void next_scriptstate( struct httpd_state *s )\r
121 {\r
122         char    *p;\r
123         p = strchr( s->scriptptr, ISO_nl ) + 1;\r
124         s->scriptlen -= ( unsigned short ) ( p - s->scriptptr );\r
125         s->scriptptr = p;\r
126 }\r
127 \r
128 /*---------------------------------------------------------------------------*/\r
129 static PT_THREAD( handle_script ( struct httpd_state *s ) )\r
130 {\r
131         char    *ptr;\r
132 \r
133         PT_BEGIN( &s->scriptpt );\r
134 \r
135         while( s->file.len > 0 )\r
136         {\r
137                 /* Check if we should start executing a script. */\r
138                 if( *s->file.data == ISO_percent && *(s->file.data + 1) == ISO_bang )\r
139                 {\r
140                         s->scriptptr = s->file.data + 3;\r
141                         s->scriptlen = s->file.len - 3;\r
142                         if( *(s->scriptptr - 1) == ISO_colon )\r
143                         {\r
144                                 httpd_fs_open( s->scriptptr + 1, &s->file );\r
145                                 PT_WAIT_THREAD( &s->scriptpt, send_file(s) );\r
146                         }\r
147                         else\r
148                         {\r
149                                 PT_WAIT_THREAD( &s->scriptpt, httpd_cgi(s->scriptptr) (s, s->scriptptr) );\r
150                         }\r
151 \r
152                         next_scriptstate( s );\r
153 \r
154                         /* The script is over, so we reset the pointers and continue\r
155                         sending the rest of the file. */\r
156                         s->file.data = s->scriptptr;\r
157                         s->file.len = s->scriptlen;\r
158                 }\r
159                 else\r
160                 {\r
161                         /* See if we find the start of script marker in the block of HTML\r
162          to be sent. */\r
163                         if( s->file.len > uip_mss() )\r
164                         {\r
165                                 s->len = uip_mss();\r
166                         }\r
167                         else\r
168                         {\r
169                                 s->len = s->file.len;\r
170                         }\r
171 \r
172                         if( *s->file.data == ISO_percent )\r
173                         {\r
174                                 ptr = strchr( s->file.data + 1, ISO_percent );\r
175                         }\r
176                         else\r
177                         {\r
178                                 ptr = strchr( s->file.data, ISO_percent );\r
179                         }\r
180 \r
181                         if( ptr != NULL && ptr != s->file.data )\r
182                         {\r
183                                 s->len = ( int ) ( ptr - s->file.data );\r
184                                 if( s->len >= uip_mss() )\r
185                                 {\r
186                                         s->len = uip_mss();\r
187                                 }\r
188                         }\r
189 \r
190                         PT_WAIT_THREAD( &s->scriptpt, send_part_of_file(s) );\r
191                         s->file.data += s->len;\r
192                         s->file.len -= s->len;\r
193                 }\r
194         }\r
195 \r
196         PT_END( &s->scriptpt );\r
197 }\r
198 \r
199 /*---------------------------------------------------------------------------*/\r
200 static PT_THREAD( send_headers ( struct httpd_state *s, const char *statushdr ) )\r
201 {\r
202         char    *ptr;\r
203 \r
204         PSOCK_BEGIN( &s->sout );\r
205 \r
206         PSOCK_SEND_STR( &s->sout, statushdr );\r
207 \r
208         ptr = strrchr( s->filename, ISO_period );\r
209         if( ptr == NULL )\r
210         {\r
211                 PSOCK_SEND_STR( &s->sout, http_content_type_binary );\r
212         }\r
213         else if( strncmp(http_html, ptr, 5) == 0 || strncmp(http_shtml, ptr, 6) == 0 )\r
214         {\r
215                 PSOCK_SEND_STR( &s->sout, http_content_type_html );\r
216         }\r
217         else if( strncmp(http_css, ptr, 4) == 0 )\r
218         {\r
219                 PSOCK_SEND_STR( &s->sout, http_content_type_css );\r
220         }\r
221         else if( strncmp(http_png, ptr, 4) == 0 )\r
222         {\r
223                 PSOCK_SEND_STR( &s->sout, http_content_type_png );\r
224         }\r
225         else if( strncmp(http_gif, ptr, 4) == 0 )\r
226         {\r
227                 PSOCK_SEND_STR( &s->sout, http_content_type_gif );\r
228         }\r
229         else if( strncmp(http_jpg, ptr, 4) == 0 )\r
230         {\r
231                 PSOCK_SEND_STR( &s->sout, http_content_type_jpg );\r
232         }\r
233         else\r
234         {\r
235                 PSOCK_SEND_STR( &s->sout, http_content_type_plain );\r
236         }\r
237 \r
238         PSOCK_END( &s->sout );\r
239 }\r
240 \r
241 /*---------------------------------------------------------------------------*/\r
242 static PT_THREAD( handle_output ( struct httpd_state *s ) )\r
243 {\r
244         char    *ptr;\r
245 \r
246         PT_BEGIN( &s->outputpt );\r
247 \r
248         if( !httpd_fs_open(s->filename, &s->file) )\r
249         {\r
250                 httpd_fs_open( http_404_html, &s->file );\r
251                 strcpy( s->filename, http_404_html );\r
252                 PT_WAIT_THREAD( &s->outputpt, send_headers(s, http_header_404) );\r
253                 PT_WAIT_THREAD( &s->outputpt, send_file(s) );\r
254         }\r
255         else\r
256         {\r
257                 PT_WAIT_THREAD( &s->outputpt, send_headers(s, http_header_200) );\r
258                 ptr = strchr( s->filename, ISO_period );\r
259                 if( ptr != NULL && strncmp(ptr, http_shtml, 6) == 0 )\r
260                 {\r
261                         PT_INIT( &s->scriptpt );\r
262                         PT_WAIT_THREAD( &s->outputpt, handle_script(s) );\r
263                 }\r
264                 else\r
265                 {\r
266                         PT_WAIT_THREAD( &s->outputpt, send_file(s) );\r
267                 }\r
268         }\r
269 \r
270         PSOCK_CLOSE( &s->sout );\r
271         PT_END( &s->outputpt );\r
272 }\r
273 \r
274 /*---------------------------------------------------------------------------*/\r
275 static PT_THREAD( handle_input ( struct httpd_state *s ) )\r
276 {\r
277         PSOCK_BEGIN( &s->sin );\r
278 \r
279         PSOCK_READTO( &s->sin, ISO_space );\r
280 \r
281         if( strncmp(s->inputbuf, http_get, 4) != 0 )\r
282         {\r
283                 PSOCK_CLOSE_EXIT( &s->sin );\r
284         }\r
285 \r
286         PSOCK_READTO( &s->sin, ISO_space );\r
287 \r
288         if( s->inputbuf[0] != ISO_slash )\r
289         {\r
290                 PSOCK_CLOSE_EXIT( &s->sin );\r
291         }\r
292 \r
293         if( s->inputbuf[1] == ISO_space )\r
294         {\r
295                 strncpy( s->filename, http_index_html, sizeof(s->filename) );\r
296         }\r
297         else\r
298         {\r
299                 s->inputbuf[PSOCK_DATALEN( &s->sin ) - 1] = 0;\r
300                 \r
301                 /* Process any form input being sent to the server. */\r
302                 #if UIP_CONF_PROCESS_HTTPD_FORMS == 1\r
303                 {\r
304                         extern void vApplicationProcessFormInput( char *pcInputString );\r
305                         vApplicationProcessFormInput( s->inputbuf );\r
306                 }\r
307                 #endif\r
308                 \r
309                 strncpy( s->filename, &s->inputbuf[0], sizeof(s->filename) );\r
310         }\r
311 \r
312         /*  httpd_log_file(uip_conn->ripaddr, s->filename);*/\r
313         s->state = STATE_OUTPUT;\r
314 \r
315         while( 1 )\r
316         {\r
317                 PSOCK_READTO( &s->sin, ISO_nl );\r
318 \r
319                 if( strncmp(s->inputbuf, http_referer, 8) == 0 )\r
320                 {\r
321                         s->inputbuf[PSOCK_DATALEN( &s->sin ) - 2] = 0;\r
322 \r
323                         /*      httpd_log(&s->inputbuf[9]);*/\r
324                 }\r
325         }\r
326 \r
327         PSOCK_END( &s->sin );\r
328 }\r
329 \r
330 /*---------------------------------------------------------------------------*/\r
331 static void handle_connection( struct httpd_state *s )\r
332 {\r
333         handle_input( s );\r
334         if( s->state == STATE_OUTPUT )\r
335         {\r
336                 handle_output( s );\r
337         }\r
338 }\r
339 \r
340 /*---------------------------------------------------------------------------*/\r
341 void httpd_appcall( void )\r
342 {\r
343         struct httpd_state      *s = ( struct httpd_state * ) &( uip_conn->appstate );\r
344 \r
345         if( uip_closed() || uip_aborted() || uip_timedout() )\r
346         {\r
347         }\r
348         else if( uip_connected() )\r
349         {\r
350                 PSOCK_INIT( &s->sin, s->inputbuf, sizeof(s->inputbuf) - 1 );\r
351                 PSOCK_INIT( &s->sout, s->inputbuf, sizeof(s->inputbuf) - 1 );\r
352                 PT_INIT( &s->outputpt );\r
353                 s->state = STATE_WAITING;\r
354 \r
355                 /*    timer_set(&s->timer, CLOCK_SECOND * 100);*/\r
356                 s->timer = 0;\r
357                 handle_connection( s );\r
358         }\r
359         else if( s != NULL )\r
360         {\r
361                 if( uip_poll() )\r
362                 {\r
363                         ++s->timer;\r
364                         if( s->timer >= 20 )\r
365                         {\r
366                                 uip_abort();\r
367                         }\r
368                 }\r
369                 else\r
370                 {\r
371                         s->timer = 0;\r
372                 }\r
373 \r
374                 handle_connection( s );\r
375         }\r
376         else\r
377         {\r
378                 uip_abort();\r
379         }\r
380 }\r
381 \r
382 /*---------------------------------------------------------------------------*/\r
383 \r
384 /**\r
385  * \brief      Initialize the web server\r
386  *\r
387  *             This function initializes the web server and should be\r
388  *             called at system boot-up.\r
389  */\r
390 void httpd_init( void )\r
391 {\r
392         uip_listen( HTONS(80) );\r
393 }\r
394 \r
395 /*---------------------------------------------------------------------------*/\r
396 \r
397 /** @} */\r