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