source: uKadecot/trunk/uip/apps/webserver/httpd.c@ 101

Last change on this file since 101 was 101, checked in by coas-nagasima, 9 years ago

TOPPERS/uKadecotのソースコードを追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/plain
File size: 12.1 KB
Line 
1/**
2 * \addtogroup apps
3 * @{
4 */
5
6/**
7 * \defgroup httpd Web server
8 * @{
9 * The uIP web server is a very simplistic implementation of an HTTP
10 * server. It can serve web pages and files from a read-only ROM
11 * filesystem, and provides a very small scripting language.
12
13 */
14
15/**
16 * \file
17 * Web server
18 * \author
19 * Adam Dunkels <adam@sics.se>
20 */
21
22
23/*
24 * Copyright (c) 2004, Adam Dunkels.
25 * All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. Neither the name of the Institute nor the names of its contributors
36 * may be used to endorse or promote products derived from this software
37 * without specific prior written permission.
38 *
39 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
40 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
42 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
43 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
44 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
45 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
47 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
48 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
49 * SUCH DAMAGE.
50 *
51 * This file is part of the uIP TCP/IP stack.
52 *
53 * Author: Adam Dunkels <adam@sics.se>
54 *
55 * $Id: httpd.c 101 2015-06-02 15:37:23Z coas-nagasima $
56 */
57
58#include "uip.h"
59#include "httpd.h"
60#include "httpd-fs.h"
61#include "http-strings.h"
62#include "base64.h"
63#include "sha1.h"
64#include "kadecot_names.h"
65#include "uip_adpt.h"
66
67#include <string.h>
68
69#define STATE_WAITING 0
70#define STATE_OUTPUT 1
71#define STATE_WS_OUTPUT 2
72
73#define ISO_nl 0x0a
74#define ISO_space 0x20
75#define ISO_bang 0x21
76#define ISO_percent 0x25
77#define ISO_period 0x2e
78#define ISO_slash 0x2f
79#define ISO_colon 0x3a
80
81#ifndef _MSC_VER
82#ifndef strcpy_s
83#define strcpy_s(s1, s1m, s2) strcpy(s1, s2)
84#endif
85
86#ifndef strncpy_s
87#define strncpy_s(dst, dsz, src, sz) strncpy(dst, src, sz)
88#endif
89#endif
90
91int httpd_strnicmp(const char *s1, const char *s2, size_t n)
92{
93 int i;
94 char c1, c2;
95
96 for(i = 0; i < n; i++, s1++, s2++){
97 c1 = *s1;
98 c2 = *s2;
99 if(c1 == '\0' && c2 == '\0')
100 return 0;
101
102 if(c1 >= 'a' && c1 <= 'z')
103 c1 += 'A' - 'a';
104
105 if(c2 >= 'a' && c2 <= 'z')
106 c2 += 'A' - 'a';
107
108 if(c1 < c2)
109 return -1;
110
111 if(c1 > c2)
112 return 1;
113 }
114
115 return 0;
116}
117
118struct websocket *websocket_getws(ID wbsid)
119{
120 struct uip_conn *conn = uip_getconn(wbsid);
121 if (conn == NULL)
122 return NULL;
123
124 return &conn->appstate.websocket;
125}
126
127/*---------------------------------------------------------------------------*/
128static unsigned short
129generate_part_of_file(void *state)
130{
131 struct httpd_state *s = (struct httpd_state *)state;
132 int len;
133
134 if (s->file.len > uip_mss()) {
135 len = uip_mss();
136 } else {
137 len = s->file.len;
138 }
139 s->len = httpd_fs_read(&s->file, uip_appdata, len);
140
141 return s->len;
142}
143/*---------------------------------------------------------------------------*/
144static
145PT_THREAD(send_file(struct httpd_state *s))
146{
147 PSOCK_BEGIN(&s->sout);
148
149 do {
150 PSOCK_GENERATOR_SEND(&s->sout, generate_part_of_file, s);
151 s->file.len -= s->len;
152 s->file.pos += s->len;
153 } while (s->file.len > 0);
154
155 PSOCK_END(&s->sout);
156}
157/*---------------------------------------------------------------------------*/
158static
159PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr))
160{
161 char *ptr;
162
163 PSOCK_BEGIN(&s->sout);
164
165 PSOCK_SEND_STR(&s->sout, statushdr);
166
167 PSOCK_SEND_STR(&s->sout, http_content_encoding_gzip);
168
169 ptr = strrchr(s->message.request_url, ISO_period);
170 if (ptr == NULL) {
171 PSOCK_SEND_STR(&s->sout, http_content_type_binary);
172 } else if (strncmp(http_html, ptr, 5) == 0 ||
173 strncmp(http_shtml, ptr, 6) == 0) {
174 PSOCK_SEND_STR(&s->sout, http_content_type_html);
175 } else if (strncmp(http_css, ptr, 4) == 0) {
176 PSOCK_SEND_STR(&s->sout, http_content_type_css);
177 } else if (strncmp(http_js, ptr, 3) == 0) {
178 PSOCK_SEND_STR(&s->sout, http_content_type_js);
179 } else if (strncmp(http_json, ptr, 5) == 0) {
180 PSOCK_SEND_STR(&s->sout, http_content_type_json);
181 } else if (strncmp(http_png, ptr, 4) == 0) {
182 PSOCK_SEND_STR(&s->sout, http_content_type_png);
183 } else if (strncmp(http_gif, ptr, 4) == 0) {
184 PSOCK_SEND_STR(&s->sout, http_content_type_gif);
185 } else if (strncmp(http_jpg, ptr, 4) == 0) {
186 PSOCK_SEND_STR(&s->sout, http_content_type_jpg);
187 } else if (strncmp(http_svg, ptr, 4) == 0) {
188 PSOCK_SEND_STR(&s->sout, http_content_type_svg);
189 } else {
190 PSOCK_SEND_STR(&s->sout, http_content_type_plain);
191 }
192 PSOCK_END(&s->sout);
193}
194/*---------------------------------------------------------------------------*/
195static
196PT_THREAD(handle_output(struct httpd_state *s))
197{
198 char *ptr;
199
200 PT_BEGIN(&s->outputpt);
201
202 if (!httpd_fs_open(s->message.request_url, &s->file)) {
203 httpd_fs_open(http_404_html, &s->file);
204 strcpy_s(s->message.request_url, sizeof(s->message.request_url), http_404_html);
205 PT_WAIT_THREAD(&s->outputpt,
206 send_headers(s,
207 http_header_404));
208 PT_WAIT_THREAD(&s->outputpt, send_file(s));
209 } else {
210 PT_WAIT_THREAD(&s->outputpt,
211 send_headers(s,
212 http_header_200));
213 ptr = strchr(s->message.request_url, ISO_period);
214 PT_WAIT_THREAD(&s->outputpt, send_file(s));
215 }
216
217 PSOCK_CLOSE(&s->sout);
218 PT_END(&s->outputpt);
219}
220/*---------------------------------------------------------------------------*/
221static
222PT_THREAD(send_ws_headers(struct httpd_state *s, const char *statushdr))
223{
224 PSOCK_BEGIN(&s->sout);
225
226 PSOCK_SEND_STR(&s->sout, statushdr);
227
228 PSOCK_SEND_STR(&s->sout, http_upgrade);
229 PSOCK_SEND_STR(&s->sout, s->message.upgrade);
230 PSOCK_SEND_STR(&s->sout, http_crnl);
231
232 PSOCK_SEND_STR(&s->sout, http_connection);
233 PSOCK_SEND_STR(&s->sout, s->message.connection);
234 PSOCK_SEND_STR(&s->sout, http_crnl);
235
236 PSOCK_SEND_STR(&s->sout, http_sec_websocket_accept);
237 PSOCK_SEND_STR(&s->sout, s->message.response_key);
238 PSOCK_SEND_STR(&s->sout, http_crnl);
239
240 PSOCK_SEND_STR(&s->sout, http_sec_websocket_protocol);
241 PSOCK_SEND_STR(&s->sout, s->message.sec_websocket_protocol);
242 PSOCK_SEND_STR(&s->sout, http_crnl);
243
244 PSOCK_SEND_STR(&s->sout, http_crnl);
245
246 PSOCK_END(&s->sout);
247}
248/*---------------------------------------------------------------------------*/
249static unsigned short
250generate_part_of_ws_data(void *state)
251{
252 struct httpd_state *s = (struct httpd_state *)state;
253
254 s->len = websocket_output(&s->websocket, uip_appdata, uip_mss());
255
256 return s->len;
257}
258/*---------------------------------------------------------------------------*/
259static
260PT_THREAD(send_ws_data(struct httpd_state *s))
261{
262 PSOCK_BEGIN(&s->sout);
263
264 PSOCK_GENERATOR_SEND(&s->sout, generate_part_of_ws_data, s);
265
266 PSOCK_END(&s->sout);
267}
268/*---------------------------------------------------------------------------*/
269static
270PT_THREAD(handle_ws_output(struct httpd_state *s))
271{
272 char shaHash[20];
273 SHA_CTX sha1;
274 int len;
275
276 PT_BEGIN(&s->outputpt);
277
278 strlncat(s->message.response_key, sizeof(s->message.response_key),
279 s->message.sec_websocket_key, sizeof(s->message.sec_websocket_key));
280 len = strlncat(s->message.response_key, sizeof(s->message.response_key),
281 http_websocket_guid, sizeof(http_websocket_guid));
282 memset(shaHash, 0, sizeof(shaHash));
283 SHA1_Init(&sha1);
284 SHA1_Update(&sha1, (sha1_byte *)s->message.response_key, len);
285 SHA1_Final((sha1_byte *)shaHash, &sha1);
286 base64_encode((unsigned char *)s->message.response_key,
287 sizeof(s->message.response_key), (unsigned char *)shaHash, sizeof(shaHash));
288
289 PT_WAIT_THREAD(&s->outputpt, send_ws_headers(s, http_header_101));
290
291 s->message.response_key[0] = '\0';
292
293 do {
294 while(!websocket_newdata(&s->websocket))
295 PT_YIELD(&s->outputpt);
296
297 PT_WAIT_THREAD(&s->outputpt, send_ws_data(s));
298 } while ((s->state == STATE_WS_OUTPUT) && (!s->close_req));
299 s->state = STATE_WAITING;
300 websocket_destroy(&s->websocket);
301 s->close_req = 0;
302
303 PSOCK_CLOSE(&s->sout);
304
305 PT_END(&s->outputpt);
306}
307/*---------------------------------------------------------------------------*/
308static
309PT_THREAD(handle_input(struct httpd_state *s))
310{
311 size_t done;
312 const char *data;
313 PSOCK_BEGIN(&s->sin);
314
315 memset(&s->message, 0, sizeof(s->message));
316 http_parser_init(&s->parser, HTTP_REQUEST);
317
318 for (;;) {
319 PSOCK_WAIT_UNTIL(&s->sin, psock_newdata(&s->sin));
320
321 s->parse_pos = 0;
322 s->parse_len = uip_datalen();
323 data = &((const char *)uip_appdata)[s->parse_pos];
324 done = http_parser_execute(&s->parser, &websvr_settings, data, s->parse_len);
325 if (done != 0) {
326 s->parse_pos += done;
327 s->parse_len -= done;
328 break;
329 }
330 }
331
332 if (!s->message.message_complete_cb_called
333 && s->message.method != HTTP_GET) {
334 PSOCK_CLOSE_EXIT(&s->sin);
335 }
336
337 /* ""‚©"/"‚È‚ç"index.html"‚ɕύX */
338 if ((s->message.request_url[0] == '\0') || ((s->message.request_url[0] == '/') && (s->message.request_url[1] == '\0'))) {
339 strncpy_s(s->message.request_url, sizeof(s->message.request_url), http_index_html, sizeof(s->message.request_url));
340 }
341
342 /* httpd_log_file(uip_conn->ripaddr, s->message.request_url);*/
343 /* httpd_log(s->message.referer);*/
344
345 if (httpd_strnicmp(http_websocket, s->message.upgrade, sizeof(s->message.upgrade)) == 0) {
346 s->state = STATE_WS_OUTPUT;
347
348 websocket_init(&s->websocket, uip_getid((struct uip_conn *)((intptr_t)s - offsetof(struct uip_conn, appstate))));
349 for (;;) {
350 if(s->parse_len <= 0){
351 PT_YIELD(&s->sin.pt);
352 PSOCK_WAIT_UNTIL(&s->sin, psock_newdata(&s->sin));
353
354 s->parse_pos = 0;
355 s->parse_len = uip_datalen();
356 }
357 data = &((const char *)uip_appdata)[s->parse_pos];
358 done = websocket_input(&s->websocket, (void *)data, s->parse_len);
359 if ((done != 0) || (s->websocket.rstate.opecode == connection_close)) {
360 s->close_req = 1;
361 PSOCK_CLOSE_EXIT(&s->sin);
362 break;
363 }
364 s->parse_pos = s->parse_len;
365 s->parse_len = 0;
366 }
367 }
368 else {
369 s->state = STATE_OUTPUT;
370
371 while (1) {
372 PSOCK_READTO(&s->sin, ISO_nl);
373 }
374 }
375
376 PSOCK_END(&s->sin);
377}
378/*---------------------------------------------------------------------------*/
379static void
380handle_connection(struct httpd_state *s)
381{
382 handle_input(s);
383 switch (s->state) {
384 case STATE_OUTPUT:
385 handle_output(s);
386 break;
387 case STATE_WS_OUTPUT:
388 handle_ws_output(s);
389 break;
390 }
391}
392/*---------------------------------------------------------------------------*/
393void
394httpd_appcall(void)
395{
396 struct httpd_state *s = (struct httpd_state *)&(uip_conn->appstate);
397
398 if (uip_closed() || uip_aborted() || uip_timedout()) {
399 } else if (uip_connected()) {
400 if(s->state != STATE_WS_OUTPUT){
401 PSOCK_INIT(&s->sin, s->inputbuf, sizeof(s->inputbuf) - 1);
402 PSOCK_INIT(&s->sout, s->inputbuf, sizeof(s->inputbuf) - 1);
403 PT_INIT(&s->outputpt);
404 s->state = STATE_WAITING;
405 /* timer_set(&s->timer, CLOCK_SECOND * 100);*/
406 s->timer = 0;
407 handle_connection(s);
408 }
409 else {
410 handle_connection(s);
411 }
412 } else if (s != NULL) {
413 if(s->state != STATE_WS_OUTPUT){
414 if (uip_poll()) {
415 ++s->timer;
416 if (s->timer >= 20) {
417 uip_abort();
418 }
419 } else {
420 s->timer = 0;
421 }
422 }
423 handle_connection(s);
424 } else {
425 uip_abort();
426 }
427}
428/*---------------------------------------------------------------------------*/
429/**
430 * \brief Initialize the web server
431 *
432 * This function initializes the web server and should be
433 * called at system boot-up.
434 */
435void
436httpd_init(void)
437{
438 uip_listen(HTONS(41314));
439
440 httpd_fs_init();
441 kadecot_names_init();
442}
443/*---------------------------------------------------------------------------*/
444/** @} */
Note: See TracBrowser for help on using the repository browser.