2 * Copyright (c) 2004, Adam Dunkels.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the Institute nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * This file is part of the Contiki operating system.
31 * Author: Adam Dunkels <adam@sics.se>
33 * $Id: httpd-cfs.c,v 1.21 2010/04/11 19:18:47 oliverschmidt Exp $
38 int snprintf(char *str
, size_t size
, const char *format
, ...);
39 #endif /* HAVE_SNPRINTF */
42 #include "contiki-net.h"
44 #include "webserver.h"
46 #include "lib/petsciiconv.h"
47 #include "http-strings.h"
50 #include "httpd-cfs.h"
52 #ifndef WEBSERVER_CONF_CFS_CONNS
54 #else /* WEBSERVER_CONF_CFS_CONNS */
55 #define CONNS WEBSERVER_CONF_CFS_CONNS
56 #endif /* WEBSERVER_CONF_CFS_CONNS */
58 #ifndef WEBSERVER_CONF_CFS_URLCONV
60 #else /* WEBSERVER_CONF_CFS_URLCONV */
61 #define URLCONV WEBSERVER_CONF_CFS_URLCONV
62 #endif /* WEBSERVER_CONF_CFS_URLCONV */
64 #define STATE_WAITING 0
65 #define STATE_OUTPUT 1
67 #define SEND_STRING(s, str) PSOCK_SEND(s, (uint8_t *)str, strlen(str))
68 MEMB(conns
, struct httpd_state
, CONNS
);
71 #define ISO_space 0x20
72 #define ISO_period 0x2e
73 #define ISO_slash 0x2f
75 /*---------------------------------------------------------------------------*/
77 PT_THREAD(send_file(struct httpd_state
*s
))
79 PSOCK_BEGIN(&s
->sout
);
82 /* Read data from file system into buffer */
83 s
->len
= cfs_read(s
->fd
, s
->outputbuf
, sizeof(s
->outputbuf
));
85 /* If there is data in the buffer, send it */
87 PSOCK_SEND(&s
->sout
, (uint8_t *)s
->outputbuf
, s
->len
);
95 /*---------------------------------------------------------------------------*/
97 PT_THREAD(send_string(struct httpd_state
*s
, const char *str
))
99 PSOCK_BEGIN(&s
->sout
);
101 SEND_STRING(&s
->sout
, str
);
105 /*---------------------------------------------------------------------------*/
107 PT_THREAD(send_headers(struct httpd_state
*s
, const char *statushdr
))
111 PSOCK_BEGIN(&s
->sout
);
113 SEND_STRING(&s
->sout
, statushdr
);
115 ptr
= strrchr(s
->filename
, ISO_period
);
117 ptr
= http_content_type_plain
;
118 } else if(strcmp(http_html
, ptr
) == 0) {
119 ptr
= http_content_type_html
;
120 } else if(strcmp(http_css
, ptr
) == 0) {
121 ptr
= http_content_type_css
;
122 } else if(strcmp(http_png
, ptr
) == 0) {
123 ptr
= http_content_type_png
;
124 } else if(strcmp(http_gif
, ptr
) == 0) {
125 ptr
= http_content_type_gif
;
126 } else if(strcmp(http_jpg
, ptr
) == 0) {
127 ptr
= http_content_type_jpg
;
129 ptr
= http_content_type_binary
;
131 SEND_STRING(&s
->sout
, ptr
);
134 /*---------------------------------------------------------------------------*/
136 PT_THREAD(handle_output(struct httpd_state
*s
))
138 PT_BEGIN(&s
->outputpt
);
140 petsciiconv_topetscii(s
->filename
, sizeof(s
->filename
));
141 s
->fd
= cfs_open(&s
->filename
[1], CFS_READ
);
142 petsciiconv_toascii(s
->filename
, sizeof(s
->filename
));
144 strcpy(s
->filename
, "/notfound.html");
145 s
->fd
= cfs_open(&s
->filename
[1], CFS_READ
);
146 petsciiconv_toascii(s
->filename
, sizeof(s
->filename
));
147 PT_WAIT_THREAD(&s
->outputpt
,
148 send_headers(s
, http_header_404
));
150 PT_WAIT_THREAD(&s
->outputpt
,
151 send_string(s
, "not found"));
153 webserver_log_file(&uip_conn
->ripaddr
, "404 (no notfound.html)");
154 PT_EXIT(&s
->outputpt
);
156 webserver_log_file(&uip_conn
->ripaddr
, "404 - notfound.html");
158 PT_WAIT_THREAD(&s
->outputpt
,
159 send_headers(s
, http_header_200
));
161 PT_WAIT_THREAD(&s
->outputpt
, send_file(s
));
164 PSOCK_CLOSE(&s
->sout
);
165 PT_END(&s
->outputpt
);
167 /*---------------------------------------------------------------------------*/
169 PT_THREAD(handle_input(struct httpd_state
*s
))
171 PSOCK_BEGIN(&s
->sin
);
173 PSOCK_READTO(&s
->sin
, ISO_space
);
175 if(strncmp(s
->inputbuf
, http_get
, 4) != 0) {
176 PSOCK_CLOSE_EXIT(&s
->sin
);
178 PSOCK_READTO(&s
->sin
, ISO_space
);
180 if(s
->inputbuf
[0] != ISO_slash
) {
181 PSOCK_CLOSE_EXIT(&s
->sin
);
185 s
->inputbuf
[PSOCK_DATALEN(&s
->sin
) - 1] = 0;
186 urlconv_tofilename(s
->filename
, s
->inputbuf
, sizeof(s
->filename
));
188 if(s
->inputbuf
[1] == ISO_space
) {
189 strncpy(s
->filename
, http_index_html
, sizeof(s
->filename
));
191 s
->inputbuf
[PSOCK_DATALEN(&s
->sin
) - 1] = 0;
192 strncpy(s
->filename
, s
->inputbuf
, sizeof(s
->filename
));
196 petsciiconv_topetscii(s
->filename
, sizeof(s
->filename
));
197 webserver_log_file(&uip_conn
->ripaddr
, s
->filename
);
198 petsciiconv_toascii(s
->filename
, sizeof(s
->filename
));
199 s
->state
= STATE_OUTPUT
;
202 PSOCK_READTO(&s
->sin
, ISO_nl
);
204 if(strncmp(s
->inputbuf
, http_referer
, 8) == 0) {
205 s
->inputbuf
[PSOCK_DATALEN(&s
->sin
) - 2] = 0;
206 petsciiconv_topetscii(s
->inputbuf
, PSOCK_DATALEN(&s
->sin
) - 2);
207 webserver_log(s
->inputbuf
);
213 /*---------------------------------------------------------------------------*/
215 handle_connection(struct httpd_state
*s
)
218 if(s
->state
== STATE_OUTPUT
) {
222 /*---------------------------------------------------------------------------*/
224 httpd_appcall(void *state
)
226 struct httpd_state
*s
= (struct httpd_state
*)state
;
228 if(uip_closed() || uip_aborted() || uip_timedout()) {
234 memb_free(&conns
, s
);
236 } else if(uip_connected()) {
237 s
= (struct httpd_state
*)memb_alloc(&conns
);
240 webserver_log_file(&uip_conn
->ripaddr
, "reset (no memory block)");
243 tcp_markconn(uip_conn
, s
);
244 PSOCK_INIT(&s
->sin
, (uint8_t *)s
->inputbuf
, sizeof(s
->inputbuf
) - 1);
245 PSOCK_INIT(&s
->sout
, (uint8_t *)s
->inputbuf
, sizeof(s
->inputbuf
) - 1);
246 PT_INIT(&s
->outputpt
);
248 s
->state
= STATE_WAITING
;
249 timer_set(&s
->timer
, CLOCK_SECOND
* 10);
250 handle_connection(s
);
251 } else if(s
!= NULL
) {
253 if(timer_expired(&s
->timer
)) {
259 memb_free(&conns
, s
);
260 webserver_log_file(&uip_conn
->ripaddr
, "reset (timeout)");
263 timer_restart(&s
->timer
);
265 handle_connection(s
);
270 /*---------------------------------------------------------------------------*/
274 tcp_listen(HTONS(80));
277 /*---------------------------------------------------------------------------*/