Reduced code size by reducing the SEND_STRING call sites.
[contiki-2.x.git] / apps / webserver / httpd.c
blob69099fbaac0a73cfeb4f81502e77145eb2e7da5e
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.13 2010/04/06 11:49:47 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 httpd_fs_open(http_404_html, &s->file);
224 PT_WAIT_THREAD(&s->outputpt,
225 send_headers(s,
226 http_header_404));
227 PT_WAIT_THREAD(&s->outputpt,
228 send_file(s));
229 } else {
230 PT_WAIT_THREAD(&s->outputpt,
231 send_headers(s,
232 http_header_200));
233 ptr = strchr(s->filename, ISO_period);
234 if(ptr != NULL && strncmp(ptr, http_shtml, 6) == 0) {
235 PT_INIT(&s->scriptpt);
236 PT_WAIT_THREAD(&s->outputpt, handle_script(s));
237 } else {
238 PT_WAIT_THREAD(&s->outputpt,
239 send_file(s));
242 PSOCK_CLOSE(&s->sout);
243 PT_END(&s->outputpt);
245 /*---------------------------------------------------------------------------*/
246 static
247 PT_THREAD(handle_input(struct httpd_state *s))
249 PSOCK_BEGIN(&s->sin);
251 PSOCK_READTO(&s->sin, ISO_space);
253 if(strncmp(s->inputbuf, http_get, 4) != 0) {
254 PSOCK_CLOSE_EXIT(&s->sin);
256 PSOCK_READTO(&s->sin, ISO_space);
258 if(s->inputbuf[0] != ISO_slash) {
259 PSOCK_CLOSE_EXIT(&s->sin);
262 if(s->inputbuf[1] == ISO_space) {
263 strncpy(s->filename, http_index_html, sizeof(s->filename));
264 } else {
265 s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
266 strncpy(s->filename, &s->inputbuf[0], sizeof(s->filename));
269 webserver_log_file(&uip_conn->ripaddr, s->filename);
271 s->state = STATE_OUTPUT;
273 while(1) {
274 PSOCK_READTO(&s->sin, ISO_nl);
276 if(strncmp(s->inputbuf, http_referer, 8) == 0) {
277 s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
278 petsciiconv_topetscii(s->inputbuf, PSOCK_DATALEN(&s->sin) - 2);
279 webserver_log(s->inputbuf);
283 PSOCK_END(&s->sin);
285 /*---------------------------------------------------------------------------*/
286 static void
287 handle_connection(struct httpd_state *s)
289 handle_input(s);
290 if(s->state == STATE_OUTPUT) {
291 handle_output(s);
294 /*---------------------------------------------------------------------------*/
295 void
296 httpd_appcall(void *state)
298 struct httpd_state *s = (struct httpd_state *)state;
300 if(uip_closed() || uip_aborted() || uip_timedout()) {
301 if(s != NULL) {
302 memb_free(&conns, s);
304 } else if(uip_connected()) {
305 s = (struct httpd_state *)memb_alloc(&conns);
306 if(s == NULL) {
307 uip_abort();
308 return;
310 tcp_markconn(uip_conn, s);
311 PSOCK_INIT(&s->sin, (uint8_t *)s->inputbuf, sizeof(s->inputbuf) - 1);
312 PSOCK_INIT(&s->sout, (uint8_t *)s->inputbuf, sizeof(s->inputbuf) - 1);
313 PT_INIT(&s->outputpt);
314 s->state = STATE_WAITING;
315 /* timer_set(&s->timer, CLOCK_SECOND * 100);*/
316 s->timer = 0;
317 handle_connection(s);
318 } else if(s != NULL) {
319 if(uip_poll()) {
320 ++s->timer;
321 if(s->timer >= 20) {
322 uip_abort();
323 memb_free(&conns, s);
325 } else {
326 s->timer = 0;
328 handle_connection(s);
329 } else {
330 uip_abort();
333 /*---------------------------------------------------------------------------*/
334 void
335 httpd_init(void)
337 tcp_listen(HTONS(80));
338 memb_init(&conns);
339 httpd_cgi_init();
341 #if UIP_CONF_IPV6
342 /*---------------------------------------------------------------------------*/
343 uint8_t
344 httpd_sprint_ip6(uip_ip6addr_t addr, char * result)
346 unsigned char i = 0;
347 unsigned char zerocnt = 0;
348 unsigned char numprinted = 0;
349 char * starting = result;
351 *result++='[';
352 while (numprinted < 8) {
353 if ((addr.u16[i] == 0) && (zerocnt == 0)) {
354 while(addr.u16[zerocnt + i] == 0) zerocnt++;
355 if (zerocnt == 1) {
356 *result++ = '0';
357 numprinted++;
358 break;
360 i += zerocnt;
361 numprinted += zerocnt;
362 } else {
363 result += sprintf(result, "%x", (unsigned int)(ntohs(addr.u16[i])));
364 i++;
365 numprinted++;
367 if (numprinted != 8) *result++ = ':';
369 *result++=']';
370 *result=0;
371 return (result - starting);
373 #endif /* UIP_CONF_IPV6 */
374 /*---------------------------------------------------------------------------*/