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

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

ntstdio_snprintfの動作が間違っていたのを修正。
Webサーバーを更新

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