source: EcnlProtoTool/trunk/ntshell/webserver/httpd.c@ 442

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

ntshellアプリはnewlibを使うよう変更し、syscallの実装部分と区別がつくよう更新。

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 26.6 KB
Line 
1/*
2 * TOPPERS PROJECT Home Network Working Group Software
3 *
4 * Copyright (C) 2017-2019 Cores Co., Ltd. Japan
5 *
6 * 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ
7 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
8 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
9 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
10 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
11 * スコード中に含まれていること.
12 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
13 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
14 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
15 * の無保証規定を掲載すること.
16 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
17 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
18 * と.
19 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
20 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
21 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
22 * 報告すること.
23 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
24 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
25 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
26 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
27 * 免責すること.
28 *
29 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
30 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
31 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
32 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
33 * の責任を負わない.
34 *
35 * @(#) $Id$
36 */
37
38#include "httpd.h"
39#include <string.h>
40#include <stdlib.h>
41#include "kernel_cfg.h"
42#include "tinet_cfg.h"
43#include "syssvc/syslog.h"
44#include "http-strings.h"
45#include <tinet_defs.h>
46#include <tinet_config.h>
47#include "netinet/in.h"
48#include "netinet/in_var.h"
49#include "netinet/in_itron.h"
50#include "httpd.h"
51#include "httpd-fs.h"
52#include "http-strings.h"
53#include "base64.h"
54#include "sha1.h"
55#include "core/ntlibc.h"
56
57#define TRUE 1
58#define FALSE 0
59
60SYSTIM httpd_time;
61struct httpd_state *uploding;
62static char command[256];
63
64/* TCP 送受信ウィンドバッファ */
65#ifdef SUPPORT_INET6
66uint8_t tcp6_swbuf1[TCP_SWBUF_SIZE];
67uint8_t tcp6_rwbuf1[TCP_RWBUF_SIZE];
68uint8_t tcp6_swbuf2[TCP_SWBUF_SIZE];
69uint8_t tcp6_rwbuf2[TCP_RWBUF_SIZE];
70#endif
71
72#ifdef SUPPORT_INET4
73uint8_t tcp_swbuf1[TCP_SWBUF_SIZE];
74uint8_t tcp_rwbuf1[TCP_RWBUF_SIZE];
75uint8_t tcp_swbuf2[TCP_SWBUF_SIZE];
76uint8_t tcp_rwbuf2[TCP_RWBUF_SIZE];
77#endif
78
79#define ISO_nl 0x0a
80#define ISO_space 0x20
81#define ISO_bang 0x21
82#define ISO_percent 0x25
83#define ISO_period 0x2e
84#define ISO_slash 0x2f
85#define ISO_colon 0x3a
86
87struct httpd_state httpd_state[2] = {
88 { HTTPD1_TASK, TCP_CEPID1 },
89 { HTTPD2_TASK, TCP_CEPID2 },
90};
91
92#ifndef _MSC_VER
93#define strnlen httpd_strnlen
94/* strnlen() is a POSIX.2008 addition. Can't rely on it being available so
95 * define it ourselves.
96 */
97size_t
98strnlen(const char *s, size_t maxlen)
99{
100 const char *p;
101
102 p = memchr(s, '\0', maxlen);
103 if (p == NULL)
104 return maxlen;
105
106 return p - s;
107}
108
109void strcpy_s(char *dst, int size, const char *src)
110{
111 int slen = strlen(src);
112 if (slen >= size)
113 slen = size - 1;
114 memcpy(dst, src, slen);
115 dst[slen] = '\0';
116}
117
118void strcat_s(char *dst, int size, const char *src)
119{
120 int dlen = strlen(dst);
121 int slen = strlen(src);
122 if (dlen + slen >= size)
123 slen = size - 1 - dlen;
124 memcpy(&dst[dlen], src, slen);
125 dst[dlen + slen] = '\0';
126}
127#endif
128
129int httpd_strnicmp(const char *s1, const char *s2, size_t n)
130{
131 int i;
132 char c1, c2;
133
134 for (i = 0; i < n; i++, s1++, s2++) {
135 c1 = *s1;
136 c2 = *s2;
137 if (c1 == '\0' && c2 == '\0')
138 return 0;
139
140 if (c1 >= 'a' && c1 <= 'z')
141 c1 += 'A' - 'a';
142
143 if (c2 >= 'a' && c2 <= 'z')
144 c2 += 'A' - 'a';
145
146 if (c1 < c2)
147 return -1;
148
149 if (c1 > c2)
150 return 1;
151 }
152
153 return 0;
154}
155
156size_t
157strlncat(char *dst, size_t len, const char *src, size_t n)
158{
159 size_t slen;
160 size_t dlen;
161 size_t rlen;
162 size_t ncpy = 0;
163
164 slen = strnlen(src, n);
165 dlen = strnlen(dst, len);
166
167 if (dlen < len) {
168 rlen = len - dlen;
169 ncpy = slen < rlen ? slen : (rlen - 1);
170 memcpy(dst + dlen, src, ncpy);
171 dst[dlen + ncpy] = '\0';
172 }
173
174 //assert(len > slen + dlen);
175 //return slen + dlen;
176 return ncpy;
177}
178
179int websvr_message_begin(http_parser *p)
180{
181 struct httpd_state *s = get_context(p);
182 memset(&s->message, 0, sizeof(s->message));
183 s->message.message_begin_cb_called = TRUE;
184 return 0;
185}
186
187int websvr_request_url(http_parser *p, const char *buf, size_t len)
188{
189 struct httpd_state *s = get_context(p);
190
191 strlncat(s->message.request_url, sizeof(s->message.request_url), buf, len);
192
193 char *ptr = strrchr(s->message.request_url, '?');
194 if (ptr != NULL) {
195 ptr[0] = '\0';
196 s->query = &ptr[1];
197 }
198 else
199 s->query = NULL;
200
201 /* ""か"/"なら"index.html"に変更 */
202 if ((s->message.request_url[0] == '\0') || ((s->message.request_url[0] == '/') && (s->message.request_url[1] == '\0'))) {
203 s->filename = &s->message.filename[sizeof(s->message.filename) - 2];
204 strcpy_s(s->filename, sizeof(s->message.request_url) + 2, "0:");
205 strcat_s(s->filename, sizeof(s->message.request_url) + 2, http_index_html);
206 s->file.redirect = 1;
207 }
208 /* "/~/"ならSDカードから読み込み */
209 else if ((s->message.request_url[0] == '/') && (s->message.request_url[1] == '~') && (s->message.request_url[2] == '/')) {
210 s->filename = &s->message.filename[sizeof(s->message.filename) - 2 - sizeof(http_www) - 1 + 2];
211 memcpy(s->filename, "1:", 2);
212 memcpy(s->filename, http_www, sizeof(http_www) - 1);
213 }
214 else {
215 s->filename = &s->message.filename[sizeof(s->message.filename) - 2];
216 memcpy(s->filename, "0:", 2);
217 }
218 return 0;
219}
220
221int websvr_response_status(http_parser *p, const char *buf, size_t len)
222{
223 struct httpd_state *s = get_context(p);
224
225 strlncat(s->message.response_status, sizeof(s->message.response_status), buf, len);
226
227 return 0;
228}
229
230int websvr_header_field(http_parser *p, const char *buf, size_t len)
231{
232 struct httpd_state *s = get_context(p);
233 struct message *m = &s->message;
234
235 if (strncmp("Referer", buf, len) == 0) {
236 m->num_headers = 1;
237 }
238 else if (strncmp("Host", buf, len) == 0) {
239 m->num_headers = 2;
240 }
241 else if (strncmp("Upgrade", buf, len) == 0) {
242 m->num_headers = 3;
243 }
244 else if (strncmp("Connection", buf, len) == 0) {
245 m->num_headers = 4;
246 }
247 else if (strncmp("Sec-WebSocket-Key", buf, len) == 0) {
248 m->num_headers = 5;
249 }
250 else if (strncmp("Origin", buf, len) == 0) {
251 m->num_headers = 6;
252 }
253 else if (strncmp("Sec-WebSocket-Protocol", buf, len) == 0) {
254 m->num_headers = 7;
255 }
256 else if (strncmp("Sec-WebSocket-Version", buf, len) == 0) {
257 m->num_headers = 8;
258 }
259 else {
260 m->num_headers = 0;
261 }
262
263 return 0;
264}
265
266int websvr_header_value(http_parser *p, const char *buf, size_t len)
267{
268 struct httpd_state *s = get_context(p);
269 struct message *m = &s->message;
270
271 switch (m->num_headers) {
272 case 1:
273 strlncat(m->referer, sizeof(m->referer), buf, len);
274 break;
275 case 2:
276 strlncat(m->host, sizeof(m->host), buf, len);
277 break;
278 case 3:
279 strlncat(m->upgrade, sizeof(m->upgrade), buf, len);
280 break;
281 case 4:
282 strlncat(m->connection, sizeof(m->connection), buf, len);
283 break;
284 case 5:
285 strlncat(m->sec_websocket_key, sizeof(m->sec_websocket_key), buf, len);
286 break;
287 case 6:
288 strlncat(m->origin, sizeof(m->origin), buf, len);
289 break;
290 case 7:
291 strlncat(m->sec_websocket_protocol, sizeof(m->sec_websocket_protocol), buf, len);
292 break;
293 case 8:
294 strlncat(m->sec_websocket_version, sizeof(m->sec_websocket_version), buf, len);
295 break;
296 }
297
298 return 0;
299}
300
301int websvr_headers_complete(http_parser *p)
302{
303 struct httpd_state *s = get_context(p);
304
305 s->message.method = p->method;
306 s->message.http_major = p->http_major;
307 s->message.http_minor = p->http_minor;
308 s->message.headers_complete_cb_called = TRUE;
309 s->message.should_keep_alive = http_should_keep_alive(p);
310
311 if ((s->message.method == HTTP_GET)
312 && httpd_strnicmp(http_websocket, s->message.upgrade, sizeof(s->message.upgrade)) == 0) {
313 s->in.state = IN_STATE_WEBSOCKET;
314 s->state = STATE_WEBSOCKET;
315 s->close_req = 0;
316 websocket_init(&s->websocket, s->cepid);
317 return 0;
318 }
319 else if (s->message.method == HTTP_GET) {
320 s->in.state = IN_STATE_RESPONSE;
321 s->out.state = OUT_STATE_OPEN_GET_FILE;
322 return 1;
323 }
324 else if (s->message.method == HTTP_POST) {
325 if ((s->parser.content_length > 16 * 1024)
326 || httpd_strnicmp(s->message.request_url, http_upload, sizeof(http_upload) - 1) != 0) {
327 goto error;
328 }
329
330 if (uploding == NULL) {
331 uploding = s;
332 // アップロード先はSDカード
333 s->filename[0] = '1';
334 printf("create: %s.%d %s\n", s->addr, ((T_IPV4EP *)s->dst)->portno, s->filename);
335 if (!httpd_fs_create(s->filename, &s->file)) {
336 goto error;
337 }
338
339 s->in.state = IN_STATE_UPLOAD;
340 }
341 else if (strcmp(s->filename, uploding->filename) == 0) {
342 printf("collision: %s.%d %s\n", s->addr, ((T_IPV4EP *)s->dst)->portno, s->filename);
343 goto error;
344 }
345 else {
346 s->in.state = IN_STATE_UPLOAD_WAIT;
347 s->in.wait = true;
348 }
349
350 s->out.state = OUT_STATE_WAIT_POST_BODY;
351 s->out.wait = true;
352 return 0;
353 }
354 else {
355 s->state = STATE_CLOSING;
356 return 1;
357 }
358error:
359 s->filename = NULL;
360 s->response_body = http_content_403;
361 s->response_pos = 0;
362 s->response_len = sizeof(http_content_403) - 1;
363
364 s->out.statushdr = http_header_403;
365 s->out.state = OUT_STATE_SEND_HEADER;
366 return 1;
367}
368
369int websvr_body(http_parser *p, const char *buf, size_t len)
370{
371 struct httpd_state *s = get_context(p);
372
373 if (s->message.body_is_final) {
374 printf("\n\n *** Error http_body_is_final() should return 1 \n"
375 "on last on_body callback call "
376 "but it doesn't! ***\n\n");
377 s->state = STATE_CLOSING;
378 return 0;
379 }
380
381 httpd_fs_write(&s->file, buf, len);
382
383 s->message.body_size += len;
384 s->message.body_is_final = http_body_is_final(p);
385
386 if (s->message.body_is_final) {
387 printf("close: %s.%d %s\n", s->addr, ((T_IPV4EP *)s->dst)->portno, s->filename);
388 httpd_fs_close(&s->file);
389 memset(&s->file, 0, sizeof(s->file));
390
391 strcpy_s(command, sizeof(command), "mruby -b ");
392 strcat_s(command, sizeof(command), s->filename);
393 s->reset = 1;
394
395 s->filename = NULL;
396 s->response_body = http_content_200;
397 s->response_pos = 0;
398 s->response_len = sizeof(http_content_200) - 1;
399
400 uploding = NULL;
401 s->in.state = IN_STATE_END;
402 s->out.state = OUT_STATE_BODY_RECEIVED;
403 }
404
405 return 0;
406}
407
408int websvr_message_complete(http_parser *p)
409{
410 struct httpd_state *s = get_context(p);
411 if (s->message.should_keep_alive != http_should_keep_alive(p)) {
412 printf("\n\n *** Error http_should_keep_alive() should have same \n"
413 "value in both on_message_complete and on_headers_complete "
414 "but it doesn't! ***\n\n");
415 assert(0);
416 }
417
418 if (s->message.body_size &&
419 http_body_is_final(p) &&
420 !s->message.body_is_final) {
421 printf("\n\n *** Error http_body_is_final() should return 1 \n"
422 "on last on_body callback call "
423 "but it doesn't! ***\n\n");
424 assert(0);
425 }
426
427 s->message.message_complete_cb_called = TRUE;
428 return 0;
429}
430
431http_parser_settings websvr_settings =
432{
433 websvr_message_begin,
434 websvr_request_url,
435 websvr_response_status,
436 websvr_header_field,
437 websvr_header_value,
438 websvr_headers_complete,
439 websvr_body,
440 websvr_message_complete,
441};
442
443/*
444 * ネットワーク層の選択
445 */
446
447#ifdef SUPPORT_INET6
448
449#define TCP_ACP_CEP(c,r,d,t) tcp6_acp_cep(c,r,d,t)
450#define IP2STR(s,a) ipv62str(s,a)
451
452#else /* of #ifdef SUPPORT_INET6 */
453
454#ifdef SUPPORT_INET4
455
456#define TCP_ACP_CEP(c,r,d,t) tcp_acp_cep(c,r,d,t)
457#define IP2STR(s,a) ip2str(s,a)
458
459#endif /* of #ifdef SUPPORT_INET4 */
460
461#endif /* of #ifdef SUPPORT_INET6 */
462
463struct httpd_state *get_httpd(ID cepid)
464{
465 for (int i = 0; i < 2; i++) {
466 if (httpd_state[i].cepid != cepid)
467 continue;
468
469 return &httpd_state[i];
470 }
471 return NULL;
472}
473
474struct websocket *websocket_getws(ID wbsid)
475{
476 for (int i = 0; i < 2; i++) {
477 if (httpd_state[i].websocket.wbsid != wbsid)
478 continue;
479
480 return &httpd_state[i].websocket;
481 }
482 return NULL;
483}
484
485void send_file(struct httpd_state *s)
486{
487 char *buf;
488 int len, slen;
489
490 while (s->file.len > 0) {
491 slen = tcp_get_buf(s->cepid, (void **)&buf, TMO_FEVR);
492 if (slen < 0) {
493 printf("send_file#tcp_get_buf(%s.%d) => %d\n", s->addr, ((T_IPV4EP *)s->dst)->portno, slen);
494 s->state = STATE_CLOSING;
495 break;
496 }
497 if (slen == 0)
498 return;
499
500 len = s->file.len;
501 if (len > slen)
502 len = slen;
503
504 len = httpd_fs_read(&s->file, buf, len);
505 if (len <= 0) {
506 printf("send_file#httpd_fs_read(%s.%d) => %d\n", s->addr, ((T_IPV4EP *)s->dst)->portno, len);
507 break;
508 }
509
510 s->file.len -= len;
511 s->file.pos += len;
512
513 if ((slen = tcp_snd_buf(s->cepid, len)) != E_OK) {
514 printf("send_file#tcp_snd_buf(%s.%d) => %d\n", s->addr, ((T_IPV4EP *)s->dst)->portno, slen);
515 s->state = STATE_CLOSING;
516 break;
517 }
518 }
519
520 printf("close: %s.%d %s\n", s->addr, ((T_IPV4EP *)s->dst)->portno, s->filename);
521 httpd_fs_close(&s->file);
522 s->file.len = 0;
523 s->file.pos = 0;
524
525 s->out.state = OUT_STATE_SEND_END;
526}
527
528void send_data(struct httpd_state *s)
529{
530 char *buf;
531 int len, slen;
532
533 while (s->response_len > 0) {
534 slen = tcp_get_buf(s->cepid, (void **)&buf, TMO_FEVR);
535 if (slen < 0) {
536 printf("send_data#tcp_get_buf(%s.%d) => %d\n", s->addr, ((T_IPV4EP *)s->dst)->portno, slen);
537 s->state = STATE_CLOSING;
538 break;
539 }
540 if (slen == 0)
541 return;
542
543 len = s->response_len;
544 if (len > slen)
545 len = slen;
546
547 memcpy(buf, &s->response_body[s->response_pos], len);
548
549 s->response_len -= len;
550 s->response_pos += len;
551
552 if ((slen = tcp_snd_buf(s->cepid, len)) != E_OK) {
553 printf("send_data#tcp_snd_buf(%s.%d) => %d\n", s->addr, ((T_IPV4EP *)s->dst)->portno, slen);
554 s->state = STATE_CLOSING;
555 break;
556 }
557 }
558
559 s->response_body = NULL;
560 s->response_len = 0;
561 s->response_pos = 0;
562
563 s->out.state = OUT_STATE_SEND_END;
564}
565
566void send_headers(struct httpd_state *s, const char *statushdr)
567{
568 int len;
569 char *ptr;
570
571 len = strlen(statushdr);
572 tcp_snd_dat(s->cepid, (void *)statushdr, len, TMO_FEVR);
573
574 if ((s->filename[0] == '0') && (s->file.len > 0)) {
575 len = sizeof(http_content_encoding_gzip) - 1;
576 tcp_snd_dat(s->cepid, (void *)http_content_encoding_gzip, len, TMO_FEVR);
577 }
578
579 if (s->file.redirect) {
580 len = sizeof(http_location) - 1;
581 tcp_snd_dat(s->cepid, (void *)http_location, len, TMO_FEVR);
582 if (s->filename[0] == '1') {
583 len = 2;
584 tcp_snd_dat(s->cepid, "/~", len, TMO_FEVR);
585 }
586 len = strlen(s->filename);
587 tcp_snd_dat(s->cepid, s->filename, len, TMO_FEVR);
588 if (s->query != NULL) {
589 tcp_snd_dat(s->cepid, "?", 1, TMO_FEVR);
590 len = strlen(s->query);
591 tcp_snd_dat(s->cepid, s->query, len, TMO_FEVR);
592 }
593 len = 2;
594 tcp_snd_dat(s->cepid, "\r", len, TMO_FEVR);
595 }
596
597 ptr = strrchr(s->filename, ISO_period);
598 if (ptr == NULL) {
599 len = sizeof(http_content_type_binary) - 1;
600 tcp_snd_dat(s->cepid, (void *)http_content_type_binary, len, TMO_FEVR);
601 }
602 else if (strncmp(http_html, ptr, sizeof(http_html) - 1) == 0 ||
603 strncmp(http_htm, ptr, sizeof(http_htm) - 1) == 0) {
604 len = sizeof(http_content_type_html) - 1;
605 tcp_snd_dat(s->cepid, (void *)http_content_type_html, len, TMO_FEVR);
606 }
607 else if (strncmp(http_css, ptr, sizeof(http_css) - 1) == 0) {
608 len = sizeof(http_content_type_css) - 1;
609 tcp_snd_dat(s->cepid, (void *)http_content_type_css, len, TMO_FEVR);
610 }
611 else if (strncmp(http_js, ptr, sizeof(http_js) - 1) == 0) {
612 len = sizeof(http_content_type_js) - 1;
613 tcp_snd_dat(s->cepid, (void *)http_content_type_js, len, TMO_FEVR);
614 }
615 else if (strncmp(http_json, ptr, sizeof(http_json) - 1) == 0) {
616 len = sizeof(http_content_type_json) - 1;
617 tcp_snd_dat(s->cepid, (void *)http_content_type_json, len, TMO_FEVR);
618 }
619 else if (strncmp(http_png, ptr, sizeof(http_png) - 1) == 0) {
620 len = sizeof(http_content_type_png) - 1;
621 tcp_snd_dat(s->cepid, (void *)http_content_type_png, len, TMO_FEVR);
622 }
623 else if (strncmp(http_gif, ptr, sizeof(http_gif) - 1) == 0) {
624 len = sizeof(http_content_type_gif) - 1;
625 tcp_snd_dat(s->cepid, (void *)http_content_type_gif, len, TMO_FEVR);
626 }
627 else if (strncmp(http_jpg, ptr, sizeof(http_jpg) - 1) == 0) {
628 len = sizeof(http_content_type_jpg) - 1;
629 tcp_snd_dat(s->cepid, (void *)http_content_type_jpg, len, TMO_FEVR);
630 }
631 else if (strncmp(http_svg, ptr, sizeof(http_svg) - 1) == 0) {
632 len = sizeof(http_content_type_svg) - 1;
633 tcp_snd_dat(s->cepid, (void *)http_content_type_svg, len, TMO_FEVR);
634 }
635 else if (strncmp(http_text, ptr, sizeof(http_text) - 1) == 0) {
636 len = sizeof(http_content_type_text) - 1;
637 tcp_snd_dat(s->cepid, (void *)http_content_type_text, len, TMO_FEVR);
638 }
639 else if (strncmp(http_eot, ptr, sizeof(http_eot) - 1) == 0) {
640 len = sizeof(http_content_type_eot) - 1;
641 tcp_snd_dat(s->cepid, (void *)http_content_type_eot, len, TMO_FEVR);
642 }
643 else if (strncmp(http_ttf, ptr, sizeof(http_ttf) - 1) == 0) {
644 len = sizeof(http_content_type_ttf) - 1;
645 tcp_snd_dat(s->cepid, (void *)http_content_type_ttf, len, TMO_FEVR);
646 }
647 else if (strncmp(http_woff, ptr, sizeof(http_woff) - 1) == 0) {
648 len = sizeof(http_content_type_woff) - 1;
649 tcp_snd_dat(s->cepid, (void *)http_content_type_woff, len, TMO_FEVR);
650 }
651 else if (strncmp(http_woff2, ptr, sizeof(http_woff2) - 1) == 0) {
652 len = sizeof(http_content_type_woff2) - 1;
653 tcp_snd_dat(s->cepid, (void *)http_content_type_woff2, len, TMO_FEVR);
654 }
655 else if (strncmp(http_ico, ptr, sizeof(http_ico) - 1) == 0) {
656 len = sizeof(http_content_type_ico) - 1;
657 tcp_snd_dat(s->cepid, (void *)http_content_type_ico, len, TMO_FEVR);
658 }
659 else {
660 len = sizeof(http_content_type_plain) - 1;
661 tcp_snd_dat(s->cepid, (void *)http_content_type_plain, len, TMO_FEVR);
662 }
663
664 if (s->file.len > 0) {
665 len = sizeof(http_content_length) - 1;
666 tcp_snd_dat(s->cepid, (void *)http_content_length, len, TMO_FEVR);
667 len = snprintf(s->temp, sizeof(s->temp), "%d\r\n", s->file.len);
668 tcp_snd_dat(s->cepid, (void *)s->temp, len, TMO_FEVR);
669 }
670
671 if (s->message.should_keep_alive && s->reset == 0) {
672 len = sizeof(http_connection_keep_alive) - 1;
673 tcp_snd_dat(s->cepid, (void *)http_connection_keep_alive, len, TMO_FEVR);
674 }
675 else {
676 len = sizeof(http_connection_close) - 1;
677 tcp_snd_dat(s->cepid, (void *)http_connection_close, len, TMO_FEVR);
678 }
679
680 tcp_snd_dat(s->cepid, (void *)http_crnl, 2, TMO_FEVR);
681
682 if (s->filename != NULL) {
683 s->out.state = OUT_STATE_SEND_FILE;
684 }
685 else {
686 s->out.state = OUT_STATE_SEND_DATA;
687 }
688}
689
690void handle_output(struct httpd_state *s)
691{
692 s->out.wait = false;
693
694 switch (s->out.state) {
695 case OUT_STATE_WAIT_REQUEST:
696 s->out.wait = true;
697 break;
698 case OUT_STATE_OPEN_GET_FILE:
699 printf("open: %s.%d %s\n", s->addr, ((T_IPV4EP *)s->dst)->portno, s->filename);
700 if (!httpd_fs_open(s->filename, sizeof(s->message.request_url), &s->file)) {
701 s->filename = NULL;
702 s->response_body = http_content_404;
703 s->response_pos = 0;
704 s->response_len = sizeof(http_content_403) - 1;
705 s->out.statushdr = http_header_404;
706 }
707 else {
708 s->out.statushdr = s->file.redirect ? http_header_301 : http_header_200;
709 }
710 s->out.state = OUT_STATE_SEND_HEADER;
711 break;
712 case OUT_STATE_WAIT_POST_BODY:
713 //printf("wait post body\n");
714 s->out.wait = true;
715 break;
716 case OUT_STATE_BODY_RECEIVED:
717 //printf("body received\n");
718 s->out.statushdr = http_header_200;
719 s->out.state = OUT_STATE_SEND_HEADER;
720 break;
721 case OUT_STATE_SEND_HEADER:
722 //printf("send header\n");
723 send_headers(s, s->out.statushdr);
724 break;
725 case OUT_STATE_SEND_FILE:
726 //printf("send file %d\n", s->file.len);
727 send_file(s);
728 break;
729 case OUT_STATE_SEND_DATA:
730 //printf("send data %d\n", s->response_len);
731 send_data(s);
732 break;
733 case OUT_STATE_SEND_END:
734 //printf("send end\n");
735 s->out.wait = true;
736 if (s->message.should_keep_alive && s->reset == 0) {
737 s->out.state = OUT_STATE_WAIT_REQUEST;
738 }
739 else {
740 s->state = STATE_CLOSING;
741 }
742 break;
743 }
744}
745
746void send_ws_headers(struct httpd_state *s, const char *statushdr)
747{
748 int len;
749
750 len = strlen(statushdr);
751 tcp_snd_dat(s->cepid, (void *)statushdr, len, TMO_FEVR);
752
753 len = sizeof(http_upgrade) - 1;
754 tcp_snd_dat(s->cepid, (void *)http_upgrade, len, TMO_FEVR);
755 len = strlen(s->message.upgrade);
756 tcp_snd_dat(s->cepid, s->message.upgrade, len, TMO_FEVR);
757 len = sizeof(http_crnl) - 1;
758 tcp_snd_dat(s->cepid, (void *)http_crnl, len, TMO_FEVR);
759
760 len = sizeof(http_connection) - 1;
761 tcp_snd_dat(s->cepid, (void *)http_connection, len, TMO_FEVR);
762 len = strlen(s->message.connection);
763 tcp_snd_dat(s->cepid, s->message.connection, len, TMO_FEVR);
764 len = sizeof(http_crnl) - 1;
765 tcp_snd_dat(s->cepid, (void *)http_crnl, len, TMO_FEVR);
766
767 len = sizeof(http_sec_websocket_accept) - 1;
768 tcp_snd_dat(s->cepid, (void *)http_sec_websocket_accept, len, TMO_FEVR);
769 len = strlen(s->message.response_key);
770 tcp_snd_dat(s->cepid, s->message.response_key, len, TMO_FEVR);
771 len = sizeof(http_crnl) - 1;
772 tcp_snd_dat(s->cepid, (void *)http_crnl, len, TMO_FEVR);
773
774 len = sizeof(http_sec_websocket_protocol) - 1;
775 tcp_snd_dat(s->cepid, (void *)http_sec_websocket_protocol, len, TMO_FEVR);
776 len = strlen(s->message.sec_websocket_protocol);
777 tcp_snd_dat(s->cepid, s->message.sec_websocket_protocol, len, TMO_FEVR);
778 len = sizeof(http_crnl) - 1;
779 tcp_snd_dat(s->cepid, (void *)http_crnl, len, TMO_FEVR);
780
781 len = sizeof(http_crnl) - 1;
782 tcp_snd_dat(s->cepid, (void *)http_crnl, len, TMO_FEVR);
783}
784
785void send_ws_data(struct httpd_state *s)
786{
787 char *buf;
788 int slen;
789
790 slen = tcp_get_buf(s->cepid, (void **)&buf, TMO_FEVR);
791 if (slen < 0) {
792 printf("send_ws_data#tcp_get_buf(%s.%d) => %d\n", s->addr, ((T_IPV4EP *)s->dst)->portno, slen);
793 return;
794 }
795
796 websocket_output(&s->websocket, buf, slen);
797}
798
799void handle_ws_output(struct httpd_state *s)
800{
801 char shaHash[20];
802 SHA_CTX sha1;
803 int len;
804
805 strlncat(s->message.response_key, sizeof(s->message.response_key),
806 s->message.sec_websocket_key, sizeof(s->message.sec_websocket_key));
807 len = strlncat(s->message.response_key, sizeof(s->message.response_key),
808 http_websocket_guid, sizeof(http_websocket_guid));
809 memset(shaHash, 0, sizeof(shaHash));
810 SHA1_Init(&sha1);
811 SHA1_Update(&sha1, (sha1_byte *)s->message.response_key, len);
812 SHA1_Final((sha1_byte *)shaHash, &sha1);
813 base64_encode((unsigned char *)s->message.response_key,
814 sizeof(s->message.response_key), (unsigned char *)shaHash, sizeof(shaHash));
815
816 send_ws_headers(s, http_header_101);
817
818 s->message.response_key[0] = '\0';
819
820 do {
821 while (!websocket_newdata(&s->websocket))
822 slp_tsk();
823
824 send_ws_data(s);
825 } while ((s->state == STATE_CONNECTED) && (!s->close_req));
826 s->state = STATE_DISCONNECTED;
827 websocket_destroy(&s->websocket);
828 s->close_req = 0;
829
830 s->state = STATE_CLOSING;
831}
832
833void handle_input(struct httpd_state *s)
834{
835 size_t done;
836 int len;
837
838 s->in.wait = false;
839
840 switch (s->in.state) {
841 case IN_STATE_START:
842 http_parser_init(&s->parser, HTTP_REQUEST);
843 s->in.state = IN_STATE_REQUEST;
844 break;
845 case IN_STATE_REQUEST:
846 case IN_STATE_RESPONSE:
847 case IN_STATE_UPLOAD:
848 if ((len = tcp_rcv_buf(s->cepid, (void **)&s->in.data, TMO_POL)) <= 0) {
849 if ((len == E_TMOUT) || (len == 0)) {
850 // 3秒は待つ
851 //if (httpd_time - s->in.timer < 30000000) {
852 s->in.wait = true;
853 break;
854 //}
855 }
856 printf("handle_input#tcp_rcv_buf#%d(%s.%d) => %d\n", s->in.state, s->addr, ((T_IPV4EP *)s->dst)->portno, len);
857 uploding = NULL;
858 s->state = STATE_CLOSING;
859 return;
860 }
861 done = http_parser_execute(&s->parser, &websvr_settings, s->in.data, len);
862 tcp_rel_buf(s->cepid, done);
863 if (s->parser.http_errno != HPE_OK) {
864 printf("http_parser error %s.%d => %d\n", s->addr, ((T_IPV4EP *)s->dst)->portno, s->parser.http_errno);
865 uploding = NULL;
866 s->state = STATE_CLOSING;
867 return;
868 }
869
870 s->parse_pos = done;
871 s->parse_len = len - done;
872 break;
873 case IN_STATE_UPLOAD_WAIT:
874 if (uploding != NULL) {
875 s->in.wait = true;
876 }
877 else {
878 uploding = s;
879 s->in.state = IN_STATE_UPLOAD;
880 }
881 break;
882 case IN_STATE_WEBSOCKET:
883 if (s->parse_len <= 0) {
884 if ((len = tcp_rcv_buf(s->cepid, (void **)&s->in.data, TMO_POL)) <= 0) {
885 if ((len == E_TMOUT) || (len == 0)) {
886 s->in.wait = true;
887 break;
888 }
889 printf("handle_input#tcp_rcv_buf#%d(%s.%d) => %d\n", s->in.state, s->addr, ((T_IPV4EP *)s->dst)->portno, len);
890 s->state = STATE_CLOSING;
891 break;
892 }
893
894 s->parse_pos = 0;
895 s->parse_len = len;
896 }
897 else
898 len = s->parse_len;
899 done = websocket_input(&s->websocket, (void *)s->in.data, s->parse_len);
900 tcp_rel_buf(s->cepid, done);
901 if ((done != 0) || (s->websocket.rstate.opecode == connection_close)) {
902 s->close_req = 1;
903 s->state = STATE_CLOSING;
904 break;
905 }
906 s->parse_pos = done;
907 s->parse_len -= done;
908 break;
909 case IN_STATE_END:
910 s->in.wait = true;
911 break;
912 default:
913 s->state = STATE_CLOSING;
914 break;
915 }
916}
917
918/*
919 * ノンブロッキングコールのコールバック関数
920 */
921ER
922callback_nblk_tcp(ID cepid, FN fncd, void *p_parblk)
923{
924 struct httpd_state *s = get_httpd(cepid);
925
926 if (s == NULL)
927 printf("callback_nblk_tcp(%d, %d)\n", fncd, cepid);
928 else
929 printf("callback_nblk_tcp(%d, %s.%d)\n", fncd, s->addr, ((T_IPV4EP *)s->dst)->portno);
930
931 return E_PAR;
932}
933
934/*
935 * HTTPサーバータスク
936 */
937void httpd_task(intptr_t exinf)
938{
939 ER ret, ret2;
940 struct httpd_state *s = &httpd_state[exinf];
941
942 for (;;) {
943 ret2 = get_tim(&httpd_time);
944 if (ret2 != E_OK) {
945 printf("get_tim\n");
946 return;
947 }
948
949 switch (s->state) {
950 case STATE_DISCONNECTED:
951 memset(&s->dst, 0, sizeof(s->dst));
952 if ((ret = tcp_acp_cep(s->cepid, TCP_REPID, (T_IPV4EP *)s->dst, TMO_FEVR)) != E_OK) {
953 printf("tcp_acp_cep(%d) => %d\n", s->cepid, ret);
954 tslp_tsk(100 * 1000); // TODO
955 s->state = STATE_CLOSING;
956 break;
957 }
958 IP2STR(s->addr, &((T_IPV4EP *)s->dst)->ipaddr);
959 printf("connected: %s.%d\n", s->addr, ((T_IPV4EP *)s->dst)->portno);
960 memset(&s->in, 0, sizeof(s->in));
961 memset(&s->out, 0, sizeof(s->out));
962 s->in.timer = httpd_time;
963 s->state = STATE_CONNECTED;
964 break;
965 case STATE_CONNECTED:
966 handle_input(s);
967 handle_output(s);
968 break;
969 case STATE_WEBSOCKET:
970 handle_input(s);
971 handle_ws_output(s);
972 break;
973 case STATE_CLOSING:
974 printf("close: %s.%d\n", s->addr, ((T_IPV4EP *)s->dst)->portno);
975 tcp_sht_cep(s->cepid);
976 tcp_cls_cep(s->cepid, TMO_FEVR);
977
978 if (s->reset) {
979 s->reset = 0;
980 s->state = STATE_RESET;
981 }
982 else {
983 s->state = STATE_DISCONNECTED;
984 }
985 break;
986 case STATE_RESET:
987 cmd_execute(command, NULL);
988 s->state = STATE_DISCONNECTED;
989 break;
990 }
991
992 if (s->in.wait && s->out.wait) {
993 tslp_tsk(100 * 1000);
994 }
995 }
996}
Note: See TracBrowser for help on using the repository browser.