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.16 2010/04/06 11:49: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"
49 #include "httpd-cfs.h"
51 #ifndef WEBSERVER_CONF_CFS_CONNS
53 #else /* WEBSERVER_CONF_CFS_CONNS */
54 #define CONNS WEBSERVER_CONF_CFS_CONNS
55 #endif /* WEBSERVER_CONF_CFS_CONNS */
57 #define STATE_WAITING 0
58 #define STATE_OUTPUT 1
60 #define SEND_STRING(s, str) PSOCK_SEND(s, (uint8_t *)str, strlen(str))
61 MEMB(conns
, struct httpd_state
, CONNS
);
64 #define ISO_space 0x20
65 #define ISO_period 0x2e
66 #define ISO_slash 0x2f
68 /*---------------------------------------------------------------------------*/
70 PT_THREAD(send_file(struct httpd_state
*s
))
72 PSOCK_BEGIN(&s
->sout
);
75 /* Read data from file system into buffer */
76 s
->len
= cfs_read(s
->fd
, s
->outputbuf
, sizeof(s
->outputbuf
));
78 /* If there is data in the buffer, send it */
80 PSOCK_SEND(&s
->sout
, (uint8_t *)s
->outputbuf
, s
->len
);
88 /*---------------------------------------------------------------------------*/
90 PT_THREAD(send_string(struct httpd_state
*s
, const char *str
))
92 PSOCK_BEGIN(&s
->sout
);
94 SEND_STRING(&s
->sout
, str
);
98 /*---------------------------------------------------------------------------*/
100 PT_THREAD(send_headers(struct httpd_state
*s
, const char *statushdr
))
104 PSOCK_BEGIN(&s
->sout
);
106 SEND_STRING(&s
->sout
, statushdr
);
108 ptr
= strrchr(s
->filename
, ISO_period
);
110 ptr
= http_content_type_plain
;
111 } else if(strncmp(http_html
, ptr
, 5) == 0) {
112 ptr
= http_content_type_html
;
113 } else if(strncmp(http_css
, ptr
, 4) == 0) {
114 ptr
= http_content_type_css
;
115 } else if(strncmp(http_png
, ptr
, 4) == 0) {
116 ptr
= http_content_type_png
;
117 } else if(strncmp(http_jpg
, ptr
, 4) == 0) {
118 ptr
= http_content_type_jpg
;
120 ptr
= http_content_type_binary
;
122 SEND_STRING(&s
->sout
, ptr
);
125 /*---------------------------------------------------------------------------*/
127 PT_THREAD(handle_output(struct httpd_state
*s
))
129 PT_BEGIN(&s
->outputpt
);
131 petsciiconv_topetscii(s
->filename
, sizeof(s
->filename
));
132 s
->fd
= cfs_open(s
->filename
, CFS_READ
);
133 petsciiconv_toascii(s
->filename
, sizeof(s
->filename
));
135 strcpy(s
->filename
, "notfound.html");
136 s
->fd
= cfs_open(s
->filename
, CFS_READ
);
137 petsciiconv_toascii(s
->filename
, sizeof(s
->filename
));
139 PT_WAIT_THREAD(&s
->outputpt
,
140 send_headers(s
, http_header_404
));
141 PT_WAIT_THREAD(&s
->outputpt
,
142 send_string(s
, "not found"));
144 webserver_log_file(&uip_conn
->ripaddr
, "404 (no notfound.html)");
145 PT_EXIT(&s
->outputpt
);
147 PT_WAIT_THREAD(&s
->outputpt
,
148 send_headers(s
, http_header_404
));
149 webserver_log_file(&uip_conn
->ripaddr
, "404 - notfound.html");
151 PT_WAIT_THREAD(&s
->outputpt
,
152 send_headers(s
, http_header_200
));
154 PT_WAIT_THREAD(&s
->outputpt
, send_file(s
));
157 PSOCK_CLOSE(&s
->sout
);
158 PT_END(&s
->outputpt
);
160 /*---------------------------------------------------------------------------*/
162 PT_THREAD(handle_input(struct httpd_state
*s
))
164 PSOCK_BEGIN(&s
->sin
);
166 PSOCK_READTO(&s
->sin
, ISO_space
);
168 if(strncmp(s
->inputbuf
, http_get
, 4) != 0) {
169 PSOCK_CLOSE_EXIT(&s
->sin
);
171 PSOCK_READTO(&s
->sin
, ISO_space
);
173 if(s
->inputbuf
[0] != ISO_slash
) {
174 PSOCK_CLOSE_EXIT(&s
->sin
);
177 if(s
->inputbuf
[1] == ISO_space
) {
178 strncpy(s
->filename
, &http_index_html
[1], sizeof(s
->filename
));
180 s
->inputbuf
[PSOCK_DATALEN(&s
->sin
) - 1] = 0;
181 strncpy(s
->filename
, &s
->inputbuf
[1], sizeof(s
->filename
));
184 petsciiconv_topetscii(s
->filename
, sizeof(s
->filename
));
185 webserver_log_file(&uip_conn
->ripaddr
, s
->filename
);
186 petsciiconv_toascii(s
->filename
, sizeof(s
->filename
));
187 s
->state
= STATE_OUTPUT
;
190 PSOCK_READTO(&s
->sin
, ISO_nl
);
192 if(strncmp(s
->inputbuf
, http_referer
, 8) == 0) {
193 s
->inputbuf
[PSOCK_DATALEN(&s
->sin
) - 2] = 0;
194 petsciiconv_topetscii(s
->inputbuf
, PSOCK_DATALEN(&s
->sin
) - 2);
195 webserver_log(s
->inputbuf
);
201 /*---------------------------------------------------------------------------*/
203 handle_connection(struct httpd_state
*s
)
206 if(s
->state
== STATE_OUTPUT
) {
210 /*---------------------------------------------------------------------------*/
212 httpd_appcall(void *state
)
214 struct httpd_state
*s
= (struct httpd_state
*)state
;
216 if(uip_closed() || uip_aborted() || uip_timedout()) {
222 memb_free(&conns
, s
);
224 } else if(uip_connected()) {
225 s
= (struct httpd_state
*)memb_alloc(&conns
);
228 webserver_log_file(&uip_conn
->ripaddr
, "reset (no memory block)");
231 tcp_markconn(uip_conn
, s
);
232 PSOCK_INIT(&s
->sin
, (uint8_t *)s
->inputbuf
, sizeof(s
->inputbuf
) - 1);
233 PSOCK_INIT(&s
->sout
, (uint8_t *)s
->inputbuf
, sizeof(s
->inputbuf
) - 1);
234 PT_INIT(&s
->outputpt
);
236 s
->state
= STATE_WAITING
;
237 timer_set(&s
->timer
, CLOCK_SECOND
* 10);
238 handle_connection(s
);
239 } else if(s
!= NULL
) {
241 if(timer_expired(&s
->timer
)) {
247 memb_free(&conns
, s
);
248 webserver_log_file(&uip_conn
->ripaddr
, "reset (timeout)");
251 timer_restart(&s
->timer
);
253 handle_connection(s
);
258 /*---------------------------------------------------------------------------*/
262 tcp_listen(HTONS(80));
265 /*---------------------------------------------------------------------------*/