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

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

ROMファイルシステムのWebコンテンツをwwwフォルダ下に移動。
etcフォルダ追加。

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 26.8 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_www);
206 strcat_s(s->filename, sizeof(s->message.request_url) + 2, http_index_html);
207 s->file.redirect = 1;
208 }
209 /* "/~/"ならSDカードから読み込み */
210 else if ((s->message.request_url[0] == '/') && (s->message.request_url[1] == '~') && (s->message.request_url[2] == '/')) {
211 s->filename = &s->message.filename[sizeof(s->message.filename) - 2 - sizeof(http_www) - 1 + 2];
212 memcpy(s->filename, "1:", 2);
213 memcpy(&s->filename[2], http_www, sizeof(http_www) - 1);
214 }
215 else {
216 s->filename = &s->message.filename[sizeof(s->message.filename) - 2 - sizeof(http_www) - 1 + 2];
217 memcpy(s->filename, "0:", 2);
218 memcpy(&s->filename[2], http_www, sizeof(http_www) - 1);
219 }
220 return 0;
221}
222
223int websvr_response_status(http_parser *p, const char *buf, size_t len)
224{
225 struct httpd_state *s = get_context(p);
226
227 strlncat(s->message.response_status, sizeof(s->message.response_status), buf, len);
228
229 return 0;
230}
231
232int websvr_header_field(http_parser *p, const char *buf, size_t len)
233{
234 struct httpd_state *s = get_context(p);
235 struct message *m = &s->message;
236
237 if (strncmp("Referer", buf, len) == 0) {
238 m->num_headers = 1;
239 }
240 else if (strncmp("Host", buf, len) == 0) {
241 m->num_headers = 2;
242 }
243 else if (strncmp("Upgrade", buf, len) == 0) {
244 m->num_headers = 3;
245 }
246 else if (strncmp("Connection", buf, len) == 0) {
247 m->num_headers = 4;
248 }
249 else if (strncmp("Sec-WebSocket-Key", buf, len) == 0) {
250 m->num_headers = 5;
251 }
252 else if (strncmp("Origin", buf, len) == 0) {
253 m->num_headers = 6;
254 }
255 else if (strncmp("Sec-WebSocket-Protocol", buf, len) == 0) {
256 m->num_headers = 7;
257 }
258 else if (strncmp("Sec-WebSocket-Version", buf, len) == 0) {
259 m->num_headers = 8;
260 }
261 else {
262 m->num_headers = 0;
263 }
264
265 return 0;
266}
267
268int websvr_header_value(http_parser *p, const char *buf, size_t len)
269{
270 struct httpd_state *s = get_context(p);
271 struct message *m = &s->message;
272
273 switch (m->num_headers) {
274 case 1:
275 strlncat(m->referer, sizeof(m->referer), buf, len);
276 break;
277 case 2:
278 strlncat(m->host, sizeof(m->host), buf, len);
279 break;
280 case 3:
281 strlncat(m->upgrade, sizeof(m->upgrade), buf, len);
282 break;
283 case 4:
284 strlncat(m->connection, sizeof(m->connection), buf, len);
285 break;
286 case 5:
287 strlncat(m->sec_websocket_key, sizeof(m->sec_websocket_key), buf, len);
288 break;
289 case 6:
290 strlncat(m->origin, sizeof(m->origin), buf, len);
291 break;
292 case 7:
293 strlncat(m->sec_websocket_protocol, sizeof(m->sec_websocket_protocol), buf, len);
294 break;
295 case 8:
296 strlncat(m->sec_websocket_version, sizeof(m->sec_websocket_version), buf, len);
297 break;
298 }
299
300 return 0;
301}
302
303int websvr_headers_complete(http_parser *p)
304{
305 struct httpd_state *s = get_context(p);
306
307 s->message.method = p->method;
308 s->message.http_major = p->http_major;
309 s->message.http_minor = p->http_minor;
310 s->message.headers_complete_cb_called = TRUE;
311 s->message.should_keep_alive = http_should_keep_alive(p);
312
313 if ((s->message.method == HTTP_GET)
314 && httpd_strnicmp(http_websocket, s->message.upgrade, sizeof(s->message.upgrade)) == 0) {
315 s->in.state = IN_STATE_WEBSOCKET;
316 s->state = STATE_WEBSOCKET;
317 s->close_req = 0;
318 websocket_init(&s->websocket, s->cepid);
319 return 0;
320 }
321 else if (s->message.method == HTTP_GET) {
322 s->in.state = IN_STATE_RESPONSE;
323 s->out.state = OUT_STATE_OPEN_GET_FILE;
324 return 1;
325 }
326 else if (s->message.method == HTTP_POST) {
327 if ((s->parser.content_length > 16 * 1024)
328 || httpd_strnicmp(s->message.request_url, http_upload, sizeof(http_upload) - 1) != 0) {
329 goto error;
330 }
331
332 if (uploding == NULL) {
333 uploding = s;
334 // アップロード先はSDカード
335 s->filename[0] = '1';
336 printf("create: %s.%d %s\n", s->addr, ((T_IPV4EP *)s->dst)->portno, s->filename);
337 if (!httpd_fs_create(s->filename, &s->file)) {
338 goto error;
339 }
340
341 s->in.state = IN_STATE_UPLOAD;
342 }
343 else if (strcmp(s->filename, uploding->filename) == 0) {
344 printf("collision: %s.%d %s\n", s->addr, ((T_IPV4EP *)s->dst)->portno, s->filename);
345 goto error;
346 }
347 else {
348 s->in.state = IN_STATE_UPLOAD_WAIT;
349 s->in.wait = true;
350 }
351
352 s->out.state = OUT_STATE_WAIT_POST_BODY;
353 s->out.wait = true;
354 return 0;
355 }
356 else {
357 s->state = STATE_CLOSING;
358 return 1;
359 }
360error:
361 s->filename = NULL;
362 s->response_body = http_content_403;
363 s->response_pos = 0;
364 s->response_len = sizeof(http_content_403) - 1;
365
366 s->out.statushdr = http_header_403;
367 s->out.state = OUT_STATE_SEND_HEADER;
368 return 1;
369}
370
371int websvr_body(http_parser *p, const char *buf, size_t len)
372{
373 struct httpd_state *s = get_context(p);
374
375 if (s->message.body_is_final) {
376 printf("\n\n *** Error http_body_is_final() should return 1 \n"
377 "on last on_body callback call "
378 "but it doesn't! ***\n\n");
379 s->state = STATE_CLOSING;
380 return 0;
381 }
382
383 httpd_fs_write(&s->file, buf, len);
384
385 s->message.body_size += len;
386 s->message.body_is_final = http_body_is_final(p);
387
388 if (s->message.body_is_final) {
389 printf("close: %s.%d %s\n", s->addr, ((T_IPV4EP *)s->dst)->portno, s->filename);
390 httpd_fs_close(&s->file);
391 memset(&s->file, 0, sizeof(s->file));
392
393 strcpy_s(command, sizeof(command), "mruby -b ");
394 strcat_s(command, sizeof(command), s->filename);
395 s->reset = 1;
396
397 s->filename = NULL;
398 s->response_body = http_content_200;
399 s->response_pos = 0;
400 s->response_len = sizeof(http_content_200) - 1;
401
402 uploding = NULL;
403 s->in.state = IN_STATE_END;
404 s->out.state = OUT_STATE_BODY_RECEIVED;
405 }
406
407 return 0;
408}
409
410int websvr_message_complete(http_parser *p)
411{
412 struct httpd_state *s = get_context(p);
413 if (s->message.should_keep_alive != http_should_keep_alive(p)) {
414 printf("\n\n *** Error http_should_keep_alive() should have same \n"
415 "value in both on_message_complete and on_headers_complete "
416 "but it doesn't! ***\n\n");
417 assert(0);
418 }
419
420 if (s->message.body_size &&
421 http_body_is_final(p) &&
422 !s->message.body_is_final) {
423 printf("\n\n *** Error http_body_is_final() should return 1 \n"
424 "on last on_body callback call "
425 "but it doesn't! ***\n\n");
426 assert(0);
427 }
428
429 s->message.message_complete_cb_called = TRUE;
430 return 0;
431}
432
433http_parser_settings websvr_settings =
434{
435 websvr_message_begin,
436 websvr_request_url,
437 websvr_response_status,
438 websvr_header_field,
439 websvr_header_value,
440 websvr_headers_complete,
441 websvr_body,
442 websvr_message_complete,
443};
444
445/*
446 * ネットワーク層の選択
447 */
448
449#ifdef SUPPORT_INET6
450
451#define TCP_ACP_CEP(c,r,d,t) tcp6_acp_cep(c,r,d,t)
452#define IP2STR(s,a) ipv62str(s,a)
453
454#else /* of #ifdef SUPPORT_INET6 */
455
456#ifdef SUPPORT_INET4
457
458#define TCP_ACP_CEP(c,r,d,t) tcp_acp_cep(c,r,d,t)
459#define IP2STR(s,a) ip2str(s,a)
460
461#endif /* of #ifdef SUPPORT_INET4 */
462
463#endif /* of #ifdef SUPPORT_INET6 */
464
465struct httpd_state *get_httpd(ID cepid)
466{
467 for (int i = 0; i < 2; i++) {
468 if (httpd_state[i].cepid != cepid)
469 continue;
470
471 return &httpd_state[i];
472 }
473 return NULL;
474}
475
476struct websocket *websocket_getws(ID wbsid)
477{
478 for (int i = 0; i < 2; i++) {
479 if (httpd_state[i].websocket.wbsid != wbsid)
480 continue;
481
482 return &httpd_state[i].websocket;
483 }
484 return NULL;
485}
486
487void send_file(struct httpd_state *s)
488{
489 char *buf;
490 int len, slen;
491
492 while (s->file.len > 0) {
493 slen = tcp_get_buf(s->cepid, (void **)&buf, TMO_FEVR);
494 if (slen < 0) {
495 printf("send_file#tcp_get_buf(%s.%d) => %d\n", s->addr, ((T_IPV4EP *)s->dst)->portno, slen);
496 s->state = STATE_CLOSING;
497 break;
498 }
499 if (slen == 0)
500 return;
501
502 len = s->file.len;
503 if (len > slen)
504 len = slen;
505
506 len = httpd_fs_read(&s->file, buf, len);
507 if (len <= 0) {
508 printf("send_file#httpd_fs_read(%s.%d) => %d\n", s->addr, ((T_IPV4EP *)s->dst)->portno, len);
509 break;
510 }
511
512 s->file.len -= len;
513 s->file.pos += len;
514
515 if ((slen = tcp_snd_buf(s->cepid, len)) != E_OK) {
516 printf("send_file#tcp_snd_buf(%s.%d) => %d\n", s->addr, ((T_IPV4EP *)s->dst)->portno, slen);
517 s->state = STATE_CLOSING;
518 break;
519 }
520 }
521
522 printf("close: %s.%d %s\n", s->addr, ((T_IPV4EP *)s->dst)->portno, s->filename);
523 httpd_fs_close(&s->file);
524 s->file.len = 0;
525 s->file.pos = 0;
526
527 s->out.state = OUT_STATE_SEND_END;
528}
529
530void send_data(struct httpd_state *s)
531{
532 char *buf;
533 int len, slen;
534
535 while (s->response_len > 0) {
536 slen = tcp_get_buf(s->cepid, (void **)&buf, TMO_FEVR);
537 if (slen < 0) {
538 printf("send_data#tcp_get_buf(%s.%d) => %d\n", s->addr, ((T_IPV4EP *)s->dst)->portno, slen);
539 s->state = STATE_CLOSING;
540 break;
541 }
542 if (slen == 0)
543 return;
544
545 len = s->response_len;
546 if (len > slen)
547 len = slen;
548
549 memcpy(buf, &s->response_body[s->response_pos], len);
550
551 s->response_len -= len;
552 s->response_pos += len;
553
554 if ((slen = tcp_snd_buf(s->cepid, len)) != E_OK) {
555 printf("send_data#tcp_snd_buf(%s.%d) => %d\n", s->addr, ((T_IPV4EP *)s->dst)->portno, slen);
556 s->state = STATE_CLOSING;
557 break;
558 }
559 }
560
561 s->response_body = NULL;
562 s->response_len = 0;
563 s->response_pos = 0;
564
565 s->out.state = OUT_STATE_SEND_END;
566}
567
568void send_headers(struct httpd_state *s, const char *statushdr)
569{
570 int len;
571 char *ptr;
572
573 len = strlen(statushdr);
574 tcp_snd_dat(s->cepid, (void *)statushdr, len, TMO_FEVR);
575
576 if ((s->filename[0] == '0') && (s->file.len > 0)) {
577 len = sizeof(http_content_encoding_gzip) - 1;
578 tcp_snd_dat(s->cepid, (void *)http_content_encoding_gzip, len, TMO_FEVR);
579 }
580
581 if (s->file.redirect) {
582 len = sizeof(http_location) - 1;
583 tcp_snd_dat(s->cepid, (void *)http_location, len, TMO_FEVR);
584 if (s->filename[0] == '1') {
585 len = 2;
586 tcp_snd_dat(s->cepid, "/~", len, TMO_FEVR);
587 }
588 len = strlen(s->filename);
589 tcp_snd_dat(s->cepid, s->filename, len, TMO_FEVR);
590 if (s->query != NULL) {
591 tcp_snd_dat(s->cepid, "?", 1, TMO_FEVR);
592 len = strlen(s->query);
593 tcp_snd_dat(s->cepid, s->query, len, TMO_FEVR);
594 }
595 len = 2;
596 tcp_snd_dat(s->cepid, "\r", len, TMO_FEVR);
597 }
598
599 ptr = strrchr(s->filename, ISO_period);
600 if (ptr == NULL) {
601 len = sizeof(http_content_type_binary) - 1;
602 tcp_snd_dat(s->cepid, (void *)http_content_type_binary, len, TMO_FEVR);
603 }
604 else if (strncmp(http_html, ptr, sizeof(http_html) - 1) == 0 ||
605 strncmp(http_htm, ptr, sizeof(http_htm) - 1) == 0) {
606 len = sizeof(http_content_type_html) - 1;
607 tcp_snd_dat(s->cepid, (void *)http_content_type_html, len, TMO_FEVR);
608 }
609 else if (strncmp(http_css, ptr, sizeof(http_css) - 1) == 0) {
610 len = sizeof(http_content_type_css) - 1;
611 tcp_snd_dat(s->cepid, (void *)http_content_type_css, len, TMO_FEVR);
612 }
613 else if (strncmp(http_js, ptr, sizeof(http_js) - 1) == 0) {
614 len = sizeof(http_content_type_js) - 1;
615 tcp_snd_dat(s->cepid, (void *)http_content_type_js, len, TMO_FEVR);
616 }
617 else if (strncmp(http_json, ptr, sizeof(http_json) - 1) == 0) {
618 len = sizeof(http_content_type_json) - 1;
619 tcp_snd_dat(s->cepid, (void *)http_content_type_json, len, TMO_FEVR);
620 }
621 else if (strncmp(http_png, ptr, sizeof(http_png) - 1) == 0) {
622 len = sizeof(http_content_type_png) - 1;
623 tcp_snd_dat(s->cepid, (void *)http_content_type_png, len, TMO_FEVR);
624 }
625 else if (strncmp(http_gif, ptr, sizeof(http_gif) - 1) == 0) {
626 len = sizeof(http_content_type_gif) - 1;
627 tcp_snd_dat(s->cepid, (void *)http_content_type_gif, len, TMO_FEVR);
628 }
629 else if (strncmp(http_jpg, ptr, sizeof(http_jpg) - 1) == 0) {
630 len = sizeof(http_content_type_jpg) - 1;
631 tcp_snd_dat(s->cepid, (void *)http_content_type_jpg, len, TMO_FEVR);
632 }
633 else if (strncmp(http_svg, ptr, sizeof(http_svg) - 1) == 0) {
634 len = sizeof(http_content_type_svg) - 1;
635 tcp_snd_dat(s->cepid, (void *)http_content_type_svg, len, TMO_FEVR);
636 }
637 else if (strncmp(http_text, ptr, sizeof(http_text) - 1) == 0) {
638 len = sizeof(http_content_type_text) - 1;
639 tcp_snd_dat(s->cepid, (void *)http_content_type_text, len, TMO_FEVR);
640 }
641 else if (strncmp(http_eot, ptr, sizeof(http_eot) - 1) == 0) {
642 len = sizeof(http_content_type_eot) - 1;
643 tcp_snd_dat(s->cepid, (void *)http_content_type_eot, len, TMO_FEVR);
644 }
645 else if (strncmp(http_ttf, ptr, sizeof(http_ttf) - 1) == 0) {
646 len = sizeof(http_content_type_ttf) - 1;
647 tcp_snd_dat(s->cepid, (void *)http_content_type_ttf, len, TMO_FEVR);
648 }
649 else if (strncmp(http_woff, ptr, sizeof(http_woff) - 1) == 0) {
650 len = sizeof(http_content_type_woff) - 1;
651 tcp_snd_dat(s->cepid, (void *)http_content_type_woff, len, TMO_FEVR);
652 }
653 else if (strncmp(http_woff2, ptr, sizeof(http_woff2) - 1) == 0) {
654 len = sizeof(http_content_type_woff2) - 1;
655 tcp_snd_dat(s->cepid, (void *)http_content_type_woff2, len, TMO_FEVR);
656 }
657 else if (strncmp(http_ico, ptr, sizeof(http_ico) - 1) == 0) {
658 len = sizeof(http_content_type_ico) - 1;
659 tcp_snd_dat(s->cepid, (void *)http_content_type_ico, len, TMO_FEVR);
660 }
661 else {
662 len = sizeof(http_content_type_plain) - 1;
663 tcp_snd_dat(s->cepid, (void *)http_content_type_plain, len, TMO_FEVR);
664 }
665
666 if (s->file.len > 0) {
667 len = sizeof(http_content_length) - 1;
668 tcp_snd_dat(s->cepid, (void *)http_content_length, len, TMO_FEVR);
669 len = snprintf(s->temp, sizeof(s->temp), "%d\r\n", s->file.len);
670 tcp_snd_dat(s->cepid, (void *)s->temp, len, TMO_FEVR);
671 }
672
673 if (s->message.should_keep_alive && s->reset == 0) {
674 len = sizeof(http_connection_keep_alive) - 1;
675 tcp_snd_dat(s->cepid, (void *)http_connection_keep_alive, len, TMO_FEVR);
676 }
677 else {
678 len = sizeof(http_connection_close) - 1;
679 tcp_snd_dat(s->cepid, (void *)http_connection_close, len, TMO_FEVR);
680 }
681
682 tcp_snd_dat(s->cepid, (void *)http_crnl, 2, TMO_FEVR);
683
684 if (s->filename != NULL) {
685 s->out.state = OUT_STATE_SEND_FILE;
686 }
687 else {
688 s->out.state = OUT_STATE_SEND_DATA;
689 }
690}
691
692void handle_output(struct httpd_state *s)
693{
694 s->out.wait = false;
695
696 switch (s->out.state) {
697 case OUT_STATE_WAIT_REQUEST:
698 s->out.wait = true;
699 break;
700 case OUT_STATE_OPEN_GET_FILE:
701 printf("open: %s.%d %s\n", s->addr, ((T_IPV4EP *)s->dst)->portno, s->filename);
702 if (!httpd_fs_open(s->filename, sizeof(s->message.request_url), &s->file)) {
703 s->filename = NULL;
704 s->response_body = http_content_404;
705 s->response_pos = 0;
706 s->response_len = sizeof(http_content_403) - 1;
707 s->out.statushdr = http_header_404;
708 }
709 else {
710 s->out.statushdr = s->file.redirect ? http_header_301 : http_header_200;
711 }
712 s->out.state = OUT_STATE_SEND_HEADER;
713 break;
714 case OUT_STATE_WAIT_POST_BODY:
715 //printf("wait post body\n");
716 s->out.wait = true;
717 break;
718 case OUT_STATE_BODY_RECEIVED:
719 //printf("body received\n");
720 s->out.statushdr = http_header_200;
721 s->out.state = OUT_STATE_SEND_HEADER;
722 break;
723 case OUT_STATE_SEND_HEADER:
724 //printf("send header\n");
725 send_headers(s, s->out.statushdr);
726 break;
727 case OUT_STATE_SEND_FILE:
728 //printf("send file %d\n", s->file.len);
729 send_file(s);
730 break;
731 case OUT_STATE_SEND_DATA:
732 //printf("send data %d\n", s->response_len);
733 send_data(s);
734 break;
735 case OUT_STATE_SEND_END:
736 //printf("send end\n");
737 s->out.wait = true;
738 if (s->message.should_keep_alive && s->reset == 0) {
739 s->out.state = OUT_STATE_WAIT_REQUEST;
740 }
741 else {
742 s->state = STATE_CLOSING;
743 }
744 break;
745 }
746}
747
748void send_ws_headers(struct httpd_state *s, const char *statushdr)
749{
750 int len;
751
752 len = strlen(statushdr);
753 tcp_snd_dat(s->cepid, (void *)statushdr, len, TMO_FEVR);
754
755 len = sizeof(http_upgrade) - 1;
756 tcp_snd_dat(s->cepid, (void *)http_upgrade, len, TMO_FEVR);
757 len = strlen(s->message.upgrade);
758 tcp_snd_dat(s->cepid, s->message.upgrade, len, TMO_FEVR);
759 len = sizeof(http_crnl) - 1;
760 tcp_snd_dat(s->cepid, (void *)http_crnl, len, TMO_FEVR);
761
762 len = sizeof(http_connection) - 1;
763 tcp_snd_dat(s->cepid, (void *)http_connection, len, TMO_FEVR);
764 len = strlen(s->message.connection);
765 tcp_snd_dat(s->cepid, s->message.connection, len, TMO_FEVR);
766 len = sizeof(http_crnl) - 1;
767 tcp_snd_dat(s->cepid, (void *)http_crnl, len, TMO_FEVR);
768
769 len = sizeof(http_sec_websocket_accept) - 1;
770 tcp_snd_dat(s->cepid, (void *)http_sec_websocket_accept, len, TMO_FEVR);
771 len = strlen(s->message.response_key);
772 tcp_snd_dat(s->cepid, s->message.response_key, len, TMO_FEVR);
773 len = sizeof(http_crnl) - 1;
774 tcp_snd_dat(s->cepid, (void *)http_crnl, len, TMO_FEVR);
775
776 len = sizeof(http_sec_websocket_protocol) - 1;
777 tcp_snd_dat(s->cepid, (void *)http_sec_websocket_protocol, len, TMO_FEVR);
778 len = strlen(s->message.sec_websocket_protocol);
779 tcp_snd_dat(s->cepid, s->message.sec_websocket_protocol, len, TMO_FEVR);
780 len = sizeof(http_crnl) - 1;
781 tcp_snd_dat(s->cepid, (void *)http_crnl, len, TMO_FEVR);
782
783 len = sizeof(http_crnl) - 1;
784 tcp_snd_dat(s->cepid, (void *)http_crnl, len, TMO_FEVR);
785}
786
787void send_ws_data(struct httpd_state *s)
788{
789 char *buf;
790 int slen;
791
792 slen = tcp_get_buf(s->cepid, (void **)&buf, TMO_FEVR);
793 if (slen < 0) {
794 printf("send_ws_data#tcp_get_buf(%s.%d) => %d\n", s->addr, ((T_IPV4EP *)s->dst)->portno, slen);
795 return;
796 }
797
798 websocket_output(&s->websocket, buf, slen);
799}
800
801void handle_ws_output(struct httpd_state *s)
802{
803 char shaHash[20];
804 SHA_CTX sha1;
805 int len;
806
807 strlncat(s->message.response_key, sizeof(s->message.response_key),
808 s->message.sec_websocket_key, sizeof(s->message.sec_websocket_key));
809 len = strlncat(s->message.response_key, sizeof(s->message.response_key),
810 http_websocket_guid, sizeof(http_websocket_guid));
811 memset(shaHash, 0, sizeof(shaHash));
812 SHA1_Init(&sha1);
813 SHA1_Update(&sha1, (sha1_byte *)s->message.response_key, len);
814 SHA1_Final((sha1_byte *)shaHash, &sha1);
815 base64_encode((unsigned char *)s->message.response_key,
816 sizeof(s->message.response_key), (unsigned char *)shaHash, sizeof(shaHash));
817
818 send_ws_headers(s, http_header_101);
819
820 s->message.response_key[0] = '\0';
821
822 do {
823 while (!websocket_newdata(&s->websocket))
824 slp_tsk();
825
826 send_ws_data(s);
827 } while ((s->state == STATE_CONNECTED) && (!s->close_req));
828 s->state = STATE_DISCONNECTED;
829 websocket_destroy(&s->websocket);
830 s->close_req = 0;
831
832 s->state = STATE_CLOSING;
833}
834
835void handle_input(struct httpd_state *s)
836{
837 size_t done;
838 int len;
839
840 s->in.wait = false;
841
842 switch (s->in.state) {
843 case IN_STATE_START:
844 http_parser_init(&s->parser, HTTP_REQUEST);
845 s->in.state = IN_STATE_REQUEST;
846 break;
847 case IN_STATE_REQUEST:
848 case IN_STATE_RESPONSE:
849 case IN_STATE_UPLOAD:
850 if ((len = tcp_rcv_buf(s->cepid, (void **)&s->in.data, TMO_POL)) <= 0) {
851 if ((len == E_TMOUT) || (len == 0)) {
852 // 3秒は待つ
853 //if (httpd_time - s->in.timer < 30000000) {
854 s->in.wait = true;
855 break;
856 //}
857 }
858 printf("handle_input#tcp_rcv_buf#%d(%s.%d) => %d\n", s->in.state, s->addr, ((T_IPV4EP *)s->dst)->portno, len);
859 uploding = NULL;
860 s->state = STATE_CLOSING;
861 return;
862 }
863 done = http_parser_execute(&s->parser, &websvr_settings, s->in.data, len);
864 tcp_rel_buf(s->cepid, done);
865 if (s->parser.http_errno != HPE_OK) {
866 printf("http_parser error %s.%d => %d\n", s->addr, ((T_IPV4EP *)s->dst)->portno, s->parser.http_errno);
867 uploding = NULL;
868 s->state = STATE_CLOSING;
869 return;
870 }
871
872 s->parse_pos = done;
873 s->parse_len = len - done;
874 break;
875 case IN_STATE_UPLOAD_WAIT:
876 if (uploding != NULL) {
877 s->in.wait = true;
878 }
879 else {
880 uploding = s;
881 s->in.state = IN_STATE_UPLOAD;
882 }
883 break;
884 case IN_STATE_WEBSOCKET:
885 if (s->parse_len <= 0) {
886 if ((len = tcp_rcv_buf(s->cepid, (void **)&s->in.data, TMO_POL)) <= 0) {
887 if ((len == E_TMOUT) || (len == 0)) {
888 s->in.wait = true;
889 break;
890 }
891 printf("handle_input#tcp_rcv_buf#%d(%s.%d) => %d\n", s->in.state, s->addr, ((T_IPV4EP *)s->dst)->portno, len);
892 s->state = STATE_CLOSING;
893 break;
894 }
895
896 s->parse_pos = 0;
897 s->parse_len = len;
898 }
899 else
900 len = s->parse_len;
901 done = websocket_input(&s->websocket, (void *)s->in.data, s->parse_len);
902 tcp_rel_buf(s->cepid, done);
903 if ((done != 0) || (s->websocket.rstate.opecode == connection_close)) {
904 s->close_req = 1;
905 s->state = STATE_CLOSING;
906 break;
907 }
908 s->parse_pos = done;
909 s->parse_len -= done;
910 break;
911 case IN_STATE_END:
912 s->in.wait = true;
913 break;
914 default:
915 s->state = STATE_CLOSING;
916 break;
917 }
918}
919
920/*
921 * ノンブロッキングコールのコールバック関数
922 */
923ER
924callback_nblk_tcp(ID cepid, FN fncd, void *p_parblk)
925{
926 struct httpd_state *s = get_httpd(cepid);
927
928 if (s == NULL)
929 printf("callback_nblk_tcp(%d, %d)\n", fncd, cepid);
930 else
931 printf("callback_nblk_tcp(%d, %s.%d)\n", fncd, s->addr, ((T_IPV4EP *)s->dst)->portno);
932
933 return E_PAR;
934}
935
936/*
937 * HTTPサーバータスク
938 */
939void httpd_task(intptr_t exinf)
940{
941 ER ret, ret2;
942 struct httpd_state *s = &httpd_state[exinf];
943
944 for (;;) {
945 ret2 = get_tim(&httpd_time);
946 if (ret2 != E_OK) {
947 printf("get_tim\n");
948 return;
949 }
950
951 switch (s->state) {
952 case STATE_DISCONNECTED:
953 memset(&s->dst, 0, sizeof(s->dst));
954 if ((ret = tcp_acp_cep(s->cepid, TCP_REPID, (T_IPV4EP *)s->dst, TMO_FEVR)) != E_OK) {
955 printf("tcp_acp_cep(%d) => %d\n", s->cepid, ret);
956 tslp_tsk(100 * 1000); // TODO
957 s->state = STATE_CLOSING;
958 break;
959 }
960 IP2STR(s->addr, &((T_IPV4EP *)s->dst)->ipaddr);
961 printf("connected: %s.%d\n", s->addr, ((T_IPV4EP *)s->dst)->portno);
962 memset(&s->in, 0, sizeof(s->in));
963 memset(&s->out, 0, sizeof(s->out));
964 s->in.timer = httpd_time;
965 s->state = STATE_CONNECTED;
966 break;
967 case STATE_CONNECTED:
968 handle_input(s);
969 handle_output(s);
970 break;
971 case STATE_WEBSOCKET:
972 handle_input(s);
973 handle_ws_output(s);
974 break;
975 case STATE_CLOSING:
976 printf("close: %s.%d\n", s->addr, ((T_IPV4EP *)s->dst)->portno);
977 tcp_sht_cep(s->cepid);
978 tcp_cls_cep(s->cepid, TMO_FEVR);
979
980 if (s->reset) {
981 s->reset = 0;
982 s->state = STATE_RESET;
983 }
984 else {
985 s->state = STATE_DISCONNECTED;
986 }
987 break;
988 case STATE_RESET:
989 cmd_execute(command, NULL);
990 s->state = STATE_DISCONNECTED;
991 break;
992 }
993
994 if (s->in.wait && s->out.wait) {
995 tslp_tsk(100 * 1000);
996 }
997 }
998}
Note: See TracBrowser for help on using the repository browser.