Search for last '.' just like in send_headers().
[contiki-2.x.git] / apps / webserver / httpd.c
blob27412cc2589cd49f3aef591c6af0bb57654f6897
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.c,v 1.15 2010/04/06 20:16:25 oliverschmidt Exp $
36 #include <stdio.h>
37 #include <string.h>
39 #include "contiki-net.h"
41 #include "webserver.h"
42 #include "httpd-fs.h"
43 #include "httpd-cgi.h"
44 #include "lib/petsciiconv.h"
45 #include "http-strings.h"
47 #include "httpd.h"
49 #ifndef WEBSERVER_CONF_CGI_CONNS
50 #define CONNS 4
51 #else /* WEBSERVER_CONF_CGI_CONNS */
52 #define CONNS WEBSERVER_CONF_CGI_CONNS
53 #endif /* WEBSERVER_CONF_CGI_CONNS */
55 #define STATE_WAITING 0
56 #define STATE_OUTPUT 1
58 #define SEND_STRING(s, str) PSOCK_SEND(s, (uint8_t *)str, (unsigned int)strlen(str))
59 MEMB(conns, struct httpd_state, CONNS);
61 #define ISO_nl 0x0a
62 #define ISO_space 0x20
63 #define ISO_bang 0x21
64 #define ISO_percent 0x25
65 #define ISO_period 0x2e
66 #define ISO_slash 0x2f
67 #define ISO_colon 0x3a
69 /*---------------------------------------------------------------------------*/
70 static unsigned short
71 generate(void *state)
73 struct httpd_state *s = (struct httpd_state *)state;
75 if(s->file.len > uip_mss()) {
76 s->len = uip_mss();
77 } else {
78 s->len = s->file.len;
80 memcpy(uip_appdata, s->file.data, s->len);
82 return s->len;
84 /*---------------------------------------------------------------------------*/
85 static
86 PT_THREAD(send_file(struct httpd_state *s))
88 PSOCK_BEGIN(&s->sout);
90 do {
91 PSOCK_GENERATOR_SEND(&s->sout, generate, s);
92 s->file.len -= s->len;
93 s->file.data += s->len;
94 } while(s->file.len > 0);
96 PSOCK_END(&s->sout);
98 /*---------------------------------------------------------------------------*/
99 static
100 PT_THREAD(send_part_of_file(struct httpd_state *s))
102 PSOCK_BEGIN(&s->sout);
104 PSOCK_SEND(&s->sout, (uint8_t *)s->file.data, s->len);
106 PSOCK_END(&s->sout);
108 /*---------------------------------------------------------------------------*/
109 static void
110 next_scriptstate(struct httpd_state *s)
112 char *p;
114 if((p = strchr(s->scriptptr, ISO_nl)) != NULL) {
115 p += 1;
116 s->scriptlen -= (unsigned short)(p - s->scriptptr);
117 s->scriptptr = p;
118 } else {
119 s->scriptlen = 0;
121 /* char *p;
122 p = strchr(s->scriptptr, ISO_nl) + 1;
123 s->scriptlen -= (unsigned short)(p - s->scriptptr);
124 s->scriptptr = p;*/
126 /*---------------------------------------------------------------------------*/
127 static
128 PT_THREAD(handle_script(struct httpd_state *s))
130 char *ptr;
132 PT_BEGIN(&s->scriptpt);
134 while(s->file.len > 0) {
136 /* Check if we should start executing a script. */
137 if(*s->file.data == ISO_percent &&
138 *(s->file.data + 1) == ISO_bang) {
139 s->scriptptr = s->file.data + 3;
140 s->scriptlen = s->file.len - 3;
141 if(*(s->scriptptr - 1) == ISO_colon) {
142 httpd_fs_open(s->scriptptr + 1, &s->file);
143 PT_WAIT_THREAD(&s->scriptpt, send_file(s));
144 } else {
145 PT_WAIT_THREAD(&s->scriptpt,
146 httpd_cgi(s->scriptptr)(s, s->scriptptr));
148 next_scriptstate(s);
150 /* The script is over, so we reset the pointers and continue
151 sending the rest of the file. */
152 s->file.data = s->scriptptr;
153 s->file.len = s->scriptlen;
154 } else {
155 /* See if we find the start of script marker in the block of HTML
156 to be sent. */
158 if(s->file.len > uip_mss()) {
159 s->len = uip_mss();
160 } else {
161 s->len = s->file.len;
164 if(*s->file.data == ISO_percent) {
165 ptr = strchr(s->file.data + 1, ISO_percent);
166 } else {
167 ptr = strchr(s->file.data, ISO_percent);
169 if(ptr != NULL &&
170 ptr != s->file.data) {
171 s->len = (int)(ptr - s->file.data);
172 if(s->len >= uip_mss()) {
173 s->len = uip_mss();
176 PT_WAIT_THREAD(&s->scriptpt, send_part_of_file(s));
177 s->file.data += s->len;
178 s->file.len -= s->len;
182 PT_END(&s->scriptpt);
184 /*---------------------------------------------------------------------------*/
185 static
186 PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr))
188 const char *ptr;
190 PSOCK_BEGIN(&s->sout);
192 SEND_STRING(&s->sout, statushdr);
194 ptr = strrchr(s->filename, ISO_period);
195 if(ptr == NULL) {
196 ptr = http_content_type_binary;
197 } else if(strncmp(http_html, ptr, 5) == 0 ||
198 strncmp(http_shtml, ptr, 6) == 0) {
199 ptr = http_content_type_html;
200 } else if(strncmp(http_css, ptr, 4) == 0) {
201 ptr = http_content_type_css;
202 } else if(strncmp(http_png, ptr, 4) == 0) {
203 ptr = http_content_type_png;
204 } else if(strncmp(http_gif, ptr, 4) == 0) {
205 ptr = http_content_type_gif;
206 } else if(strncmp(http_jpg, ptr, 4) == 0) {
207 ptr = http_content_type_jpg;
208 } else {
209 ptr = http_content_type_plain;
211 SEND_STRING(&s->sout, ptr);
212 PSOCK_END(&s->sout);
214 /*---------------------------------------------------------------------------*/
215 static
216 PT_THREAD(handle_output(struct httpd_state *s))
218 char *ptr;
220 PT_BEGIN(&s->outputpt);
222 if(!httpd_fs_open(s->filename, &s->file)) {
223 strcpy(s->filename, http_404_html);
224 httpd_fs_open(s->filename, &s->file);
225 PT_WAIT_THREAD(&s->outputpt,
226 send_headers(s,
227 http_header_404));
228 PT_WAIT_THREAD(&s->outputpt,
229 send_file(s));
230 } else {
231 PT_WAIT_THREAD(&s->outputpt,
232 send_headers(s,
233 http_header_200));
234 ptr = strrchr(s->filename, ISO_period);
235 if(ptr != NULL && strncmp(ptr, http_shtml, 6) == 0) {
236 PT_INIT(&s->scriptpt);
237 PT_WAIT_THREAD(&s->outputpt, handle_script(s));
238 } else {
239 PT_WAIT_THREAD(&s->outputpt,
240 send_file(s));
243 PSOCK_CLOSE(&s->sout);
244 PT_END(&s->outputpt);
246 /*---------------------------------------------------------------------------*/
247 static
248 PT_THREAD(handle_input(struct httpd_state *s))
250 PSOCK_BEGIN(&s->sin);
252 PSOCK_READTO(&s->sin, ISO_space);
254 if(strncmp(s->inputbuf, http_get, 4) != 0) {
255 PSOCK_CLOSE_EXIT(&s->sin);
257 PSOCK_READTO(&s->sin, ISO_space);
259 if(s->inputbuf[0] != ISO_slash) {
260 PSOCK_CLOSE_EXIT(&s->sin);
263 if(s->inputbuf[1] == ISO_space) {
264 strncpy(s->filename, http_index_html, sizeof(s->filename));
265 } else {
266 s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
267 strncpy(s->filename, &s->inputbuf[0], sizeof(s->filename));
270 webserver_log_file(&uip_conn->ripaddr, s->filename);
272 s->state = STATE_OUTPUT;
274 while(1) {
275 PSOCK_READTO(&s->sin, ISO_nl);
277 if(strncmp(s->inputbuf, http_referer, 8) == 0) {
278 s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
279 petsciiconv_topetscii(s->inputbuf, PSOCK_DATALEN(&s->sin) - 2);
280 webserver_log(s->inputbuf);
284 PSOCK_END(&s->sin);
286 /*---------------------------------------------------------------------------*/
287 static void
288 handle_connection(struct httpd_state *s)
290 handle_input(s);
291 if(s->state == STATE_OUTPUT) {
292 handle_output(s);
295 /*---------------------------------------------------------------------------*/
296 void
297 httpd_appcall(void *state)
299 struct httpd_state *s = (struct httpd_state *)state;
301 if(uip_closed() || uip_aborted() || uip_timedout()) {
302 if(s != NULL) {
303 memb_free(&conns, s);
305 } else if(uip_connected()) {
306 s = (struct httpd_state *)memb_alloc(&conns);
307 if(s == NULL) {
308 uip_abort();
309 return;
311 tcp_markconn(uip_conn, s);
312 PSOCK_INIT(&s->sin, (uint8_t *)s->inputbuf, sizeof(s->inputbuf) - 1);
313 PSOCK_INIT(&s->sout, (uint8_t *)s->inputbuf, sizeof(s->inputbuf) - 1);
314 PT_INIT(&s->outputpt);
315 s->state = STATE_WAITING;
316 /* timer_set(&s->timer, CLOCK_SECOND * 100);*/
317 s->timer = 0;
318 handle_connection(s);
319 } else if(s != NULL) {
320 if(uip_poll()) {
321 ++s->timer;
322 if(s->timer >= 20) {
323 uip_abort();
324 memb_free(&conns, s);
326 } else {
327 s->timer = 0;
329 handle_connection(s);
330 } else {
331 uip_abort();
334 /*---------------------------------------------------------------------------*/
335 void
336 httpd_init(void)
338 tcp_listen(HTONS(80));
339 memb_init(&conns);
340 httpd_cgi_init();
342 #if UIP_CONF_IPV6
343 /*---------------------------------------------------------------------------*/
344 uint8_t
345 httpd_sprint_ip6(uip_ip6addr_t addr, char * result)
347 unsigned char i = 0;
348 unsigned char zerocnt = 0;
349 unsigned char numprinted = 0;
350 char * starting = result;
352 *result++='[';
353 while (numprinted < 8) {
354 if ((addr.u16[i] == 0) && (zerocnt == 0)) {
355 while(addr.u16[zerocnt + i] == 0) zerocnt++;
356 if (zerocnt == 1) {
357 *result++ = '0';
358 numprinted++;
359 break;
361 i += zerocnt;
362 numprinted += zerocnt;
363 } else {
364 result += sprintf(result, "%x", (unsigned int)(ntohs(addr.u16[i])));
365 i++;
366 numprinted++;
368 if (numprinted != 8) *result++ = ':';
370 *result++=']';
371 *result=0;
372 return (result - starting);
374 #endif /* UIP_CONF_IPV6 */
375 /*---------------------------------------------------------------------------*/