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-nogui.h"
00041 #include "httpd-fs.h"
00042 #include "httpd-cgi.h"
00043 #include "http-strings.h"
00044
00045 #include "httpd.h"
00046 #include "ctk/libconio_arch-small.h"
00047
00048 #define STATE_WAITING 0
00049 #define STATE_OUTPUT 1
00050
00051 #define SEND_STRING(s, str) PSOCK_SEND(s, str, (unsigned int)strlen(str))
00052 MEMB(conns, struct httpd_state, 4);
00053
00054 #define ISO_nl 0x0a
00055 #define ISO_space 0x20
00056 #define ISO_bang 0x21
00057 #define ISO_percent 0x25
00058 #define ISO_period 0x2e
00059 #define ISO_slash 0x2f
00060 #define ISO_colon 0x3a
00061
00062
00063 static unsigned short
00064 generate(void *state)
00065 {
00066 struct httpd_state *s = (struct httpd_state *)state;
00067
00068 if(s->file.len > uip_mss()) {
00069 s->len = uip_mss();
00070 } else {
00071 s->len = s->file.len;
00072 }
00073 memcpy(uip_appdata, s->file.data, s->len);
00074
00075 return s->len;
00076 }
00077
00078 static
00079 PT_THREAD(send_file(struct httpd_state *s))
00080 {
00081 PSOCK_BEGIN(&s->sout);
00082
00083 do {
00084 PSOCK_GENERATOR_SEND(&s->sout, generate, s);
00085 s->file.len -= s->len;
00086 s->file.data += s->len;
00087 } while(s->file.len > 0);
00088
00089 PSOCK_END(&s->sout);
00090 }
00091
00092 static
00093 PT_THREAD(send_part_of_file(struct httpd_state *s))
00094 {
00095 PSOCK_BEGIN(&s->sout);
00096
00097 PSOCK_SEND(&s->sout, s->file.data, s->len);
00098
00099 PSOCK_END(&s->sout);
00100 }
00101
00102 #if HTTPD_CONF_SCRIPT
00103 static void
00104 next_scriptstate(struct httpd_state *s)
00105 {
00106 char *p;
00107
00108 if((p = strchr(s->scriptptr, ISO_nl)) != NULL) {
00109 p += 1;
00110 s->scriptlen -= (unsigned short)(p - s->scriptptr);
00111 s->scriptptr = p;
00112 } else {
00113 s->scriptlen = 0;
00114 }
00115
00116
00117
00118
00119 }
00120
00121 static
00122 PT_THREAD(handle_script(struct httpd_state *s))
00123 {
00124 char *ptr;
00125
00126 PT_BEGIN(&s->scriptpt);
00127
00128 while(s->file.len > 0) {
00129
00130
00131 if(*s->file.data == ISO_percent &&
00132 *(s->file.data + 1) == ISO_bang) {
00133 s->scriptptr = s->file.data + 3;
00134 s->scriptlen = s->file.len - 3;
00135 if(*(s->scriptptr - 1) == ISO_colon) {
00136 httpd_fs_open(s->scriptptr + 1, &s->file);
00137 PT_WAIT_THREAD(&s->scriptpt, send_file(s));
00138 #if HTTPD_CONF_CGI
00139 } else {
00140 PT_WAIT_THREAD(&s->scriptpt,
00141 httpd_cgi(s->scriptptr)(s, s->scriptptr));
00142 #endif
00143 }
00144 next_scriptstate(s);
00145
00146
00147
00148 s->file.data = s->scriptptr;
00149 s->file.len = s->scriptlen;
00150 } else {
00151
00152
00153
00154 if(s->file.len > uip_mss()) {
00155 s->len = uip_mss();
00156 } else {
00157 s->len = s->file.len;
00158 }
00159
00160 if(*s->file.data == ISO_percent) {
00161 ptr = strchr(s->file.data + 1, ISO_percent);
00162 } else {
00163 ptr = strchr(s->file.data, ISO_percent);
00164 }
00165 if(ptr != NULL &&
00166 ptr != s->file.data) {
00167 s->len = (int)(ptr - s->file.data);
00168 if(s->len >= uip_mss()) {
00169 s->len = uip_mss();
00170 }
00171 }
00172 PT_WAIT_THREAD(&s->scriptpt, send_part_of_file(s));
00173 s->file.data += s->len;
00174 s->file.len -= s->len;
00175 }
00176 }
00177
00178 PT_END(&s->scriptpt);
00179 }
00180 #endif
00181
00182 static
00183 PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr))
00184 {
00185 char *ptr;
00186
00187 PSOCK_BEGIN(&s->sout);
00188
00189 SEND_STRING(&s->sout, statushdr);
00190
00191 ptr = strrchr(s->filename, ISO_period);
00192 if(ptr == NULL) {
00193 SEND_STRING(&s->sout, http_content_type_binary);
00194 } else if(strncmp(http_html, ptr, 5) == 0 ||
00195 strncmp(http_shtml, ptr, 6) == 0) {
00196 SEND_STRING(&s->sout, http_content_type_html);
00197 #if 0
00198 } else if(strncmp(http_css, ptr, 4) == 0) {
00199 SEND_STRING(&s->sout, http_content_type_css);
00200 } else if(strncmp(http_png, ptr, 4) == 0) {
00201 SEND_STRING(&s->sout, http_content_type_png);
00202 } else if(strncmp(http_gif, ptr, 4) == 0) {
00203 SEND_STRING(&s->sout, http_content_type_gif);
00204 } else if(strncmp(http_jpg, ptr, 4) == 0) {
00205 SEND_STRING(&s->sout, http_content_type_jpg);
00206 #endif
00207 } else {
00208 SEND_STRING(&s->sout, http_content_type_plain);
00209 }
00210 PSOCK_END(&s->sout);
00211 }
00212
00213 static
00214 PT_THREAD(handle_output(struct httpd_state *s))
00215 {
00216 char *ptr;
00217
00218 PT_BEGIN(&s->outputpt);
00219
00220 if(!httpd_fs_open(s->filename, &s->file)) {
00221 httpd_fs_open(http_404_html, &s->file);
00222 PT_WAIT_THREAD(&s->outputpt,
00223 send_headers(s,
00224 http_header_404));
00225 PT_WAIT_THREAD(&s->outputpt,
00226 send_file(s));
00227 } else {
00228 PT_WAIT_THREAD(&s->outputpt,
00229 send_headers(s,
00230 http_header_200));
00231 ptr = strchr(s->filename, ISO_period);
00232 #if HTTPD_CONF_SCRIPT
00233 if(ptr != NULL && strncmp(ptr, http_shtml, 6) == 0) {
00234 PT_INIT(&s->scriptpt);
00235 PT_WAIT_THREAD(&s->outputpt, handle_script(s));
00236 } else {
00237 PT_WAIT_THREAD(&s->outputpt,
00238 send_file(s));
00239 }
00240 #else
00241 PT_WAIT_THREAD(&s->outputpt,
00242 send_file(s));
00243 #endif
00244 }
00245 PSOCK_CLOSE(&s->sout);
00246 PT_END(&s->outputpt);
00247 }
00248
00249 static
00250 PT_THREAD(handle_input(struct httpd_state *s))
00251 {
00252 PSOCK_BEGIN(&s->sin);
00253
00254 PSOCK_READTO(&s->sin, ISO_space);
00255
00256 if(strncmp(s->inputbuf, http_get, 4) != 0) {
00257 PSOCK_CLOSE_EXIT(&s->sin);
00258 }
00259 PSOCK_READTO(&s->sin, ISO_space);
00260
00261 if(s->inputbuf[0] != ISO_slash) {
00262 PSOCK_CLOSE_EXIT(&s->sin);
00263 }
00264
00265 if(s->inputbuf[1] == ISO_space) {
00266 strncpy(s->filename, http_index_html, sizeof(s->filename));
00267 } else {
00268 s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
00269 strncpy(s->filename, &s->inputbuf[0], sizeof(s->filename));
00270 }
00271
00272 libputs_arch(s->filename);
00273
00274 s->state = STATE_OUTPUT;
00275
00276 while(1) {
00277 PSOCK_READTO(&s->sin, ISO_nl);
00278
00279 if(strncmp(s->inputbuf, http_referer, 8) == 0) {
00280 s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
00281 }
00282 }
00283
00284 PSOCK_END(&s->sin);
00285 }
00286
00287 static void
00288 handle_connection(struct httpd_state *s)
00289 {
00290 handle_input(s);
00291 if(s->state == STATE_OUTPUT) {
00292 handle_output(s);
00293 }
00294 }
00295
00296 void
00297 httpd_appcall(void *state)
00298 {
00299 struct httpd_state *s = (struct httpd_state *)state;
00300
00301 if(uip_closed() || uip_aborted() || uip_timedout()) {
00302 if(s != NULL) {
00303 memb_free(&conns, s);
00304 }
00305 } else if(uip_connected()) {
00306 s = (struct httpd_state *)memb_alloc(&conns);
00307 if(s == NULL) {
00308 uip_abort();
00309 return;
00310 }
00311 tcp_markconn(uip_conn, s);
00312 PSOCK_INIT(&s->sin, s->inputbuf, sizeof(s->inputbuf) - 1);
00313 PSOCK_INIT(&s->sout, s->inputbuf, sizeof(s->inputbuf) - 1);
00314 PT_INIT(&s->outputpt);
00315 s->state = STATE_WAITING;
00316
00317 s->timer = 0;
00318 handle_connection(s);
00319 } else if(s != NULL) {
00320 if(uip_poll()) {
00321 ++s->timer;
00322 if(s->timer >= 20) {
00323 uip_abort();
00324 memb_free(&conns, s);
00325 }
00326 } else {
00327 s->timer = 0;
00328 }
00329 handle_connection(s);
00330 } else {
00331 uip_abort();
00332 }
00333 }
00334
00335 void
00336 httpd_init(void)
00337 {
00338 tcp_listen(UIP_HTONS(80));
00339 memb_init(&conns);
00340 #if HTTPD_CONF_CGI
00341 httpd_cgi_init();
00342 #endif
00343 }
00344