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

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

prototoolに関連するプロジェクトをnewlibからmuslを使うよう変更・更新
ntshellをnewlibの下位の実装から、muslのsyscallの実装に変更・更新
以下のOSSをアップデート
・mruby-1.3.0
・musl-1.1.18
・onigmo-6.1.3
・tcc-0.9.27
以下のOSSを追加
・openssl-1.1.0e
・curl-7.57.0
・zlib-1.2.11
以下のmrbgemsを追加
・iij/mruby-digest
・iij/mruby-env
・iij/mruby-errno
・iij/mruby-iijson
・iij/mruby-ipaddr
・iij/mruby-mock
・iij/mruby-require
・iij/mruby-tls-openssl

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