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

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

ファイルを追加、更新。

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