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

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

文字コードを設定

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