source: uKadecot/trunk/uip/apps/webserver/httpd.c@ 152

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

・デジタルPinとアナログPinのWAMPトピックを追加し、PubSubできるように機能追加。

デジタルPINのトピックは、

「com.sonycsl.kadecot.arduino.topic.pinXX」(XXは0から13)

アナログPINのトピックは、

「com.sonycsl.kadecot.arduino.topic.pinXX.thrYYY」(XXは14から19、YYYは閾値十進)

・デバッグ用の使用していない文字列が、ROM領域に残ってしまうのを修正
・WebSocket接続時のHTTPヘッダーを1行ずつNAK応答を待って送信しているのを、一括で送るよう変更

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-chdr; charset=SHIFT_JIS
File size: 14.5 KB
RevLine 
[101]1/**
2 * \addtogroup apps
3 * @{
4 */
5
6/**
7 * \defgroup httpd Web server
8 * @{
9 * The uIP web server is a very simplistic implementation of an HTTP
10 * server. It can serve web pages and files from a read-only ROM
11 * filesystem, and provides a very small scripting language.
12
13 */
14
15/**
16 * \file
17 * Web server
18 * \author
19 * Adam Dunkels <adam@sics.se>
20 */
21
22
23/*
24 * Copyright (c) 2004, Adam Dunkels.
25 * All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. Neither the name of the Institute nor the names of its contributors
36 * may be used to endorse or promote products derived from this software
37 * without specific prior written permission.
38 *
39 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
40 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
42 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
43 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
44 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
45 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
47 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
48 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
49 * SUCH DAMAGE.
50 *
51 * This file is part of the uIP TCP/IP stack.
52 *
53 * Author: Adam Dunkels <adam@sics.se>
54 *
55 * $Id: httpd.c 152 2016-01-14 04:17:21Z coas-nagasima $
56 */
57
58#include "uip.h"
59#include "httpd.h"
60#include "httpd-fs.h"
61#include "http-strings.h"
62#include "base64.h"
63#include "sha1.h"
64#include "kadecot_names.h"
65#include "uip_adpt.h"
66
67#include <string.h>
68
69#define STATE_WAITING 0
70#define STATE_OUTPUT 1
71#define STATE_WS_OUTPUT 2
72
73#define ISO_nl 0x0a
74#define ISO_space 0x20
75#define ISO_bang 0x21
76#define ISO_percent 0x25
77#define ISO_period 0x2e
78#define ISO_slash 0x2f
79#define ISO_colon 0x3a
80
81#ifndef _MSC_VER
82#ifndef strcpy_s
83#define strcpy_s(s1, s1m, s2) strcpy(s1, s2)
84#endif
85
86#ifndef strncpy_s
87#define strncpy_s(dst, dsz, src, sz) strncpy(dst, src, sz)
88#endif
89#endif
90
[152]91#define MAX(a, b) ((a > b) ? a : b)
92
93union temp_type_t {
94 char binary[sizeof(http_content_type_binary)];
95 char html[sizeof(http_content_type_html)];
96 char css[sizeof(http_content_type_css)];
97 char js[sizeof(http_content_type_js)];
98 char json[sizeof(http_content_type_json)];
99 char png[sizeof(http_content_type_png)];
100 char gif[sizeof(http_content_type_gif)];
101 char jpg[sizeof(http_content_type_jpg)];
102 char svg[sizeof(http_content_type_svg)];
103 char plain[sizeof(http_content_type_plain)];
104};
105
106struct temp_buf_t{
107 char headers[MAX(sizeof(http_header_404), sizeof(http_header_200))
108 + sizeof(http_content_encoding_gzip)
109 + sizeof(union temp_type_t)
110 ];
111 char ws_headers[sizeof(http_header_101)
112 + sizeof(http_upgrade) + sizeof(((struct httpd_state *)0)->message.upgrade) + sizeof(http_crnl)
113 + sizeof(http_connection) + sizeof(((struct httpd_state *)0)->message.connection) + sizeof(http_crnl)
114 + sizeof(http_sec_websocket_accept) + sizeof(((struct httpd_state *)0)->message.response_key) + sizeof(http_crnl)
115 + sizeof(http_sec_websocket_protocol) + sizeof(((struct httpd_state *)0)->message.sec_websocket_protocol) + sizeof(http_crnl)
116 + sizeof(http_crnl)
117 ];
118};
119static char temp_buf[sizeof(struct temp_buf_t)];
120
[101]121int httpd_strnicmp(const char *s1, const char *s2, size_t n)
122{
123 int i;
124 char c1, c2;
125
126 for(i = 0; i < n; i++, s1++, s2++){
127 c1 = *s1;
128 c2 = *s2;
129 if(c1 == '\0' && c2 == '\0')
130 return 0;
131
132 if(c1 >= 'a' && c1 <= 'z')
133 c1 += 'A' - 'a';
134
135 if(c2 >= 'a' && c2 <= 'z')
136 c2 += 'A' - 'a';
137
138 if(c1 < c2)
139 return -1;
140
141 if(c1 > c2)
142 return 1;
143 }
144
145 return 0;
146}
147
148struct websocket *websocket_getws(ID wbsid)
149{
150 struct uip_conn *conn = uip_getconn(wbsid);
151 if (conn == NULL)
152 return NULL;
153
154 return &conn->appstate.websocket;
155}
156
157/*---------------------------------------------------------------------------*/
158static unsigned short
159generate_part_of_file(void *state)
160{
161 struct httpd_state *s = (struct httpd_state *)state;
162 int len;
163
164 if (s->file.len > uip_mss()) {
165 len = uip_mss();
166 } else {
167 len = s->file.len;
168 }
169 s->len = httpd_fs_read(&s->file, uip_appdata, len);
170
171 return s->len;
172}
173/*---------------------------------------------------------------------------*/
174static
175PT_THREAD(send_file(struct httpd_state *s))
176{
177 PSOCK_BEGIN(&s->sout);
178
179 do {
180 PSOCK_GENERATOR_SEND(&s->sout, generate_part_of_file, s);
181 s->file.len -= s->len;
182 s->file.pos += s->len;
183 } while (s->file.len > 0);
184
185 PSOCK_END(&s->sout);
186}
187/*---------------------------------------------------------------------------*/
188static
189PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr))
190{
[152]191 char *pos = temp_buf;
192 int len;
[101]193 char *ptr;
194
195 PSOCK_BEGIN(&s->sout);
196
[152]197 len = strlen(statushdr);
198 memcpy(pos, statushdr, len); pos += len;
[101]199
[152]200 len = strlen(http_content_encoding_gzip);
201 memcpy(pos, http_content_encoding_gzip, len); pos += len;
[101]202
203 ptr = strrchr(s->message.request_url, ISO_period);
204 if (ptr == NULL) {
[152]205 len = strlen(http_content_type_binary);
206 memcpy(pos, http_content_type_binary, len); pos += len;
[101]207 } else if (strncmp(http_html, ptr, 5) == 0 ||
208 strncmp(http_shtml, ptr, 6) == 0) {
[152]209 len = strlen(http_content_type_html);
210 memcpy(pos, http_content_type_html, len); pos += len;
[101]211 } else if (strncmp(http_css, ptr, 4) == 0) {
[152]212 len = strlen(http_content_type_css);
213 memcpy(pos, http_content_type_css, len); pos += len;
[101]214 } else if (strncmp(http_js, ptr, 3) == 0) {
[152]215 len = strlen(http_content_type_js);
216 memcpy(pos, http_content_type_js, len); pos += len;
[101]217 } else if (strncmp(http_json, ptr, 5) == 0) {
[152]218 len = strlen(http_content_type_json);
219 memcpy(pos, http_content_type_json, len); pos += len;
[101]220 } else if (strncmp(http_png, ptr, 4) == 0) {
[152]221 len = strlen(http_content_type_png);
222 memcpy(pos, http_content_type_png, len); pos += len;
[101]223 } else if (strncmp(http_gif, ptr, 4) == 0) {
[152]224 len = strlen(http_content_type_gif);
225 memcpy(pos, http_content_type_gif, len); pos += len;
[101]226 } else if (strncmp(http_jpg, ptr, 4) == 0) {
[152]227 len = strlen(http_content_type_jpg);
228 memcpy(pos, http_content_type_jpg, len); pos += len;
[101]229 } else if (strncmp(http_svg, ptr, 4) == 0) {
[152]230 len = strlen(http_content_type_svg);
231 memcpy(pos, http_content_type_svg, len); pos += len;
[101]232 } else {
[152]233 len = strlen(http_content_type_plain);
234 memcpy(pos, http_content_type_plain, len); pos += len;
[101]235 }
[152]236 *pos = '\0';
237
238 PSOCK_SEND(&s->sout, temp_buf, pos - temp_buf);
239
[101]240 PSOCK_END(&s->sout);
241}
242/*---------------------------------------------------------------------------*/
243static
244PT_THREAD(handle_output(struct httpd_state *s))
245{
246 char *ptr;
247
248 PT_BEGIN(&s->outputpt);
249
250 if (!httpd_fs_open(s->message.request_url, &s->file)) {
251 httpd_fs_open(http_404_html, &s->file);
252 strcpy_s(s->message.request_url, sizeof(s->message.request_url), http_404_html);
253 PT_WAIT_THREAD(&s->outputpt,
254 send_headers(s,
255 http_header_404));
256 PT_WAIT_THREAD(&s->outputpt, send_file(s));
257 } else {
258 PT_WAIT_THREAD(&s->outputpt,
259 send_headers(s,
260 http_header_200));
261 ptr = strchr(s->message.request_url, ISO_period);
262 PT_WAIT_THREAD(&s->outputpt, send_file(s));
263 }
264
265 PSOCK_CLOSE(&s->sout);
266 PT_END(&s->outputpt);
267}
268/*---------------------------------------------------------------------------*/
269static
270PT_THREAD(send_ws_headers(struct httpd_state *s, const char *statushdr))
271{
[152]272 char *pos = temp_buf;
273 int len;
274
[101]275 PSOCK_BEGIN(&s->sout);
276
[152]277 len = strlen(statushdr);
278 memcpy(pos, statushdr, len); pos += len;
[101]279
[152]280 len = strlen(http_upgrade);
281 memcpy(pos, http_upgrade, len); pos += len;
282 len = strlen(s->message.upgrade);
283 memcpy(pos, s->message.upgrade, len); pos += len;
284 len = strlen(http_crnl);
285 memcpy(pos, http_crnl, len); pos += len;
[101]286
[152]287 len = strlen(http_connection);
288 memcpy(pos, http_connection, len); pos += len;
289 len = strlen(s->message.connection);
290 memcpy(pos, s->message.connection, len); pos += len;
291 len = strlen(http_crnl);
292 memcpy(pos, http_crnl, len); pos += len;
[101]293
[152]294 len = strlen(http_sec_websocket_accept);
295 memcpy(pos, http_sec_websocket_accept, len); pos += len;
296 len = strlen(s->message.response_key);
297 memcpy(pos, s->message.response_key, len); pos += len;
298 len = strlen(http_crnl);
299 memcpy(pos, http_crnl, len); pos += len;
[101]300
[152]301 len = strlen(http_sec_websocket_protocol);
302 memcpy(pos, http_sec_websocket_protocol, len); pos += len;
303 len = strlen(s->message.sec_websocket_protocol);
304 memcpy(pos, s->message.sec_websocket_protocol, len); pos += len;
305 len = strlen(http_crnl);
306 memcpy(pos, http_crnl, len); pos += len;
[101]307
[152]308 len = strlen(http_crnl);
309 memcpy(pos, http_crnl, len); pos += len;
310 *pos = '\0';
[101]311
[152]312 PSOCK_SEND(&s->sout, temp_buf, pos - temp_buf);
313
[101]314 PSOCK_END(&s->sout);
315}
316/*---------------------------------------------------------------------------*/
317static unsigned short
318generate_part_of_ws_data(void *state)
319{
320 struct httpd_state *s = (struct httpd_state *)state;
321
322 s->len = websocket_output(&s->websocket, uip_appdata, uip_mss());
323
324 return s->len;
325}
326/*---------------------------------------------------------------------------*/
327static
328PT_THREAD(send_ws_data(struct httpd_state *s))
329{
330 PSOCK_BEGIN(&s->sout);
331
332 PSOCK_GENERATOR_SEND(&s->sout, generate_part_of_ws_data, s);
333
334 PSOCK_END(&s->sout);
335}
336/*---------------------------------------------------------------------------*/
337static
338PT_THREAD(handle_ws_output(struct httpd_state *s))
339{
340 char shaHash[20];
341 SHA_CTX sha1;
342 int len;
343
344 PT_BEGIN(&s->outputpt);
345
346 strlncat(s->message.response_key, sizeof(s->message.response_key),
347 s->message.sec_websocket_key, sizeof(s->message.sec_websocket_key));
348 len = strlncat(s->message.response_key, sizeof(s->message.response_key),
349 http_websocket_guid, sizeof(http_websocket_guid));
350 memset(shaHash, 0, sizeof(shaHash));
351 SHA1_Init(&sha1);
352 SHA1_Update(&sha1, (sha1_byte *)s->message.response_key, len);
353 SHA1_Final((sha1_byte *)shaHash, &sha1);
354 base64_encode((unsigned char *)s->message.response_key,
355 sizeof(s->message.response_key), (unsigned char *)shaHash, sizeof(shaHash));
356
357 PT_WAIT_THREAD(&s->outputpt, send_ws_headers(s, http_header_101));
358
359 s->message.response_key[0] = '\0';
360
361 do {
362 while(!websocket_newdata(&s->websocket))
363 PT_YIELD(&s->outputpt);
364
365 PT_WAIT_THREAD(&s->outputpt, send_ws_data(s));
366 } while ((s->state == STATE_WS_OUTPUT) && (!s->close_req));
367 s->state = STATE_WAITING;
368 websocket_destroy(&s->websocket);
369 s->close_req = 0;
370
371 PSOCK_CLOSE(&s->sout);
372
373 PT_END(&s->outputpt);
374}
375/*---------------------------------------------------------------------------*/
376static
377PT_THREAD(handle_input(struct httpd_state *s))
378{
379 size_t done;
380 const char *data;
381 PSOCK_BEGIN(&s->sin);
382
383 memset(&s->message, 0, sizeof(s->message));
384 http_parser_init(&s->parser, HTTP_REQUEST);
385
386 for (;;) {
387 PSOCK_WAIT_UNTIL(&s->sin, psock_newdata(&s->sin));
388
389 s->parse_pos = 0;
390 s->parse_len = uip_datalen();
391 data = &((const char *)uip_appdata)[s->parse_pos];
392 done = http_parser_execute(&s->parser, &websvr_settings, data, s->parse_len);
393 if (done != 0) {
394 s->parse_pos += done;
395 s->parse_len -= done;
396 break;
397 }
398 }
399
400 if (!s->message.message_complete_cb_called
401 && s->message.method != HTTP_GET) {
402 PSOCK_CLOSE_EXIT(&s->sin);
403 }
404
405 /* ""か"/"なら"index.html"に変更 */
406 if ((s->message.request_url[0] == '\0') || ((s->message.request_url[0] == '/') && (s->message.request_url[1] == '\0'))) {
407 strncpy_s(s->message.request_url, sizeof(s->message.request_url), http_index_html, sizeof(s->message.request_url));
408 }
409
410 /* httpd_log_file(uip_conn->ripaddr, s->message.request_url);*/
411 /* httpd_log(s->message.referer);*/
412
413 if (httpd_strnicmp(http_websocket, s->message.upgrade, sizeof(s->message.upgrade)) == 0) {
414 s->state = STATE_WS_OUTPUT;
415
416 websocket_init(&s->websocket, uip_getid((struct uip_conn *)((intptr_t)s - offsetof(struct uip_conn, appstate))));
417 for (;;) {
418 if(s->parse_len <= 0){
419 PT_YIELD(&s->sin.pt);
420 PSOCK_WAIT_UNTIL(&s->sin, psock_newdata(&s->sin));
421
422 s->parse_pos = 0;
423 s->parse_len = uip_datalen();
424 }
425 data = &((const char *)uip_appdata)[s->parse_pos];
426 done = websocket_input(&s->websocket, (void *)data, s->parse_len);
427 if ((done != 0) || (s->websocket.rstate.opecode == connection_close)) {
428 s->close_req = 1;
429 PSOCK_CLOSE_EXIT(&s->sin);
430 break;
431 }
432 s->parse_pos = s->parse_len;
433 s->parse_len = 0;
434 }
435 }
436 else {
437 s->state = STATE_OUTPUT;
438
439 while (1) {
440 PSOCK_READTO(&s->sin, ISO_nl);
441 }
442 }
443
444 PSOCK_END(&s->sin);
445}
446/*---------------------------------------------------------------------------*/
447static void
448handle_connection(struct httpd_state *s)
449{
450 handle_input(s);
451 switch (s->state) {
452 case STATE_OUTPUT:
453 handle_output(s);
454 break;
455 case STATE_WS_OUTPUT:
456 handle_ws_output(s);
457 break;
458 }
459}
460/*---------------------------------------------------------------------------*/
461void
462httpd_appcall(void)
463{
464 struct httpd_state *s = (struct httpd_state *)&(uip_conn->appstate);
465
466 if (uip_closed() || uip_aborted() || uip_timedout()) {
467 } else if (uip_connected()) {
468 if(s->state != STATE_WS_OUTPUT){
469 PSOCK_INIT(&s->sin, s->inputbuf, sizeof(s->inputbuf) - 1);
470 PSOCK_INIT(&s->sout, s->inputbuf, sizeof(s->inputbuf) - 1);
471 PT_INIT(&s->outputpt);
472 s->state = STATE_WAITING;
473 /* timer_set(&s->timer, CLOCK_SECOND * 100);*/
474 s->timer = 0;
475 handle_connection(s);
476 }
477 else {
478 handle_connection(s);
479 }
480 } else if (s != NULL) {
481 if(s->state != STATE_WS_OUTPUT){
482 if (uip_poll()) {
483 ++s->timer;
484 if (s->timer >= 20) {
485 uip_abort();
486 }
487 } else {
488 s->timer = 0;
489 }
490 }
491 handle_connection(s);
492 } else {
493 uip_abort();
494 }
495}
496/*---------------------------------------------------------------------------*/
497/**
498 * \brief Initialize the web server
499 *
500 * This function initializes the web server and should be
501 * called at system boot-up.
502 */
503void
504httpd_init(void)
505{
506 uip_listen(HTONS(41314));
507
508 httpd_fs_init();
509 kadecot_names_init();
510}
511/*---------------------------------------------------------------------------*/
512/** @} */
Note: See TracBrowser for help on using the repository browser.