7 * \defgroup httpd Web server
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.
19 * Adam Dunkels <adam@sics.se>
24 * Copyright (c) 2004, Adam Dunkels.
25 * All rights reserved.
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. Neither the name of the Institute nor the names of its contributors
36 * may be used to endorse or promote products derived from this software
37 * without specific prior written permission.
39 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
40 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
42 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
43 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
44 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
45 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
47 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
48 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * This file is part of the uIP TCP/IP stack.
53 * Author: Adam Dunkels <adam@sics.se>
55 * $Id: httpd.c,v 1.2 2006/06/11 21:46:38 adam Exp $
61 #include "httpd-cgi.h"
62 #include "http-strings.h"
66 #define STATE_WAITING 0
67 #define STATE_OUTPUT 1
70 #define ISO_space 0x20
72 #define ISO_percent 0x25
73 #define ISO_period 0x2e
74 #define ISO_slash 0x2f
75 #define ISO_colon 0x3a
78 /*---------------------------------------------------------------------------*/
80 generate_part_of_file(void *state
)
82 struct httpd_state
*s
= (struct httpd_state
*)state
;
84 if(s
->file
.len
> uip_mss()) {
89 memcpy(uip_appdata
, s
->file
.data
, s
->len
);
93 /*---------------------------------------------------------------------------*/
95 PT_THREAD(send_file(struct httpd_state
*s
))
97 PSOCK_BEGIN(&s
->sout
);
100 PSOCK_GENERATOR_SEND(&s
->sout
, generate_part_of_file
, s
);
101 s
->file
.len
-= s
->len
;
102 s
->file
.data
+= s
->len
;
103 } while(s
->file
.len
> 0);
107 /*---------------------------------------------------------------------------*/
109 PT_THREAD(send_part_of_file(struct httpd_state
*s
))
111 PSOCK_BEGIN(&s
->sout
);
113 PSOCK_SEND(&s
->sout
, s
->file
.data
, s
->len
);
117 /*---------------------------------------------------------------------------*/
119 next_scriptstate(struct httpd_state
*s
)
122 p
= strchr(s
->scriptptr
, ISO_nl
) + 1;
123 s
->scriptlen
-= (unsigned short)(p
- s
->scriptptr
);
126 /*---------------------------------------------------------------------------*/
128 PT_THREAD(handle_script(struct httpd_state
*s
))
132 PT_BEGIN(&s
->scriptpt
);
135 while(s
->file
.len
> 0) {
137 /* Check if we should start executing a script. */
138 if(*s
->file
.data
== ISO_percent
&&
139 *(s
->file
.data
+ 1) == ISO_bang
) {
140 s
->scriptptr
= s
->file
.data
+ 3;
141 s
->scriptlen
= s
->file
.len
- 3;
142 if(*(s
->scriptptr
- 1) == ISO_colon
) {
143 httpd_fs_open(s
->scriptptr
+ 1, &s
->file
);
144 PT_WAIT_THREAD(&s
->scriptpt
, send_file(s
));
146 PT_WAIT_THREAD(&s
->scriptpt
,
147 httpd_cgi(s
->scriptptr
)(s
, s
->scriptptr
));
151 /* The script is over, so we reset the pointers and continue
152 sending the rest of the file. */
153 s
->file
.data
= s
->scriptptr
;
154 s
->file
.len
= s
->scriptlen
;
156 /* See if we find the start of script marker in the block of HTML
159 if(s
->file
.len
> uip_mss()) {
162 s
->len
= s
->file
.len
;
165 if(*s
->file
.data
== ISO_percent
) {
166 ptr
= strchr(s
->file
.data
+ 1, ISO_percent
);
168 ptr
= strchr(s
->file
.data
, ISO_percent
);
171 ptr
!= s
->file
.data
) {
172 s
->len
= (int)(ptr
- s
->file
.data
);
173 if(s
->len
>= uip_mss()) {
177 PT_WAIT_THREAD(&s
->scriptpt
, send_part_of_file(s
));
178 s
->file
.data
+= s
->len
;
179 s
->file
.len
-= s
->len
;
184 PT_END(&s
->scriptpt
);
186 /*---------------------------------------------------------------------------*/
188 PT_THREAD(send_headers(struct httpd_state
*s
, const char *statushdr
))
192 PSOCK_BEGIN(&s
->sout
);
194 PSOCK_SEND_STR(&s
->sout
, statushdr
);
196 ptr
= strrchr(s
->filename
, ISO_period
);
198 PSOCK_SEND_STR(&s
->sout
, http_content_type_binary
);
199 } else if(strncmp(http_html
, ptr
, 5) == 0 ||
200 strncmp(http_shtml
, ptr
, 6) == 0) {
201 PSOCK_SEND_STR(&s
->sout
, http_content_type_html
);
202 } else if(strncmp(http_css
, ptr
, 4) == 0) {
203 PSOCK_SEND_STR(&s
->sout
, http_content_type_css
);
204 } else if(strncmp(http_png
, ptr
, 4) == 0) {
205 PSOCK_SEND_STR(&s
->sout
, http_content_type_png
);
206 } else if(strncmp(http_gif
, ptr
, 4) == 0) {
207 PSOCK_SEND_STR(&s
->sout
, http_content_type_gif
);
208 } else if(strncmp(http_jpg
, ptr
, 4) == 0) {
209 PSOCK_SEND_STR(&s
->sout
, http_content_type_jpg
);
211 PSOCK_SEND_STR(&s
->sout
, http_content_type_plain
);
215 /*---------------------------------------------------------------------------*/
217 PT_THREAD(handle_output(struct httpd_state
*s
))
221 PT_BEGIN(&s
->outputpt
);
223 if(!httpd_fs_open(s
->filename
, &s
->file
)) {
224 httpd_fs_open(http_404_html
, &s
->file
);
225 strcpy(s
->filename
, http_404_html
);
226 PT_WAIT_THREAD(&s
->outputpt
,
229 PT_WAIT_THREAD(&s
->outputpt
,
232 PT_WAIT_THREAD(&s
->outputpt
,
235 ptr
= strchr(s
->filename
, ISO_period
);
236 if(ptr
!= NULL
&& strncmp(ptr
, http_shtml
, 6) == 0) {
237 PT_INIT(&s
->scriptpt
);
238 PT_WAIT_THREAD(&s
->outputpt
, handle_script(s
));
240 PT_WAIT_THREAD(&s
->outputpt
,
244 PSOCK_CLOSE(&s
->sout
);
245 PT_END(&s
->outputpt
);
247 /*---------------------------------------------------------------------------*/
249 PT_THREAD(handle_input(struct httpd_state
*s
))
251 PSOCK_BEGIN(&s
->sin
);
253 PSOCK_READTO(&s
->sin
, ISO_space
);
256 if(strncmp(s
->inputbuf
, http_get
, 4) != 0) {
257 PSOCK_CLOSE_EXIT(&s
->sin
);
259 PSOCK_READTO(&s
->sin
, ISO_space
);
261 if(s
->inputbuf
[0] != ISO_slash
) {
262 PSOCK_CLOSE_EXIT(&s
->sin
);
265 if(s
->inputbuf
[1] == ISO_space
) {
266 strncpy(s
->filename
, http_index_html
, sizeof(s
->filename
));
268 s
->inputbuf
[PSOCK_DATALEN(&s
->sin
) - 1] = 0;
269 strncpy(s
->filename
, &s
->inputbuf
[0], sizeof(s
->filename
));
272 /* httpd_log_file(uip_conn->ripaddr, s->filename);*/
274 s
->state
= STATE_OUTPUT
;
277 PSOCK_READTO(&s
->sin
, ISO_nl
);
279 if(strncmp(s
->inputbuf
, http_referer
, 8) == 0) {
280 s
->inputbuf
[PSOCK_DATALEN(&s
->sin
) - 2] = 0;
281 /* httpd_log(&s->inputbuf[9]);*/
287 /*---------------------------------------------------------------------------*/
289 handle_connection(struct httpd_state
*s
)
292 if(s
->state
== STATE_OUTPUT
) {
296 /*---------------------------------------------------------------------------*/
300 struct httpd_state
*s
= (struct httpd_state
*)&(uip_conn
->appstate
);
302 if(uip_closed() || uip_aborted() || uip_timedout()) {
303 } else if(uip_connected()) {
304 PSOCK_INIT(&s
->sin
, s
->inputbuf
, sizeof(s
->inputbuf
) - 1);
305 PSOCK_INIT(&s
->sout
, s
->inputbuf
, sizeof(s
->inputbuf
) - 1);
306 PT_INIT(&s
->outputpt
);
307 s
->state
= STATE_WAITING
;
308 /* timer_set(&s->timer, CLOCK_SECOND * 100);*/
310 handle_connection(s
);
311 } else if(s
!= NULL
) {
320 handle_connection(s
);
325 /*---------------------------------------------------------------------------*/
327 * \brief Initialize the web server
329 * This function initializes the web server and should be
330 * called at system boot-up.
335 uip_listen(HTONS(80));
337 /*---------------------------------------------------------------------------*/