Added optional URL filtering code to the CFS web server contributed by Kajtar Zsolt...
[contiki-2.x.git] / apps / webserver / httpd-cfs.c
blobd3113ba8008aa1c4ef11e5c485c49568e603d53f
1 /*
2 * Copyright (c) 2004, Adam Dunkels.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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
27 * SUCH DAMAGE.
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 $
36 #include <stdio.h>
37 #ifndef HAVE_SNPRINTF
38 int snprintf(char *str, size_t size, const char *format, ...);
39 #endif /* HAVE_SNPRINTF */
40 #include <string.h>
42 #include "contiki-net.h"
44 #include "webserver.h"
45 #include "cfs/cfs.h"
46 #include "lib/petsciiconv.h"
47 #include "http-strings.h"
48 #include "urlconv.h"
50 #include "httpd-cfs.h"
52 #ifndef WEBSERVER_CONF_CFS_CONNS
53 #define CONNS 4
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
59 #define URLCONV 1
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);
70 #define ISO_nl 0x0a
71 #define ISO_space 0x20
72 #define ISO_period 0x2e
73 #define ISO_slash 0x2f
75 /*---------------------------------------------------------------------------*/
76 static
77 PT_THREAD(send_file(struct httpd_state *s))
79 PSOCK_BEGIN(&s->sout);
81 do {
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 */
86 if(s->len > 0) {
87 PSOCK_SEND(&s->sout, (uint8_t *)s->outputbuf, s->len);
88 } else {
89 break;
91 } while(s->len > 0);
93 PSOCK_END(&s->sout);
95 /*---------------------------------------------------------------------------*/
96 static
97 PT_THREAD(send_string(struct httpd_state *s, const char *str))
99 PSOCK_BEGIN(&s->sout);
101 SEND_STRING(&s->sout, str);
103 PSOCK_END(&s->sout);
105 /*---------------------------------------------------------------------------*/
106 static
107 PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr))
109 const char *ptr;
111 PSOCK_BEGIN(&s->sout);
113 SEND_STRING(&s->sout, statushdr);
115 ptr = strrchr(s->filename, ISO_period);
116 if(ptr == NULL) {
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;
128 } else {
129 ptr = http_content_type_binary;
131 SEND_STRING(&s->sout, ptr);
132 PSOCK_END(&s->sout);
134 /*---------------------------------------------------------------------------*/
135 static
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));
143 if(s->fd < 0) {
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));
149 if(s->fd < 0) {
150 PT_WAIT_THREAD(&s->outputpt,
151 send_string(s, "not found"));
152 uip_close();
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");
157 } else {
158 PT_WAIT_THREAD(&s->outputpt,
159 send_headers(s, http_header_200));
161 PT_WAIT_THREAD(&s->outputpt, send_file(s));
162 cfs_close(s->fd);
163 s->fd = -1;
164 PSOCK_CLOSE(&s->sout);
165 PT_END(&s->outputpt);
167 /*---------------------------------------------------------------------------*/
168 static
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);
184 #if URLCONV
185 s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
186 urlconv_tofilename(s->filename, s->inputbuf, sizeof(s->filename));
187 #else /* URLCONV */
188 if(s->inputbuf[1] == ISO_space) {
189 strncpy(s->filename, http_index_html, sizeof(s->filename));
190 } else {
191 s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
192 strncpy(s->filename, s->inputbuf, sizeof(s->filename));
194 #endif /* URLCONV */
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;
201 while(1) {
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);
211 PSOCK_END(&s->sin);
213 /*---------------------------------------------------------------------------*/
214 static void
215 handle_connection(struct httpd_state *s)
217 handle_input(s);
218 if(s->state == STATE_OUTPUT) {
219 handle_output(s);
222 /*---------------------------------------------------------------------------*/
223 void
224 httpd_appcall(void *state)
226 struct httpd_state *s = (struct httpd_state *)state;
228 if(uip_closed() || uip_aborted() || uip_timedout()) {
229 if(s != NULL) {
230 if(s->fd >= 0) {
231 cfs_close(s->fd);
232 s->fd = -1;
234 memb_free(&conns, s);
236 } else if(uip_connected()) {
237 s = (struct httpd_state *)memb_alloc(&conns);
238 if(s == NULL) {
239 uip_abort();
240 webserver_log_file(&uip_conn->ripaddr, "reset (no memory block)");
241 return;
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);
247 s->fd = -1;
248 s->state = STATE_WAITING;
249 timer_set(&s->timer, CLOCK_SECOND * 10);
250 handle_connection(s);
251 } else if(s != NULL) {
252 if(uip_poll()) {
253 if(timer_expired(&s->timer)) {
254 uip_abort();
255 if(s->fd >= 0) {
256 cfs_close(s->fd);
257 s->fd = -1;
259 memb_free(&conns, s);
260 webserver_log_file(&uip_conn->ripaddr, "reset (timeout)");
262 } else {
263 timer_restart(&s->timer);
265 handle_connection(s);
266 } else {
267 uip_abort();
270 /*---------------------------------------------------------------------------*/
271 void
272 httpd_init(void)
274 tcp_listen(HTONS(80));
275 memb_init(&conns);
277 /*---------------------------------------------------------------------------*/