00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include <string.h>
00037
00038 #include "contiki-net.h"
00039
00040 #include "webserver.h"
00041 #include "httpd-fs.h"
00042 #include "httpd-cgi.h"
00043 #include "httpd.h"
00044 #include "raven-lcd.h"
00045
00046
00047 #if COFFEE_FILES
00048 #include "cfs-coffee-arch.h"
00049 #endif
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062 #define DEBUGLOGIC 0
00063 #define DEBUG 0
00064 #if DEBUGLOGIC
00065 struct httpd_state *sg;
00066 #define uip_mss(...) 512
00067 #define uip_appdata TCPBUF
00068 char TCPBUF[512];
00069 #endif
00070 #if DEBUG
00071 #include <stdio.h>
00072 #if HTTPD_STRING_TYPE==PROGMEM_TYPE
00073 #define PRINTF(FORMAT,args...) printf_P(PSTR(FORMAT),##args)
00074 #else
00075 #define PRINTF printf
00076 #endif
00077 #else
00078 #define PRINTF(...)
00079 #endif
00080
00081 #ifndef WEBSERVER_CONF_CGI_CONNS
00082 #define CONNS 4
00083 #else
00084 #define CONNS WEBSERVER_CONF_CGI_CONNS
00085 #endif
00086
00087 #define STATE_WAITING 0
00088 #define STATE_OUTPUT 1
00089
00090
00091 MEMB(conns, struct httpd_state, CONNS);
00092
00093
00094 #define MAX_SCRIPT_NAME_LENGTH 20
00095 #define ISO_tab 0x09
00096 #define ISO_nl 0x0a
00097 #define ISO_cr 0x0d
00098 #define ISO_space 0x20
00099 #define ISO_bang 0x21
00100 #define ISO_percent 0x25
00101 #define ISO_period 0x2e
00102 #define ISO_slash 0x2f
00103 #define ISO_colon 0x3a
00104
00105
00106 static unsigned short
00107 generate(void *state)
00108 {
00109 struct httpd_state *s = (struct httpd_state *)state;
00110
00111 if(s->file.len > uip_mss()) {
00112 s->len = uip_mss();
00113 } else {
00114 s->len = s->file.len;
00115 }
00116 httpd_fs_cpy(uip_appdata, s->file.data, s->len);
00117 #if DEBUGLOGIC
00118 return 0;
00119 #else
00120 return s->len;
00121 #endif
00122 }
00123
00124 static
00125 PT_THREAD(send_file(struct httpd_state *s))
00126 {
00127 PSOCK_BEGIN(&s->sout);
00128
00129 do {
00130 PSOCK_GENERATOR_SEND(&s->sout, generate, s);
00131 s->file.len -= s->len;
00132 s->file.data += s->len;
00133 } while(s->file.len > 0);
00134
00135 PSOCK_END(&s->sout);
00136 }
00137
00138 static
00139 PT_THREAD(send_part_of_file(struct httpd_state *s))
00140 {
00141 PSOCK_BEGIN(&s->sout);
00142
00143 static int oldfilelen, oldlen;
00144 static char * olddata;
00145
00146
00147 oldfilelen = s->file.len;
00148 oldlen = s->len;
00149 olddata = s->file.data;
00150
00151
00152 s->file.len = s->len;
00153
00154 do {
00155 PSOCK_GENERATOR_SEND(&s->sout, generate, s);
00156 s->file.len -= s->len;
00157 s->file.data += s->len;
00158 } while(s->file.len > 0);
00159
00160 s->len = oldlen;
00161 s->file.len = oldfilelen;
00162 s->file.data = olddata;
00163
00164 PSOCK_END(&s->sout);
00165 }
00166
00167 static void
00168 next_scriptstate(struct httpd_state *s)
00169 {
00170 char *p;
00171
00172 if((p = (char *)httpd_fs_strchr(s->scriptptr, ISO_nl)) != NULL) {
00173 p += 1;
00174 s->scriptlen -= (unsigned short)(p - s->scriptptr);
00175 s->scriptptr = p;
00176 } else {
00177 s->scriptlen = 0;
00178 }
00179
00180
00181
00182
00183
00184 }
00185
00186
00187 char *
00188 get_scriptname(char *dest, char *fromfile)
00189 {
00190 uint8_t i=0,skip=1;
00191
00192
00193 do {
00194 dest[i]=httpd_fs_getchar(fromfile++);
00195 if (dest[i]==ISO_colon) {if (!skip) break;}
00196 else if (dest[i]==ISO_tab ) {if (skip) continue;else break;}
00197 else if (dest[i]==ISO_space) {if (skip) continue;else break;}
00198 else if (dest[i]==ISO_nl ) break;
00199 else if (dest[i]==ISO_cr ) break;
00200 else if (dest[i]==0 ) break;
00201 else skip=0;
00202 i++;
00203 } while (i<(MAX_SCRIPT_NAME_LENGTH+1));
00204 fromfile--;
00205 while ((dest[i]==ISO_space) || (dest[i]==ISO_tab)) dest[i]=httpd_fs_getchar(++fromfile);
00206 dest[i]=0;
00207 return (fromfile);
00208 }
00209
00210
00211 static
00212 PT_THREAD(handle_script(struct httpd_state *s))
00213 {
00214
00215 static char scriptname[MAX_SCRIPT_NAME_LENGTH+1],*pptr;
00216 static uint16_t filelength;
00217
00218 PT_BEGIN(&s->scriptpt);
00219
00220 filelength=s->file.len;
00221 while(s->file.len > 0) {
00222
00223 if (s->file.len > filelength) break;
00224
00225
00226 if(httpd_fs_getchar(s->file.data) == ISO_percent &&
00227 httpd_fs_getchar(s->file.data + 1) == ISO_bang) {
00228
00229
00230 s->scriptptr=get_scriptname(scriptname,s->file.data+2);
00231 s->scriptlen=s->file.len-(s->scriptptr-s->file.data);
00232 PRINTF("httpd: Handle script named %s\n",scriptname);
00233 if(scriptname[0] == ISO_colon) {
00234 if (httpd_fs_open(&scriptname[1], &s->file)) {
00235 PT_WAIT_THREAD(&s->scriptpt, send_file(s));
00236 }
00237 } else {
00238 PT_WAIT_THREAD(&s->scriptpt,httpd_cgi(scriptname)(s, s->scriptptr));
00239 }
00240 next_scriptstate(s);
00241
00242
00243 s->file.data = s->scriptptr;
00244 s->file.len = s->scriptlen;
00245 } else {
00246
00247
00248 if(s->file.len > uip_mss()) {
00249 s->len = uip_mss();
00250 } else {
00251 s->len = s->file.len;
00252 }
00253
00254 if(httpd_fs_getchar(s->file.data) == ISO_percent) {
00255 pptr = (char *) httpd_fs_strchr(s->file.data + 1, ISO_percent);
00256 } else {
00257 pptr = (char *) httpd_fs_strchr(s->file.data, ISO_percent);
00258 }
00259
00260 if(pptr != NULL && pptr != s->file.data) {
00261 s->len = (int)(pptr - s->file.data);
00262 if(s->len >= uip_mss()) {
00263 s->len = uip_mss();
00264 }
00265 }
00266 PRINTF("httpd: Sending %u bytes from 0x%04x\n",s->file.len,(unsigned int)s->file.data);
00267 PT_WAIT_THREAD(&s->scriptpt, send_part_of_file(s));
00268 s->file.data += s->len;
00269 s->file.len -= s->len;
00270 }
00271 }
00272
00273 PT_END(&s->scriptpt);
00274 }
00275
00276 const char httpd_http[] HTTPD_STRING_ATTR = "HTTP/1.0 ";
00277 const char httpd_server[] HTTPD_STRING_ATTR = "\r\nServer: Contiki/2.0 http://www.sics.se/contiki/\r\nConnection: close\r\n";
00278 static unsigned short
00279 generate_status(void *sstr)
00280 {
00281 uint8_t slen=httpd_strlen((char *)sstr);
00282 httpd_memcpy(uip_appdata, httpd_http, sizeof(httpd_http)-1);
00283 httpd_memcpy(uip_appdata+sizeof(httpd_http)-1, (char *)sstr, slen);
00284 slen+=sizeof(httpd_http)-1;
00285 httpd_memcpy(uip_appdata+slen, httpd_server, sizeof(httpd_server)-1);
00286 #if DEBUGLOGIC
00287 return 0;
00288 #else
00289 return slen+sizeof(httpd_server)-1;
00290 #endif
00291 }
00292
00293 const char httpd_content[] HTTPD_STRING_ATTR = "Content-type: ";
00294 const char httpd_crlf[] HTTPD_STRING_ATTR = "\r\n\r\n";
00295 static unsigned short
00296 generate_header(void *hstr)
00297 {
00298 uint8_t slen=httpd_strlen((char *)hstr);
00299 httpd_memcpy(uip_appdata,httpd_content,sizeof(httpd_content)-1);
00300 httpd_memcpy(uip_appdata+sizeof(httpd_content)-1, (char *)hstr, slen);
00301 slen+=sizeof(httpd_content)-1;
00302 httpd_memcpy(uip_appdata+slen,httpd_crlf,sizeof(httpd_crlf)-1);
00303 #if DEBUGLOGIC
00304 return 0;
00305 #else
00306 return slen+4;
00307 #endif
00308 }
00309
00310 char http_htm[10] PROGMEM ="text/html";
00311 char http_css[ 9] PROGMEM ="text/css";
00312 const char httpd_mime_htm[] HTTPD_STRING_ATTR = "text/html";
00313 const char httpd_mime_css[] HTTPD_STRING_ATTR = "text/css";
00314 const char httpd_mime_png[] HTTPD_STRING_ATTR = "image/png";
00315 const char httpd_mime_gif[] HTTPD_STRING_ATTR = "image/gif";
00316 const char httpd_mime_jpg[] HTTPD_STRING_ATTR = "image/jpeg";
00317 const char httpd_mime_txt[] HTTPD_STRING_ATTR = "text/plain";
00318 const char httpd_mime_bin[] HTTPD_STRING_ATTR = "application/octet-stream";
00319 const char httpd_jpg [] HTTPD_STRING_ATTR = "jpg";
00320 const char httpd_shtml [] HTTPD_STRING_ATTR = ".shtml";
00321
00322 static
00323 PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr))
00324 {
00325 char *ptr;
00326 PSOCK_BEGIN(&s->sout);
00327
00328 PSOCK_GENERATOR_SEND(&s->sout, generate_status, (char *)statushdr);
00329
00330 ptr = strrchr(s->filename, ISO_period);
00331 if (httpd_strncmp("4", statushdr, 1)==0) {
00332 PSOCK_GENERATOR_SEND(&s->sout, generate_header, &httpd_mime_htm );
00333 } else if(ptr == NULL) {
00334 PSOCK_GENERATOR_SEND(&s->sout, generate_header, &httpd_mime_bin );
00335 } else {
00336 ptr++;
00337 if(httpd_strncmp(ptr, &httpd_mime_htm[5],3)== 0 ||httpd_strncmp(ptr, &httpd_shtml[1], 4) == 0) {
00338 PSOCK_GENERATOR_SEND(&s->sout, generate_header, &httpd_mime_htm );
00339 } else if(httpd_strcmp(ptr, &httpd_mime_css[5]) == 0) {
00340 PSOCK_GENERATOR_SEND(&s->sout, generate_header, &httpd_mime_css );
00341 } else if(httpd_strcmp(ptr, &httpd_mime_png[6]) == 0) {
00342 PSOCK_GENERATOR_SEND(&s->sout, generate_header, &httpd_mime_png );
00343 } else if(httpd_strcmp(ptr, &httpd_mime_gif[6])== 0) {
00344 PSOCK_GENERATOR_SEND(&s->sout, generate_header, &httpd_mime_gif );
00345 } else if(httpd_strcmp(ptr, httpd_mime_jpg) == 0) {
00346 PSOCK_GENERATOR_SEND(&s->sout, generate_header, &httpd_mime_jpg );
00347 } else {
00348 PSOCK_GENERATOR_SEND(&s->sout, generate_header, &httpd_mime_txt);
00349 }
00350 }
00351 PSOCK_END(&s->sout);
00352 }
00353
00354 const char httpd_indexfn [] HTTPD_STRING_ATTR = "/index.html";
00355 const char httpd_404fn [] HTTPD_STRING_ATTR = "/404.html";
00356 const char httpd_404notf [] HTTPD_STRING_ATTR = "404 Not found";
00357 const char httpd_200ok [] HTTPD_STRING_ATTR = "200 OK";
00358 static
00359 PT_THREAD(handle_output(struct httpd_state *s))
00360 {
00361 char *ptr;
00362
00363 PT_BEGIN(&s->outputpt);
00364 #if DEBUGLOGIC
00365 httpd_strcpy(s->filename,httpd_indexfn);
00366 #endif
00367 if(!httpd_fs_open(s->filename, &s->file)) {
00368 httpd_strcpy(s->filename, httpd_404fn);
00369 httpd_fs_open(s->filename, &s->file);
00370 PT_WAIT_THREAD(&s->outputpt, send_headers(s, httpd_404notf));
00371 PT_WAIT_THREAD(&s->outputpt, send_file(s));
00372 } else {
00373 PT_WAIT_THREAD(&s->outputpt, send_headers(s, httpd_200ok));
00374 ptr = strchr(s->filename, ISO_period);
00375 if((ptr != NULL && httpd_strncmp(ptr, httpd_shtml, 6) == 0) || httpd_strcmp(s->filename,httpd_indexfn)==0) {
00376 PT_INIT(&s->scriptpt);
00377 PT_WAIT_THREAD(&s->outputpt, handle_script(s));
00378 } else {
00379 PT_WAIT_THREAD(&s->outputpt, send_file(s));
00380 }
00381 }
00382 PSOCK_CLOSE(&s->sout);
00383 PT_END(&s->outputpt);
00384 }
00385
00386 const char httpd_get[] HTTPD_STRING_ATTR = "GET ";
00387 const char httpd_ref[] HTTPD_STRING_ATTR = "Referer:";
00388 static
00389 PT_THREAD(handle_input(struct httpd_state *s))
00390 {
00391
00392 PSOCK_BEGIN(&s->sin);
00393
00394 PSOCK_READTO(&s->sin, ISO_space);
00395
00396 if(httpd_strncmp(s->inputbuf, httpd_get, 4) != 0) {
00397 PSOCK_CLOSE_EXIT(&s->sin);
00398 }
00399 PSOCK_READTO(&s->sin, ISO_space);
00400
00401 if(s->inputbuf[0] != ISO_slash) {
00402 PSOCK_CLOSE_EXIT(&s->sin);
00403 }
00404
00405 if(s->inputbuf[1] == ISO_space) {
00406 httpd_strcpy(s->filename, httpd_indexfn);
00407 } else {
00408 s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
00409 strncpy(s->filename, &s->inputbuf[0], sizeof(s->filename));
00410 {
00411
00412 uint8_t i;
00413 for (i=0;i<sizeof(s->inputbuf);i++) {
00414 if (s->inputbuf[i]=='?') {
00415 raven_lcd_show_text(&s->inputbuf[i]);
00416 if (i<sizeof(s->filename)) s->filename[i]=0;
00417
00418 }
00419 if (s->inputbuf[i]==0) break;
00420 }
00421 }
00422 }
00423
00424 webserver_log_file(&uip_conn->ripaddr, s->filename);
00425
00426 s->state = STATE_OUTPUT;
00427
00428 while(1) {
00429 PSOCK_READTO(&s->sin, ISO_nl);
00430
00431 if(httpd_strncmp(s->inputbuf, httpd_ref, 8) == 0) {
00432 s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
00433 petsciiconv_topetscii(s->inputbuf, PSOCK_DATALEN(&s->sin) - 2);
00434 webserver_log(s->inputbuf);
00435 }
00436 }
00437 PSOCK_END(&s->sin);
00438 }
00439
00440 static void
00441 handle_connection(struct httpd_state *s)
00442 {
00443 #if DEBUGLOGIC
00444 handle_output(s);
00445 #else
00446 handle_input(s);
00447 if(s->state == STATE_OUTPUT) {
00448 handle_output(s);
00449 }
00450 #endif
00451 }
00452
00453 void
00454 httpd_appcall(void *state)
00455 {
00456 #if DEBUGLOGIC
00457 struct httpd_state *s;
00458 s = sg = (struct httpd_state *)memb_alloc(&conns);
00459 if (1) {
00460 #else
00461 struct httpd_state *s = (struct httpd_state *)state;
00462 if(uip_closed() || uip_aborted() || uip_timedout()) {
00463 if(s != NULL) {
00464 memb_free(&conns, s);
00465 }
00466 } else if(uip_connected()) {
00467 s = (struct httpd_state *)memb_alloc(&conns);
00468 if(s == NULL) {
00469 uip_abort();
00470 return;
00471 }
00472 #endif
00473 tcp_markconn(uip_conn, s);
00474 PSOCK_INIT(&s->sin, (uint8_t *)s->inputbuf, sizeof(s->inputbuf) - 1);
00475 PSOCK_INIT(&s->sout, (uint8_t *)s->inputbuf, sizeof(s->inputbuf) - 1);
00476 PT_INIT(&s->outputpt);
00477 s->state = STATE_WAITING;
00478
00479 s->timer = 0;
00480 handle_connection(s);
00481 } else if(s != NULL) {
00482 if(uip_poll()) {
00483 ++s->timer;
00484 if(s->timer >= 20) {
00485 uip_abort();
00486 memb_free(&conns, s);
00487 }
00488 } else {
00489 s->timer = 0;
00490 }
00491 handle_connection(s);
00492 } else {
00493 uip_abort();
00494 }
00495 }
00496
00497 void
00498 httpd_init(void)
00499 {
00500 tcp_listen(UIP_HTONS(80));
00501 memb_init(&conns);
00502 httpd_cgi_init();
00503 }
00504