blob: caadc02949d7891e9ed57ac7ce142e98ceef8cdb [file] [log] [blame]
adamdunkelsa2f3c422004-09-12 20:24:53 +00001/*
2 * Copyright (c) 2004, Adam Dunkels.
3 * All rights reserved.
4 *
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.
16 *
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.
28 *
29 * This file is part of the Contiki operating system.
30 *
31 * Author: Adam Dunkels <adam@sics.se>
32 *
ryohjic615a2d2007-06-02 07:32:05 +000033 * $Id: httpd.c,v 1.10 2007/06/02 07:32:06 ryohji Exp $
adamdunkelsa2f3c422004-09-12 20:24:53 +000034 */
adamdunkelsc7cc92a2003-05-28 05:21:49 +000035
adamdunkelsb63552d2004-09-12 07:15:00 +000036#include "contiki.h"
adamdunkelsc7cc92a2003-05-28 05:21:49 +000037#include "httpd.h"
38#include "httpd-fs.h"
adamdunkelsc7cc92a2003-05-28 05:21:49 +000039#include "httpd-cgi.h"
adamdunkelsf29d8882005-02-27 09:33:50 +000040#include "psock.h"
41#include "http-strings.h"
adamdunkelsc7cc92a2003-05-28 05:21:49 +000042
oliverschmidt52042b32004-12-22 09:36:10 +000043#include <string.h>
adamdunkelsc7cc92a2003-05-28 05:21:49 +000044
adamdunkelsb63552d2004-09-12 07:15:00 +000045#define STATE_WAITING 0
46#define STATE_OUTPUT 1
adamdunkelsc7cc92a2003-05-28 05:21:49 +000047
oliverschmidta900bff2005-02-23 21:18:05 +000048#define SEND_STRING(s, str) PSOCK_SEND(s, str, strlen(str))
adamdunkelsb63552d2004-09-12 07:15:00 +000049MEMB(conns, sizeof(struct httpd_state), 8);
adamdunkelsc7cc92a2003-05-28 05:21:49 +000050
adamdunkelsf29d8882005-02-27 09:33:50 +000051#define ISO_nl 0x0a
52#define ISO_space 0x20
53#define ISO_bang 0x21
54#define ISO_percent 0x25
55#define ISO_period 0x2e
56#define ISO_slash 0x2f
57#define ISO_colon 0x3a
58
59
adamdunkelsb63552d2004-09-12 07:15:00 +000060/*---------------------------------------------------------------------------*/
61static unsigned short
62generate(void *state)
adamdunkelsc7cc92a2003-05-28 05:21:49 +000063{
adamdunkelsb63552d2004-09-12 07:15:00 +000064 struct httpd_state *s = (struct httpd_state *)state;
65
66 if(s->file.len > uip_mss()) {
67 s->len = uip_mss();
68 } else {
69 s->len = s->file.len;
70 }
71 memcpy(uip_appdata, s->file.data, s->len);
adamdunkelsf1d19652003-06-30 20:42:49 +000072
adamdunkelsb63552d2004-09-12 07:15:00 +000073 return s->len;
74}
75/*---------------------------------------------------------------------------*/
76static
77PT_THREAD(send_file(struct httpd_state *s))
78{
oliverschmidta900bff2005-02-23 21:18:05 +000079 PSOCK_BEGIN(&s->sout);
adamdunkelsb63552d2004-09-12 07:15:00 +000080
81 do {
oliverschmidta900bff2005-02-23 21:18:05 +000082 PSOCK_GENERATOR_SEND(&s->sout, generate, s);
adamdunkelsb63552d2004-09-12 07:15:00 +000083 s->file.len -= s->len;
84 s->file.data += s->len;
85 } while(s->file.len > 0);
86
oliverschmidta900bff2005-02-23 21:18:05 +000087 PSOCK_END(&s->sout);
adamdunkelsb63552d2004-09-12 07:15:00 +000088}
89/*---------------------------------------------------------------------------*/
adamdunkelsf29d8882005-02-27 09:33:50 +000090static
91PT_THREAD(send_part_of_file(struct httpd_state *s))
92{
93 PSOCK_BEGIN(&s->sout);
94
95 PSOCK_SEND(&s->sout, s->file.data, s->len);
96
97 PSOCK_END(&s->sout);
98}
99/*---------------------------------------------------------------------------*/
adamdunkelsb63552d2004-09-12 07:15:00 +0000100static void
101next_scriptstate(struct httpd_state *s)
102{
103 char *p;
adamdunkelsf29d8882005-02-27 09:33:50 +0000104 p = strchr(s->scriptptr, ISO_nl) + 1;
adamdunkelsb63552d2004-09-12 07:15:00 +0000105 s->scriptlen -= (unsigned short)(p - s->scriptptr);
106 s->scriptptr = p;
107}
108/*---------------------------------------------------------------------------*/
109static
110PT_THREAD(handle_script(struct httpd_state *s))
111{
adamdunkelsf29d8882005-02-27 09:33:50 +0000112 char *ptr;
113
adamdunkelsb63552d2004-09-12 07:15:00 +0000114 PT_BEGIN(&s->scriptpt);
115
adamdunkelsb63552d2004-09-12 07:15:00 +0000116
adamdunkelsf29d8882005-02-27 09:33:50 +0000117 while(s->file.len > 0) {
118
119 /* Check if we should start executing a script. */
120 if(*s->file.data == ISO_percent &&
121 *(s->file.data + 1) == ISO_bang) {
122 s->scriptptr = s->file.data + 3;
123 s->scriptlen = s->file.len - 3;
124 if(*(s->scriptptr - 1) == ISO_colon) {
125 httpd_fs_open(s->scriptptr + 1, &s->file);
126 PT_WAIT_THREAD(&s->scriptpt, send_file(s));
127 } else {
128 PT_WAIT_THREAD(&s->scriptpt,
129 httpd_cgi(s->scriptptr)(s, s->scriptptr));
130 }
adamdunkelsb63552d2004-09-12 07:15:00 +0000131 next_scriptstate(s);
adamdunkelsf29d8882005-02-27 09:33:50 +0000132
133 /* The script is over, so we reset the pointers and continue
134 sending the rest of the file. */
135 s->file.data = s->scriptptr;
136 s->file.len = s->scriptlen;
137 } else {
138 /* See if we find the start of script marker in the block of HTML
139 to be sent. */
140
141 if(s->file.len > uip_mss()) {
142 s->len = uip_mss();
143 } else {
144 s->len = s->file.len;
145 }
146
147 if(*s->file.data == ISO_percent) {
148 ptr = strchr(s->file.data + 1, ISO_percent);
149 } else {
150 ptr = strchr(s->file.data, ISO_percent);
151 }
152 if(ptr != NULL &&
153 ptr != s->file.data) {
154 s->len = (int)(ptr - s->file.data);
155 if(s->len >= uip_mss()) {
156 s->len = uip_mss();
157 }
158 }
159 PT_WAIT_THREAD(&s->scriptpt, send_part_of_file(s));
160 s->file.data += s->len;
161 s->file.len -= s->len;
162
adamdunkelsc7cc92a2003-05-28 05:21:49 +0000163 }
164 }
adamdunkelsb63552d2004-09-12 07:15:00 +0000165
166 PT_END(&s->scriptpt);
167}
168/*---------------------------------------------------------------------------*/
169static
adamdunkelsf29d8882005-02-27 09:33:50 +0000170PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr))
adamdunkelsb63552d2004-09-12 07:15:00 +0000171{
ryohjic615a2d2007-06-02 07:32:05 +0000172 static char *ptr;
adamdunkelsf1d19652003-06-30 20:42:49 +0000173
oliverschmidta900bff2005-02-23 21:18:05 +0000174 PSOCK_BEGIN(&s->sout);
adamdunkelsb63552d2004-09-12 07:15:00 +0000175
176 SEND_STRING(&s->sout, statushdr);
adamdunkelsb63552d2004-09-12 07:15:00 +0000177
adamdunkelsf29d8882005-02-27 09:33:50 +0000178 ptr = strrchr(s->filename, ISO_period);
adamdunkelsb63552d2004-09-12 07:15:00 +0000179 if(ptr == NULL) {
adamdunkelsf29d8882005-02-27 09:33:50 +0000180 SEND_STRING(&s->sout, http_content_type_binary);
181 } else if(strncmp(http_html, ptr, 5) == 0 ||
182 strncmp(http_shtml, ptr, 6) == 0) {
183 SEND_STRING(&s->sout, http_content_type_html);
184 } else if(strncmp(http_css, ptr, 4) == 0) {
185 SEND_STRING(&s->sout, http_content_type_css);
186 } else if(strncmp(http_png, ptr, 4) == 0) {
187 SEND_STRING(&s->sout, http_content_type_png);
188 } else if(strncmp(http_gif, ptr, 4) == 0) {
189 SEND_STRING(&s->sout, http_content_type_gif);
190 } else if(strncmp(http_jpg, ptr, 4) == 0) {
191 SEND_STRING(&s->sout, http_content_type_jpg);
adamdunkelsb63552d2004-09-12 07:15:00 +0000192 } else {
adamdunkelsf29d8882005-02-27 09:33:50 +0000193 SEND_STRING(&s->sout, http_content_type_plain);
adamdunkelsb63552d2004-09-12 07:15:00 +0000194 }
oliverschmidta900bff2005-02-23 21:18:05 +0000195 PSOCK_END(&s->sout);
adamdunkelsb63552d2004-09-12 07:15:00 +0000196}
197/*---------------------------------------------------------------------------*/
198static
199PT_THREAD(handle_output(struct httpd_state *s))
200{
adamdunkelsf29d8882005-02-27 09:33:50 +0000201 char *ptr;
202
adamdunkelsb63552d2004-09-12 07:15:00 +0000203 PT_BEGIN(&s->outputpt);
204
205 if(!httpd_fs_open(s->filename, &s->file)) {
adamdunkelsf29d8882005-02-27 09:33:50 +0000206 httpd_fs_open(http_404_html, &s->file);
adamdunkelsb63552d2004-09-12 07:15:00 +0000207 PT_WAIT_THREAD(&s->outputpt,
adamdunkelsf29d8882005-02-27 09:33:50 +0000208 send_headers(s,
209 http_header_404));
adamdunkelsb63552d2004-09-12 07:15:00 +0000210 PT_WAIT_THREAD(&s->outputpt,
211 send_file(s));
212 } else {
213 PT_WAIT_THREAD(&s->outputpt,
adamdunkelsf29d8882005-02-27 09:33:50 +0000214 send_headers(s,
215 http_header_200));
216 ptr = strchr(s->filename, ISO_period);
217 if(ptr != NULL && strncmp(ptr, http_shtml, 6) == 0) {
adamdunkelsb63552d2004-09-12 07:15:00 +0000218 PT_INIT(&s->scriptpt);
219 PT_WAIT_THREAD(&s->outputpt, handle_script(s));
220 } else {
221 PT_WAIT_THREAD(&s->outputpt,
222 send_file(s));
223 }
224 }
oliverschmidta900bff2005-02-23 21:18:05 +0000225 PSOCK_CLOSE(&s->sout);
adamdunkelsb63552d2004-09-12 07:15:00 +0000226 PT_END(&s->outputpt);
227}
228/*---------------------------------------------------------------------------*/
229static
230PT_THREAD(handle_input(struct httpd_state *s))
231{
oliverschmidta900bff2005-02-23 21:18:05 +0000232 PSOCK_BEGIN(&s->sin);
adamdunkelsb63552d2004-09-12 07:15:00 +0000233
adamdunkelsf29d8882005-02-27 09:33:50 +0000234 PSOCK_READTO(&s->sin, ISO_space);
adamdunkelsb63552d2004-09-12 07:15:00 +0000235
236
adamdunkelsf29d8882005-02-27 09:33:50 +0000237 if(strncmp(s->inputbuf, http_get, 4) != 0) {
oliverschmidta900bff2005-02-23 21:18:05 +0000238 PSOCK_CLOSE_EXIT(&s->sin);
adamdunkelsb63552d2004-09-12 07:15:00 +0000239 }
adamdunkelsf29d8882005-02-27 09:33:50 +0000240 PSOCK_READTO(&s->sin, ISO_space);
adamdunkelsb63552d2004-09-12 07:15:00 +0000241
adamdunkelsf29d8882005-02-27 09:33:50 +0000242 if(s->inputbuf[0] != ISO_slash) {
oliverschmidta900bff2005-02-23 21:18:05 +0000243 PSOCK_CLOSE_EXIT(&s->sin);
adamdunkelsb63552d2004-09-12 07:15:00 +0000244 }
245
adamdunkelsf29d8882005-02-27 09:33:50 +0000246 if(s->inputbuf[1] == ISO_space) {
247 strncpy(s->filename, http_index_html, sizeof(s->filename));
adamdunkelsb63552d2004-09-12 07:15:00 +0000248 } else {
oliverschmidta900bff2005-02-23 21:18:05 +0000249 s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
adamdunkelsb63552d2004-09-12 07:15:00 +0000250 strncpy(s->filename, &s->inputbuf[0], sizeof(s->filename));
251 }
252
adamdunkelsf29d8882005-02-27 09:33:50 +0000253 httpd_log_file(uip_conn->ripaddr, s->filename);
adamdunkelsb63552d2004-09-12 07:15:00 +0000254
255 s->state = STATE_OUTPUT;
256
257 while(1) {
adamdunkelsf29d8882005-02-27 09:33:50 +0000258 PSOCK_READTO(&s->sin, ISO_nl);
adamdunkelsb63552d2004-09-12 07:15:00 +0000259
adamdunkelsf29d8882005-02-27 09:33:50 +0000260 if(strncmp(s->inputbuf, http_referer, 8) == 0) {
oliverschmidta900bff2005-02-23 21:18:05 +0000261 s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
adamdunkelsf29d8882005-02-27 09:33:50 +0000262 httpd_log(&s->inputbuf[9]);
adamdunkelsb63552d2004-09-12 07:15:00 +0000263 }
adamdunkelsf1d19652003-06-30 20:42:49 +0000264 }
265
oliverschmidta900bff2005-02-23 21:18:05 +0000266 PSOCK_END(&s->sin);
adamdunkelsc7cc92a2003-05-28 05:21:49 +0000267}
adamdunkelsb63552d2004-09-12 07:15:00 +0000268/*---------------------------------------------------------------------------*/
adamdunkelsc7cc92a2003-05-28 05:21:49 +0000269static void
adamdunkelsb63552d2004-09-12 07:15:00 +0000270handle_connection(struct httpd_state *s)
adamdunkelsc7cc92a2003-05-28 05:21:49 +0000271{
adamdunkelsb63552d2004-09-12 07:15:00 +0000272 handle_input(s);
273 if(s->state == STATE_OUTPUT) {
274 handle_output(s);
275 }
adamdunkelsc7cc92a2003-05-28 05:21:49 +0000276}
adamdunkelsb63552d2004-09-12 07:15:00 +0000277/*---------------------------------------------------------------------------*/
278void
279httpd_appcall(void *state)
280{
281 struct httpd_state *s = (struct httpd_state *)state;
282
283 if(uip_closed() || uip_aborted() || uip_timedout()) {
284 if(s != NULL) {
285 memb_free(&conns, s);
286 }
287 } else if(uip_connected()) {
288 s = (struct httpd_state *)memb_alloc(&conns);
289 if(s == NULL) {
290 uip_abort();
291 return;
292 }
293 tcp_markconn(uip_conn, s);
oliverschmidta900bff2005-02-23 21:18:05 +0000294 PSOCK_INIT(&s->sin, s->inputbuf, sizeof(s->inputbuf) - 1);
295 PSOCK_INIT(&s->sout, s->inputbuf, sizeof(s->inputbuf) - 1);
adamdunkelsb63552d2004-09-12 07:15:00 +0000296 PT_INIT(&s->outputpt);
297 s->state = STATE_WAITING;
adamdunkelsf29d8882005-02-27 09:33:50 +0000298 timer_set(&s->timer, CLOCK_SECOND * 100);
adamdunkelsb63552d2004-09-12 07:15:00 +0000299 handle_connection(s);
300 } else if(s != NULL) {
301 if(uip_poll()) {
adamdunkelsf29d8882005-02-27 09:33:50 +0000302
adamdunkelsb63552d2004-09-12 07:15:00 +0000303 if(timer_expired(&s->timer)) {
304 uip_abort();
adamdunkelsf29d8882005-02-27 09:33:50 +0000305 memb_free(&conns, s);
adamdunkelsb63552d2004-09-12 07:15:00 +0000306 }
adamdunkelsf29d8882005-02-27 09:33:50 +0000307 }
308 timer_restart(&s->timer);
adamdunkelsb63552d2004-09-12 07:15:00 +0000309 handle_connection(s);
310 } else {
311 uip_abort();
312 }
313}
314/*---------------------------------------------------------------------------*/
adamdunkelsc7cc92a2003-05-28 05:21:49 +0000315void
316httpd_init(void)
317{
adamdunkelsb63552d2004-09-12 07:15:00 +0000318 tcp_listen(HTONS(80));
319 memb_init(&conns);
adamdunkelsc7cc92a2003-05-28 05:21:49 +0000320}
adamdunkelsb63552d2004-09-12 07:15:00 +0000321/*---------------------------------------------------------------------------*/