38 #include "contiki-net.h"
41 #include "webserver.h"
44 #if WEBSERVER_CONF_CGI
45 #include "httpd-cgi.h"
51 #include "cfs-coffee-arch.h"
61 #define STATE_WAITING 0
62 #define STATE_OUTPUT 1
64 MEMB(conns,
struct httpd_state, WEBSERVER_CONF_CONNS);
69 #define ISO_space 0x20
71 #define ISO_percent 0x25
72 #define ISO_period 0x2e
73 #define ISO_slash 0x2f
74 #define ISO_colon 0x3a
75 #define ISO_qmark 0x3f
82 struct httpd_state *s = (
struct httpd_state *)state;
94 PT_THREAD(send_file(
struct httpd_state *s))
99 s->file.len -= s->len;
100 s->file.data += s->len;
101 }
while(s->file.len > 0);
106 #if WEBSERVER_CONF_INCLUDE || WEBSERVER_CONF_CGI
108 PT_THREAD(send_part_of_file(
struct httpd_state *s))
112 static int oldfilelen, oldlen;
113 static char * olddata;
116 oldfilelen = s->file.len;
118 olddata = s->file.data;
120 s->file.len = s->len;
123 s->file.len -= s->len;
124 s->file.data += s->len;
125 }
while(s->file.len > 0);
128 s->file.len = oldfilelen;
129 s->file.data = olddata;
135 next_scriptstate(
struct httpd_state *s)
139 if((p = (
char *)httpd_fs_strchr(s->scriptptr, ISO_nl)) !=
NULL) {
141 s->scriptlen -= (
unsigned short)(p - s->scriptptr);
150 get_scriptname(
char *dest,
char *fromfile)
156 dest[i]=httpd_fs_getchar(fromfile++);
157 if (dest[i]==ISO_colon) {
if (!skip)
break;}
158 else if (dest[i]==ISO_tab ) {
if (skip)
continue;
else break;}
159 else if (dest[i]==ISO_space) {
if (skip)
continue;
else break;}
160 else if (dest[i]==ISO_nl )
break;
161 else if (dest[i]==ISO_cr )
break;
162 else if (dest[i]==0 )
break;
165 }
while (i<(MAX_SCRIPT_NAME_LENGTH+1));
167 while ((dest[i]==ISO_space) || (dest[i]==ISO_tab)) dest[i]=httpd_fs_getchar(++fromfile);
174 PT_THREAD(handle_script(
struct httpd_state *s))
177 static char scriptname[MAX_SCRIPT_NAME_LENGTH+1],*pptr;
178 static uint16_t filelength;
182 filelength=s->file.len;
183 while(s->file.len > 0) {
185 if (s->file.len > filelength)
break;
188 if(httpd_fs_getchar(s->file.data) == ISO_percent &&
189 httpd_fs_getchar(s->file.data + 1) == ISO_bang) {
192 s->scriptptr=get_scriptname(scriptname,s->file.data+2);
193 s->scriptlen=s->file.len-(s->scriptptr-s->file.data);
194 PRINTD(
"httpd: Handle script named %s\n",scriptname);
195 if(scriptname[0] == ISO_colon) {
196 #if WEBSERVER_CONF_INCLUDE
197 if (httpd_fs_open(&scriptname[1], &s->file)) {
203 #if WEBSERVER_CONF_CGI
204 PT_WAIT_THREAD(&s->scriptpt,httpd_cgi(scriptname)(s, s->scriptptr));
210 s->file.data = s->scriptptr;
211 s->file.len = s->scriptlen;
218 s->len = s->file.len;
221 if(httpd_fs_getchar(s->file.data) == ISO_percent) {
222 pptr = (
char *) httpd_fs_strchr(s->file.data + 1, ISO_percent);
224 pptr = (
char *) httpd_fs_strchr(s->file.data, ISO_percent);
227 if(pptr !=
NULL && pptr != s->file.data) {
228 s->len = (int)(pptr - s->file.data);
233 PRINTD(
"httpd: Sending %u bytes from 0x%04x\n",s->file.len,(
unsigned int)s->file.data);
235 s->file.data += s->len;
236 s->file.len -= s->len;
244 const char httpd_http[] HTTPD_STRING_ATTR =
"HTTP/1.0 ";
245 const char httpd_server[] HTTPD_STRING_ATTR =
"\r\nServer: Contiki/2.0 http://www.sics.se/contiki/\r\nConnection: close\r\n";
246 static unsigned short
247 generate_status(
void *sstr)
249 uint8_t slen=httpd_strlen((
char *)sstr);
250 httpd_memcpy(
uip_appdata, httpd_http,
sizeof(httpd_http)-1);
251 httpd_memcpy(
uip_appdata+
sizeof(httpd_http)-1, (
char *)sstr, slen);
252 slen+=
sizeof(httpd_http)-1;
253 httpd_memcpy(
uip_appdata+slen, httpd_server,
sizeof(httpd_server)-1);
254 return slen+
sizeof(httpd_server)-1;
257 const char httpd_content[] HTTPD_STRING_ATTR =
"Content-type: ";
258 const char httpd_crlf[] HTTPD_STRING_ATTR =
"\r\n\r\n";
259 static unsigned short
260 generate_header(
void *hstr)
262 uint8_t slen=httpd_strlen((
char *)hstr);
263 httpd_memcpy(
uip_appdata,httpd_content,
sizeof(httpd_content)-1);
264 httpd_memcpy(
uip_appdata+
sizeof(httpd_content)-1, (
char *)hstr, slen);
265 slen+=
sizeof(httpd_content)-1;
266 httpd_memcpy(
uip_appdata+slen,httpd_crlf,
sizeof(httpd_crlf)-1);
270 const char httpd_mime_htm[] HTTPD_STRING_ATTR =
"text/html";
271 #if WEBSERVER_CONF_CSS
272 const char httpd_mime_css[] HTTPD_STRING_ATTR =
"text/css";
274 #if WEBSERVER_CONF_PNG
275 const char httpd_mime_png[] HTTPD_STRING_ATTR =
"image/png";
277 #if WEBSERVER_CONF_GIF
278 const char httpd_mime_gif[] HTTPD_STRING_ATTR =
"image/gif";
280 #if WEBSERVER_CONF_JPG
281 const char httpd_mime_jpg[] HTTPD_STRING_ATTR =
"image/jpeg";
282 const char httpd_jpg [] HTTPD_STRING_ATTR =
"jpg";
284 #if WEBSERVER_CONF_TXT
285 const char httpd_mime_txt[] HTTPD_STRING_ATTR =
"text/plain";
287 #if WEBSERVER_CONF_BIN
288 const char httpd_mime_bin[] HTTPD_STRING_ATTR =
"application/octet-stream";
290 #if WEBSERVER_CONF_INCLUDE || WEBSERVER_CONF_CGI
291 const char httpd_shtml [] HTTPD_STRING_ATTR =
".shtml";
295 PT_THREAD(send_headers(
struct httpd_state *s,
const char *statushdr))
302 ptr = strrchr(s->filename, ISO_period);
303 if (httpd_strncmp(
"4", statushdr, 1)==0) {
305 }
else if(ptr ==
NULL) {
306 #if WEBSERVER_CONF_BIN
313 #if WEBSERVER_CONF_INCLUDE || WEBSERVER_CONF_CGI
314 if(httpd_strncmp(ptr, &httpd_mime_htm[5],3)== 0 ||httpd_strncmp(ptr, &httpd_shtml[1], 4) == 0) {
316 if(httpd_strncmp(ptr, &httpd_mime_htm[5],3)== 0) {
319 #if WEBSEVER_CONF_CSS
320 }
else if(httpd_strcmp(ptr, &httpd_mime_css[5]) == 0) {
323 #if WEBSERVER_CONF_PNG
324 }
else if(httpd_strcmp(ptr, &httpd_mime_png[6]) == 0) {
327 #if WEBSERVER_CONF_GIF
328 }
else if(httpd_strcmp(ptr, &httpd_mime_gif[6])== 0) {
331 #if WEBSERVER_CONF_JPG
332 }
else if(httpd_strcmp(ptr, httpd_mime_jpg) == 0) {
335 #if WEBSERVER_CONF_TXT
344 const char httpd_indexfn [] HTTPD_STRING_ATTR =
"/index.html";
345 #if WEBSERVER_CONF_INCLUDE || WEBSERVER_CONF_CGI
346 const char httpd_indexsfn [] HTTPD_STRING_ATTR =
"/index.shtml";
348 const char httpd_404fn [] HTTPD_STRING_ATTR =
"/404.html";
349 const char httpd_404notf [] HTTPD_STRING_ATTR =
"404 Not found";
350 const char httpd_200ok [] HTTPD_STRING_ATTR =
"200 OK";
352 PT_THREAD(handle_output(
struct httpd_state *s))
358 httpd_strcpy(s->filename,httpd_indexfn);
360 if(!httpd_fs_open(s->filename, &s->file)) {
361 #if WEBSERVER_CONF_INCLUDE || WEBSERVER_CONF_CGI
363 if (httpd_strcmp(s->filename,httpd_indexfn)==0) httpd_strcpy(s->filename,httpd_indexsfn);
364 if (httpd_fs_open(s->filename, &s->file))
goto sendfile;
366 httpd_strcpy(s->filename, httpd_404fn);
367 httpd_fs_open(s->filename, &s->file);
373 #if WEBSERVER_CONF_INCLUDE || WEBSERVER_CONF_CGI
374 ptr = strchr(s->filename, ISO_period);
375 if((ptr !=
NULL && httpd_strncmp(ptr, httpd_shtml, 6) == 0) || httpd_strcmp(s->filename,httpd_indexfn)==0) {
389 #if WEBSERVER_CONF_PASSQUERY
390 char httpd_query[WEBSERVER_CONF_PASSQUERY];
393 const char httpd_get[] HTTPD_STRING_ATTR =
"GET ";
394 const char httpd_ref[] HTTPD_STRING_ATTR =
"Referer:";
396 PT_THREAD(handle_input(
struct httpd_state *s))
403 if(httpd_strncmp(s->inputbuf, httpd_get, 4) != 0) {
408 if(s->inputbuf[0] != ISO_slash) {
412 if(s->inputbuf[1] == ISO_space) {
413 httpd_strcpy(s->filename, httpd_indexfn);
416 for (i=0;i<
sizeof(s->filename)+1;i++) {
418 if (s->inputbuf[i]==ISO_space)
break;
419 #if WEBSERVER_CONF_PASSQUERY
421 if (s->inputbuf[i]==ISO_qmark) {
422 strncpy(httpd_query,&s->inputbuf[i+1],
sizeof(httpd_query));
426 s->filename[i]=s->inputbuf[i];
431 #if WEBSERVER_CONF_LOG
435 #if WEBSERVER_CONF_LOADTIME
438 s->state = STATE_OUTPUT;
441 #if WEBSERVER_CONF_LOG && WEBSERVER_CONF_REFERER
442 if(httpd_strncmp(s->inputbuf, httpd_ref, 8) == 0) {
444 petsciiconv_topetscii(s->inputbuf,
PSOCK_DATALEN(&s->sin) - 2);
445 webserver_log(s->inputbuf);
453 handle_connection(
struct httpd_state *s)
459 if(s->state == STATE_OUTPUT) {
465 httpd_appcall(
void *state)
468 struct httpd_state *s;
469 s = sg = (
struct httpd_state *)
memb_alloc(&conns);
472 struct httpd_state *s = (
struct httpd_state *)state;
485 PSOCK_INIT(&s->sin, (uint8_t *)s->inputbuf,
sizeof(s->inputbuf) - 1);
486 PSOCK_INIT(&s->sout, (uint8_t *)s->inputbuf,
sizeof(s->inputbuf) - 1);
488 s->state = STATE_WAITING;
490 #if WEBSERVER_CONF_AJAX
491 s->ajax_timeout = WEBSERVER_CONF_TIMEOUT;
493 handle_connection(s);
494 }
else if(s !=
NULL) {
497 #if WEBSERVER_CONF_AJAX
498 if(s->timer >= s->ajax_timeout) {
500 if(s->timer >= WEBSERVER_CONF_TIMEOUT) {
508 handle_connection(s);
519 PRINTD(
" sizof(struct httpd_state) = %d\n",
sizeof(
struct httpd_state));
520 PRINTA(
" %d bytes used for httpd state storage\n",conns.size * conns.num);
521 #if WEBSERVER_CONF_CGI
#define PT_WAIT_THREAD(pt, thread)
Block and wait until a child protothread completes.
#define PSOCK_READTO(psock, c)
Read data up to a specified character.
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
#define PSOCK_CLOSE_EXIT(psock)
Close a protosocket and exit the protosocket's protothread.
#define PSOCK_BEGIN(psock)
Start the protosocket protothread in a function.
Representation of a uIP TCP connection.
#define uip_aborted()
Has the connection been aborted by the other end?
char memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
#define uip_mss()
Get the current maximum segment size that can be sent on the current connection.
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
#define NULL
The null pointer.
#define PT_INIT(pt)
Initialize a protothread.
#define uip_poll()
Is the connection being polled by uIP?
#define UIP_HTONS(n)
Convert 16-bit quantity from host byte order to network byte order.
#define PT_THREAD(name_args)
Declaration of a protothread.
#define uip_connected()
Has the connection just been connected?
CCIF clock_time_t clock_time(void)
Get the current clock time.
#define uip_abort()
Abort the current connection.
PETSCII/ASCII conversion functions.
#define PSOCK_INIT(psock, buffer, buffersize)
Initialize a protosocket.
#define PSOCK_GENERATOR_SEND(psock, generator, arg)
Generate data with a function and send it.
#define MEMB(name, structure, num)
Declare a memory block.
#define PSOCK_CLOSE(psock)
Close a protosocket.
#define PSOCK_END(psock)
Declare the end of a protosocket's protothread.
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function implementing the protothread.
#define uip_timedout()
Has the connection timed out?
#define PT_END(pt)
Declare the end of a protothread.
CCIF void tcp_listen(uint16_t port)
Open a TCP port.
#define PSOCK_DATALEN(psock)
The length of the data that was previously read.
#define uip_closed()
Has the connection been closed by the other end?
uip_ipaddr_t ripaddr
The IP address of the remote host.
uip_appdata
Pointer to the application data in the packet buffer.