blob: 7354d52f99340b20b68ef0b0b5c316b9b5feb344 [file] [log] [blame]
Andy Greena1ce6be2013-01-18 11:43:21 +08001/*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation:
9 * version 2.1 of the License.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301 USA
20 */
21
22
23#include "private-libwebsockets.h"
24
Andy Greene38031a2014-04-03 08:24:29 +080025int lws_context_init_server(struct lws_context_creation_info *info,
26 struct libwebsocket_context *context)
27{
28 int n;
29 int sockfd;
30 struct sockaddr_in sin;
31 socklen_t len = sizeof(sin);
32 int opt = 1;
33 struct libwebsocket *wsi;
34#ifdef LWS_USE_IPV6
35 struct sockaddr_in6 serv_addr6;
36#endif
37 struct sockaddr_in serv_addr4;
38 struct sockaddr *v;
39
40 /* set up our external listening socket we serve on */
41
42 if (info->port == CONTEXT_PORT_NO_LISTEN)
43 return 0;
44
45#ifdef LWS_USE_IPV6
46 if (LWS_IPV6_ENABLED(context))
47 sockfd = socket(AF_INET6, SOCK_STREAM, 0);
48 else
49#endif
50 sockfd = socket(AF_INET, SOCK_STREAM, 0);
51
52 if (sockfd < 0) {
53 lwsl_err("ERROR opening socket\n");
54 return 1;
55 }
56
57 /*
58 * allow us to restart even if old sockets in TIME_WAIT
59 */
Andy Greenf38e7862014-11-30 13:07:11 +080060 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
Andy Green9c8d5902014-11-30 13:30:57 +080061 (const void *)&opt, sizeof(opt)) < 0) {
62 compatible_close(sockfd);
Andy Greenf38e7862014-11-30 13:07:11 +080063 return 1;
Andy Green9c8d5902014-11-30 13:30:57 +080064 }
Andy Greene38031a2014-04-03 08:24:29 +080065
66 lws_plat_set_socket_options(context, sockfd);
67
68#ifdef LWS_USE_IPV6
69 if (LWS_IPV6_ENABLED(context)) {
70 v = (struct sockaddr *)&serv_addr6;
71 n = sizeof(struct sockaddr_in6);
72 bzero((char *) &serv_addr6, sizeof(serv_addr6));
73 serv_addr6.sin6_addr = in6addr_any;
74 serv_addr6.sin6_family = AF_INET6;
75 serv_addr6.sin6_port = htons(info->port);
76 } else
77#endif
78 {
79 v = (struct sockaddr *)&serv_addr4;
80 n = sizeof(serv_addr4);
81 bzero((char *) &serv_addr4, sizeof(serv_addr4));
82 serv_addr4.sin_addr.s_addr = INADDR_ANY;
83 serv_addr4.sin_family = AF_INET;
Andy Greene38031a2014-04-03 08:24:29 +080084
85 if (info->iface) {
86 if (interface_to_sa(context, info->iface,
87 (struct sockaddr_in *)v, n) < 0) {
88 lwsl_err("Unable to find interface %s\n",
89 info->iface);
90 compatible_close(sockfd);
91 return 1;
92 }
93 }
vpeter47cc7ae42014-04-27 12:32:15 +020094
95 serv_addr4.sin_port = htons(info->port);
Andy Greene38031a2014-04-03 08:24:29 +080096 } /* ipv4 */
97
98 n = bind(sockfd, v, n);
99 if (n < 0) {
100 lwsl_err("ERROR on binding to port %d (%d %d)\n",
101 info->port, n, LWS_ERRNO);
102 compatible_close(sockfd);
103 return 1;
104 }
Alejandro Mery6ff28242014-12-04 23:59:35 +0100105
Andy Greene38031a2014-04-03 08:24:29 +0800106 if (getsockname(sockfd, (struct sockaddr *)&sin, &len) == -1)
107 lwsl_warn("getsockname: %s\n", strerror(LWS_ERRNO));
108 else
109 info->port = ntohs(sin.sin_port);
110
111 context->listen_port = info->port;
112
Alejandro Mery6ff28242014-12-04 23:59:35 +0100113 wsi = lws_zalloc(sizeof(struct libwebsocket));
Andy Greene38031a2014-04-03 08:24:29 +0800114 if (wsi == NULL) {
115 lwsl_err("Out of mem\n");
116 compatible_close(sockfd);
117 return 1;
118 }
Andy Greene38031a2014-04-03 08:24:29 +0800119 wsi->sock = sockfd;
120 wsi->mode = LWS_CONNMODE_SERVER_LISTENER;
121
122 insert_wsi_socket_into_fds(context, wsi);
123
124 context->listen_service_modulo = LWS_LISTEN_SERVICE_MODULO;
125 context->listen_service_count = 0;
126 context->listen_service_fd = sockfd;
127
128 listen(sockfd, LWS_SOMAXCONN);
129 lwsl_notice(" Listening on port %d\n", info->port);
Alejandro Mery6ff28242014-12-04 23:59:35 +0100130
Andy Greene38031a2014-04-03 08:24:29 +0800131 return 0;
132}
133
Andy Greend99476b2014-04-03 08:40:05 +0800134int
135_libwebsocket_rx_flow_control(struct libwebsocket *wsi)
136{
137 struct libwebsocket_context *context = wsi->protocol->owning_server;
138
139 /* there is no pending change */
Andy Green024eb6c2014-10-08 12:00:53 +0800140 if (!(wsi->rxflow_change_to & LWS_RXFLOW_PENDING_CHANGE))
Andy Greend99476b2014-04-03 08:40:05 +0800141 return 0;
142
143 /* stuff is still buffered, not ready to really accept new input */
Andy Green024eb6c2014-10-08 12:00:53 +0800144 if (wsi->rxflow_buffer) {
Andy Greend99476b2014-04-03 08:40:05 +0800145 /* get ourselves called back to deal with stashed buffer */
146 libwebsocket_callback_on_writable(context, wsi);
147 return 0;
148 }
149
150 /* pending is cleared, we can change rxflow state */
151
Andy Green024eb6c2014-10-08 12:00:53 +0800152 wsi->rxflow_change_to &= ~LWS_RXFLOW_PENDING_CHANGE;
Andy Greend99476b2014-04-03 08:40:05 +0800153
154 lwsl_info("rxflow: wsi %p change_to %d\n", wsi,
Andy Green024eb6c2014-10-08 12:00:53 +0800155 wsi->rxflow_change_to & LWS_RXFLOW_ALLOW);
Andy Greend99476b2014-04-03 08:40:05 +0800156
157 /* adjust the pollfd for this wsi */
158
Andy Green024eb6c2014-10-08 12:00:53 +0800159 if (wsi->rxflow_change_to & LWS_RXFLOW_ALLOW) {
Andy Greena717df22014-04-11 13:14:37 +0800160 if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
161 lwsl_info("%s: fail\n", __func__);
Andy Greend99476b2014-04-03 08:40:05 +0800162 return -1;
Andy Greena717df22014-04-11 13:14:37 +0800163 }
Andy Greend99476b2014-04-03 08:40:05 +0800164 } else
165 if (lws_change_pollfd(wsi, LWS_POLLIN, 0))
166 return -1;
167
Andy Greenf004ec52014-04-12 11:47:25 +0800168 return 0;
Andy Greend99476b2014-04-03 08:40:05 +0800169}
170
Andy Green024eb6c2014-10-08 12:00:53 +0800171int lws_http_action(struct libwebsocket_context *context,
172 struct libwebsocket *wsi)
173{
174 char *uri_ptr = NULL;
175 int uri_len = 0;
176 enum http_version request_version;
177 enum http_connection_type connection_type;
178 int http_version_len;
179 char content_length_str[32];
180 char http_version_str[10];
181 char http_conn_str[20];
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800182 int n, count = 0;
183 static const unsigned char methods[] = {
184 WSI_TOKEN_GET_URI,
185 WSI_TOKEN_POST_URI,
186 WSI_TOKEN_OPTIONS_URI,
187 WSI_TOKEN_PUT_URI,
188 WSI_TOKEN_PATCH_URI,
189 WSI_TOKEN_DELETE_URI,
190#ifdef LWS_USE_HTTP2
191 WSI_TOKEN_HTTP_COLON_PATH,
192#endif
193 };
Andy Green93d947c2015-02-20 07:37:20 +0800194#ifdef _DEBUG
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800195 static const char * const method_names[] = {
196 "GET", "POST", "OPTIONS", "PUT", "PATCH", "DELETE",
197#ifdef LWS_USE_HTTP2
198 ":path",
199#endif
200 };
Andy Green93d947c2015-02-20 07:37:20 +0800201#endif
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800202
Andy Green024eb6c2014-10-08 12:00:53 +0800203 /* it's not websocket.... shall we accept it as http? */
204
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800205 for (n = 0; n < ARRAY_SIZE(methods); n++)
206 if (lws_hdr_total_length(wsi, methods[n]))
207 count++;
208 if (!count) {
Andy Green024eb6c2014-10-08 12:00:53 +0800209 lwsl_warn("Missing URI in HTTP request\n");
210 goto bail_nuke_ah;
211 }
212
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800213 if (count != 1) {
214 lwsl_warn("multiple methods?\n");
Andy Green024eb6c2014-10-08 12:00:53 +0800215 goto bail_nuke_ah;
216 }
217
218 if (libwebsocket_ensure_user_space(wsi))
219 goto bail_nuke_ah;
220
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800221 for (n = 0; n < ARRAY_SIZE(methods); n++)
222 if (lws_hdr_total_length(wsi, methods[n])) {
223 uri_ptr = lws_hdr_simple_ptr(wsi, methods[n]);
224 uri_len = lws_hdr_total_length(wsi, methods[n]);
225 lwsl_info("Method: %s request for '%s'\n",
226 method_names[n], uri_ptr);
227 break;
228 }
Andy Green024eb6c2014-10-08 12:00:53 +0800229
230 /* HTTP header had a content length? */
231
232 wsi->u.http.content_length = 0;
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800233 if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) ||
234 lws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI) ||
235 lws_hdr_total_length(wsi, WSI_TOKEN_PUT_URI))
Andy Green024eb6c2014-10-08 12:00:53 +0800236 wsi->u.http.content_length = 100 * 1024 * 1024;
237
238 if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
239 lws_hdr_copy(wsi, content_length_str,
240 sizeof(content_length_str) - 1,
241 WSI_TOKEN_HTTP_CONTENT_LENGTH);
242 wsi->u.http.content_length = atoi(content_length_str);
243 }
244
245 /* http_version? Default to 1.0, override with token: */
246 request_version = HTTP_VERSION_1_0;
247
248 /* Works for single digit HTTP versions. : */
249 http_version_len = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP);
250 if (http_version_len > 7) {
251 lws_hdr_copy(wsi, http_version_str,
252 sizeof(http_version_str) - 1, WSI_TOKEN_HTTP);
253 if (http_version_str[5] == '1' && http_version_str[7] == '1')
254 request_version = HTTP_VERSION_1_1;
255 }
256 wsi->u.http.request_version = request_version;
257
258 /* HTTP/1.1 defaults to "keep-alive", 1.0 to "close" */
259 if (request_version == HTTP_VERSION_1_1)
260 connection_type = HTTP_CONNECTION_KEEP_ALIVE;
261 else
262 connection_type = HTTP_CONNECTION_CLOSE;
263
264 /* Override default if http "Connection:" header: */
265 if (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION)) {
266 lws_hdr_copy(wsi, http_conn_str, sizeof(http_conn_str) - 1,
267 WSI_TOKEN_CONNECTION);
268 http_conn_str[sizeof(http_conn_str) - 1] = '\0';
269 if (!strcasecmp(http_conn_str, "keep-alive"))
270 connection_type = HTTP_CONNECTION_KEEP_ALIVE;
271 else
272 if (strcasecmp(http_conn_str, "close"))
273 connection_type = HTTP_CONNECTION_CLOSE;
274 }
275 wsi->u.http.connection_type = connection_type;
276
277 n = 0;
278 if (wsi->protocol->callback)
279 n = wsi->protocol->callback(context, wsi,
280 LWS_CALLBACK_FILTER_HTTP_CONNECTION,
281 wsi->user_space, uri_ptr, uri_len);
282
283 if (!n) {
284 /*
285 * if there is content supposed to be coming,
286 * put a timeout on it having arrived
287 */
288 libwebsocket_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,
289 AWAITING_TIMEOUT);
290
291 if (wsi->protocol->callback)
292 n = wsi->protocol->callback(context, wsi,
293 LWS_CALLBACK_HTTP,
294 wsi->user_space, uri_ptr, uri_len);
295 }
296
297 /* now drop the header info we kept a pointer to */
Alejandro Meryac3ec392014-12-05 00:09:20 +0100298 lws_free2(wsi->u.http.ah);
Andy Green024eb6c2014-10-08 12:00:53 +0800299
300 if (n) {
301 lwsl_info("LWS_CALLBACK_HTTP closing\n");
302 return 1; /* struct ah ptr already nuked */ }
303
304 /*
305 * If we're not issuing a file, check for content_length or
306 * HTTP keep-alive. No keep-alive header allocation for
307 * ISSUING_FILE, as this uses HTTP/1.0.
308 *
309 * In any case, return 0 and let libwebsocket_read decide how to
310 * proceed based on state
311 */
312 if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE)
313 /* Prepare to read body if we have a content length: */
314 if (wsi->u.http.content_length > 0)
315 wsi->state = WSI_STATE_HTTP_BODY;
316
317 return 0;
318
319bail_nuke_ah:
320 /* drop the header info */
Alejandro Meryac3ec392014-12-05 00:09:20 +0100321 lws_free2(wsi->u.hdr.ah);
322
Andy Green024eb6c2014-10-08 12:00:53 +0800323 return 1;
324}
325
Andy Greenaad2eac2014-04-03 09:03:37 +0800326
327int lws_handshake_server(struct libwebsocket_context *context,
328 struct libwebsocket *wsi, unsigned char **buf, size_t len)
329{
330 struct allocated_headers *ah;
Andy Green024eb6c2014-10-08 12:00:53 +0800331 int protocol_len;
Andy Green7a8d86e2014-07-19 06:52:39 +0800332 char protocol_list[128];
333 char protocol_name[32];
Andy Green7a8d86e2014-07-19 06:52:39 +0800334 char *p;
335 int n, hit;
Andy Greenaad2eac2014-04-03 09:03:37 +0800336
337 /* LWS_CONNMODE_WS_SERVING */
338
339 while (len--) {
Andrew Canaday74b4a652014-06-29 00:25:19 -0400340 if (libwebsocket_parse(context, wsi, *(*buf)++)) {
Andy Greenaad2eac2014-04-03 09:03:37 +0800341 lwsl_info("libwebsocket_parse failed\n");
342 goto bail_nuke_ah;
343 }
344
345 if (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE)
346 continue;
347
348 lwsl_parser("libwebsocket_parse sees parsing complete\n");
349
350 wsi->mode = LWS_CONNMODE_PRE_WS_SERVING_ACCEPT;
351 libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
352
353 /* is this websocket protocol or normal http 1.0? */
354
355 if (!lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE) ||
356 !lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION)) {
Andy Green024eb6c2014-10-08 12:00:53 +0800357
Andy Greenaad2eac2014-04-03 09:03:37 +0800358 ah = wsi->u.hdr.ah;
Andy Green024eb6c2014-10-08 12:00:53 +0800359
Andy Green44c11612014-11-08 11:18:47 +0800360 lws_union_transition(wsi, LWS_CONNMODE_HTTP_SERVING_ACCEPTED);
Andy Greenaad2eac2014-04-03 09:03:37 +0800361 wsi->state = WSI_STATE_HTTP;
362 wsi->u.http.fd = LWS_INVALID_FILE;
363
364 /* expose it at the same offset as u.hdr */
365 wsi->u.http.ah = ah;
Andy Green024eb6c2014-10-08 12:00:53 +0800366
367 n = lws_http_action(context, wsi);
Andy Greenaad2eac2014-04-03 09:03:37 +0800368
Andy Green024eb6c2014-10-08 12:00:53 +0800369 return n;
Andy Greenaad2eac2014-04-03 09:03:37 +0800370 }
371
Andy Green2af58562014-09-30 08:15:49 +0800372 if (!strcasecmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE),
373 "websocket"))
374 goto upgrade_ws;
Andy Green024eb6c2014-10-08 12:00:53 +0800375#ifdef LWS_USE_HTTP2
Andy Greena54f2322014-09-30 09:43:14 +0800376 if (!strcasecmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE),
Andy Greenb08cb502014-09-30 16:33:56 +0800377 "h2c-14"))
Andy Greena54f2322014-09-30 09:43:14 +0800378 goto upgrade_h2c;
Andy Green024eb6c2014-10-08 12:00:53 +0800379#endif
Andy Green2af58562014-09-30 08:15:49 +0800380 /* dunno what he wanted to upgrade to */
381 goto bail_nuke_ah;
Andy Greena54f2322014-09-30 09:43:14 +0800382
Andy Green024eb6c2014-10-08 12:00:53 +0800383#ifdef LWS_USE_HTTP2
384upgrade_h2c:
385 if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP2_SETTINGS)) {
386 lwsl_err("missing http2_settings\n");
Andy Greena54f2322014-09-30 09:43:14 +0800387 goto bail_nuke_ah;
388 }
389
Andy Green024eb6c2014-10-08 12:00:53 +0800390 lwsl_err("h2c upgrade...\n");
Andy Greena54f2322014-09-30 09:43:14 +0800391
Andy Green024eb6c2014-10-08 12:00:53 +0800392 p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP2_SETTINGS);
393 /* convert the peer's HTTP-Settings */
394 n = lws_b64_decode_string(p, protocol_list, sizeof(protocol_list));
395 if (n < 0) {
396 lwsl_parser("HTTP2_SETTINGS too long\n");
397 return 1;
398 }
399
400 /* adopt the header info */
401
402 ah = wsi->u.hdr.ah;
Andy Greena54f2322014-09-30 09:43:14 +0800403
Andy Green44c11612014-11-08 11:18:47 +0800404 lws_union_transition(wsi, LWS_CONNMODE_HTTP2_SERVING);
Andy Green2af58562014-09-30 08:15:49 +0800405
Andy Green024eb6c2014-10-08 12:00:53 +0800406 /* http2 union member has http union struct at start */
407 wsi->u.http.ah = ah;
408
409 lws_http2_init(&wsi->u.http2.peer_settings);
410 lws_http2_init(&wsi->u.http2.my_settings);
411
412 /* HTTP2 union */
413
414 lws_http2_interpret_settings_payload(&wsi->u.http2.peer_settings, (unsigned char *)protocol_list, n);
415
416 strcpy(protocol_list,
417 "HTTP/1.1 101 Switching Protocols\x0d\x0a"
418 "Connection: Upgrade\x0d\x0a"
419 "Upgrade: h2c\x0d\x0a\x0d\x0a");
Andy Green97ee57f2014-10-29 09:39:08 +0800420 n = lws_issue_raw(wsi, (unsigned char *)protocol_list,
421 strlen(protocol_list));
422 if (n != strlen(protocol_list)) {
Andy Green024eb6c2014-10-08 12:00:53 +0800423 lwsl_debug("http2 switch: ERROR writing to socket\n");
424 return 1;
425 }
426
427 wsi->state = WSI_STATE_HTTP2_AWAIT_CLIENT_PREFACE;
428
Andy Greena54f2322014-09-30 09:43:14 +0800429 return 0;
Andy Green024eb6c2014-10-08 12:00:53 +0800430#endif
Andy Greena54f2322014-09-30 09:43:14 +0800431
Andy Green2af58562014-09-30 08:15:49 +0800432upgrade_ws:
Andy Greenaad2eac2014-04-03 09:03:37 +0800433 if (!wsi->protocol)
434 lwsl_err("NULL protocol at libwebsocket_read\n");
435
436 /*
437 * It's websocket
438 *
Andy Green7a8d86e2014-07-19 06:52:39 +0800439 * Select the first protocol we support from the list
440 * the client sent us.
441 *
442 * Copy it to remove header fragmentation
Andy Greenaad2eac2014-04-03 09:03:37 +0800443 */
444
Andy Green7a8d86e2014-07-19 06:52:39 +0800445 if (lws_hdr_copy(wsi, protocol_list, sizeof(protocol_list) - 1,
446 WSI_TOKEN_PROTOCOL) < 0) {
447 lwsl_err("protocol list too long");
448 goto bail_nuke_ah;
449 }
Andy Greenaad2eac2014-04-03 09:03:37 +0800450
Andy Green7a8d86e2014-07-19 06:52:39 +0800451 protocol_len = lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL);
452 protocol_list[protocol_len] = '\0';
453 p = protocol_list;
454 hit = 0;
Andy Greenaad2eac2014-04-03 09:03:37 +0800455
Andy Green7a8d86e2014-07-19 06:52:39 +0800456 while (*p && !hit) {
457 n = 0;
458 while (n < sizeof(protocol_name) - 1 && *p && *p !=',')
459 protocol_name[n++] = *p++;
460 protocol_name[n] = '\0';
461 if (*p)
462 p++;
463
464 lwsl_info("checking %s\n", protocol_name);
465
466 n = 0;
Andy Greenf14ea7a2014-11-30 12:45:39 +0800467 while (wsi->protocol && context->protocols[n].callback) {
Andy Greenafa10d52014-08-11 09:11:57 +0800468 if (!wsi->protocol->name) {
469 n++;
Andy Green7a8d86e2014-07-19 06:52:39 +0800470 continue;
Andy Greenafa10d52014-08-11 09:11:57 +0800471 }
Andy Green7a8d86e2014-07-19 06:52:39 +0800472 if (!strcmp(context->protocols[n].name,
473 protocol_name)) {
474 lwsl_info("prot match %d\n", n);
475 wsi->protocol = &context->protocols[n];
476 hit = 1;
477 break;
478 }
479
480 n++;
481 }
Andy Greenaad2eac2014-04-03 09:03:37 +0800482 }
483
484 /* we didn't find a protocol he wanted? */
485
Andy Green7a8d86e2014-07-19 06:52:39 +0800486 if (!hit) {
Andy Greenaad2eac2014-04-03 09:03:37 +0800487 if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL) ==
488 NULL) {
Andy Green7a8d86e2014-07-19 06:52:39 +0800489 /*
490 * some clients only have one protocol and
491 * do not sent the protocol list header...
492 * allow it and match to protocol 0
493 */
494 lwsl_info("defaulting to prot 0 handler\n");
Andy Greenaad2eac2014-04-03 09:03:37 +0800495 wsi->protocol = &context->protocols[0];
496 } else {
Andy Green7a8d86e2014-07-19 06:52:39 +0800497 lwsl_err("No protocol from list \"%s\" supported\n",
498 protocol_list);
Andy Greenaad2eac2014-04-03 09:03:37 +0800499 goto bail_nuke_ah;
500 }
501 }
502
503 /* allocate wsi->user storage */
504 if (libwebsocket_ensure_user_space(wsi))
505 goto bail_nuke_ah;
506
507 /*
508 * Give the user code a chance to study the request and
509 * have the opportunity to deny it
510 */
511
512 if ((wsi->protocol->callback)(wsi->protocol->owning_server, wsi,
513 LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,
514 wsi->user_space,
515 lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL), 0)) {
516 lwsl_warn("User code denied connection\n");
517 goto bail_nuke_ah;
518 }
519
520
521 /*
522 * Perform the handshake according to the protocol version the
523 * client announced
524 */
525
526 switch (wsi->ietf_spec_revision) {
527 case 13:
528 lwsl_parser("lws_parse calling handshake_04\n");
529 if (handshake_0405(context, wsi)) {
530 lwsl_info("hs0405 has failed the connection\n");
531 goto bail_nuke_ah;
532 }
533 break;
534
535 default:
536 lwsl_warn("Unknown client spec version %d\n",
537 wsi->ietf_spec_revision);
538 goto bail_nuke_ah;
539 }
540
541 /* drop the header info -- no bail_nuke_ah after this */
Andrew Canadaya19d4852014-11-07 11:21:09 +0800542 lws_free_header_table(wsi);
Andy Greenaad2eac2014-04-03 09:03:37 +0800543
Andy Green44c11612014-11-08 11:18:47 +0800544 lws_union_transition(wsi, LWS_CONNMODE_WS_SERVING);
Andy Greenaad2eac2014-04-03 09:03:37 +0800545
546 /*
547 * create the frame buffer for this connection according to the
548 * size mentioned in the protocol definition. If 0 there, use
549 * a big default for compatibility
550 */
551
552 n = wsi->protocol->rx_buffer_size;
553 if (!n)
554 n = LWS_MAX_SOCKET_IO_BUF;
555 n += LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING;
Alejandro Mery6ff28242014-12-04 23:59:35 +0100556 wsi->u.ws.rx_user_buffer = lws_malloc(n);
Andy Greenaad2eac2014-04-03 09:03:37 +0800557 if (!wsi->u.ws.rx_user_buffer) {
558 lwsl_err("Out of Mem allocating rx buffer %d\n", n);
559 return 1;
560 }
561 lwsl_info("Allocating RX buffer %d\n", n);
562
563 if (setsockopt(wsi->sock, SOL_SOCKET, SO_SNDBUF, (const char *)&n, sizeof n)) {
564 lwsl_warn("Failed to set SNDBUF to %d", n);
565 return 1;
566 }
567
568 lwsl_parser("accepted v%02d connection\n",
569 wsi->ietf_spec_revision);
570 } /* while all chars are handled */
571
572 return 0;
573
574bail_nuke_ah:
575 /* drop the header info */
Andrew Canadaya19d4852014-11-07 11:21:09 +0800576 lws_free_header_table(wsi);
Andy Greenaad2eac2014-04-03 09:03:37 +0800577 return 1;
578}
579
Andy Greena1ce6be2013-01-18 11:43:21 +0800580struct libwebsocket *
581libwebsocket_create_new_server_wsi(struct libwebsocket_context *context)
582{
583 struct libwebsocket *new_wsi;
Andy Greena1ce6be2013-01-18 11:43:21 +0800584
Alejandro Mery6ff28242014-12-04 23:59:35 +0100585 new_wsi = lws_zalloc(sizeof(struct libwebsocket));
Andy Greena1ce6be2013-01-18 11:43:21 +0800586 if (new_wsi == NULL) {
587 lwsl_err("Out of memory for new connection\n");
588 return NULL;
589 }
590
Andy Greena1ce6be2013-01-18 11:43:21 +0800591 new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
Andy Green024eb6c2014-10-08 12:00:53 +0800592 new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
Andy Greena1ce6be2013-01-18 11:43:21 +0800593
594 /* intialize the instance struct */
595
596 new_wsi->state = WSI_STATE_HTTP;
Andy Greena1ce6be2013-01-18 11:43:21 +0800597 new_wsi->mode = LWS_CONNMODE_HTTP_SERVING;
Andy Green224149a2013-02-11 21:43:41 +0800598 new_wsi->hdr_parsing_completed = 0;
Andy Greena1ce6be2013-01-18 11:43:21 +0800599
Andy Green16ab3182013-02-10 18:02:31 +0800600 if (lws_allocate_header_table(new_wsi)) {
Alejandro Mery6ff28242014-12-04 23:59:35 +0100601 lws_free(new_wsi);
Andy Green16ab3182013-02-10 18:02:31 +0800602 return NULL;
Andy Greena1ce6be2013-01-18 11:43:21 +0800603 }
604
605 /*
606 * these can only be set once the protocol is known
607 * we set an unestablished connection's protocol pointer
608 * to the start of the supported list, so it can look
609 * for matching ones during the handshake
610 */
611 new_wsi->protocol = context->protocols;
612 new_wsi->user_space = NULL;
Andy Greena1ce6be2013-01-18 11:43:21 +0800613 new_wsi->ietf_spec_revision = 0;
614
Andy Green76b6ea12014-02-15 19:25:50 +0800615 /*
616 * outermost create notification for wsi
617 * no user_space because no protocol selection
618 */
619 context->protocols[0].callback(context, new_wsi,
620 LWS_CALLBACK_WSI_CREATE, NULL, NULL, 0);
621
Andy Greena1ce6be2013-01-18 11:43:21 +0800622 return new_wsi;
623}
624
Andy Green91b05892014-10-17 08:38:44 +0800625/**
626 * lws_http_transaction_completed() - wait for new http transaction or close
627 * @wsi: websocket connection
628 *
629 * Returns 1 if the HTTP connection must close now
630 * Returns 0 and resets connection to wait for new HTTP header /
631 * transaction if possible
632 */
633
634LWS_VISIBLE
635int lws_http_transaction_completed(struct libwebsocket *wsi)
636{
637 /* if we can't go back to accept new headers, drop the connection */
638 if (wsi->u.http.connection_type != HTTP_CONNECTION_KEEP_ALIVE) {
639 lwsl_info("%s: close connection\n", __func__);
640 return 1;
641 }
642
643 /* otherwise set ourselves up ready to go again */
644 wsi->state = WSI_STATE_HTTP;
645
646 lwsl_info("%s: await new transaction\n", __func__);
647
648 return 0;
649}
650
Andy Greena1ce6be2013-01-18 11:43:21 +0800651int lws_server_socket_service(struct libwebsocket_context *context,
Patrick Gansterer73882e42014-03-29 08:25:58 +0100652 struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd)
Andy Greena1ce6be2013-01-18 11:43:21 +0800653{
Andy Greencdb9bf92014-04-12 10:07:02 +0800654 struct libwebsocket *new_wsi = NULL;
655 int accept_fd = 0;
Bob Robertsac049112013-04-25 09:16:30 +0800656 socklen_t clilen;
Andy Greena1ce6be2013-01-18 11:43:21 +0800657 struct sockaddr_in cli_addr;
658 int n;
Patrick Ganstererac49f1e2014-03-30 10:18:51 +0200659 int len;
Andy Greena1ce6be2013-01-18 11:43:21 +0800660
661 switch (wsi->mode) {
662
663 case LWS_CONNMODE_HTTP_SERVING:
Andy Green7cf6cb02013-05-19 14:04:10 +0800664 case LWS_CONNMODE_HTTP_SERVING_ACCEPTED:
Andy Green024eb6c2014-10-08 12:00:53 +0800665 case LWS_CONNMODE_HTTP2_SERVING:
Andy Greena1ce6be2013-01-18 11:43:21 +0800666
667 /* handle http headers coming in */
668
Andy Green2764eba2013-12-09 14:16:17 +0800669 /* pending truncated sends have uber priority */
670
Andrew Canadayaf8db352014-08-23 21:45:12 -0400671 if (wsi->truncated_send_len) {
Patrick Ganstererb47f87b2014-03-30 09:18:05 +0200672 if (pollfd->revents & LWS_POLLOUT)
Andy Greena1a24d22014-04-10 14:25:24 +0800673 if (lws_issue_raw(wsi, wsi->truncated_send_malloc +
Andy Green2764eba2013-12-09 14:16:17 +0800674 wsi->truncated_send_offset,
Andy Greena1a24d22014-04-10 14:25:24 +0800675 wsi->truncated_send_len) < 0) {
676 lwsl_info("closing from socket service\n");
677 return -1;
678 }
Andy Green2764eba2013-12-09 14:16:17 +0800679 /*
680 * we can't afford to allow input processing send
681 * something new, so spin around he event loop until
682 * he doesn't have any partials
683 */
684 break;
685 }
686
Andy Greena1ce6be2013-01-18 11:43:21 +0800687 /* any incoming data ready? */
688
Patrick Ganstererb47f87b2014-03-30 09:18:05 +0200689 if (pollfd->revents & LWS_POLLIN) {
Andy Green1f5c9f02014-10-09 08:14:30 +0800690 len = lws_ssl_capable_read(context, wsi,
Andy Greenb5b23192013-02-11 17:13:32 +0800691 context->service_buffer,
Andy Green78f266a2014-04-05 16:48:48 +0100692 sizeof(context->service_buffer));
693 switch (len) {
694 case 0:
Andy Green224149a2013-02-11 21:43:41 +0800695 lwsl_info("lws_server_skt_srv: read 0 len\n");
696 /* lwsl_info(" state=%d\n", wsi->state); */
697 if (!wsi->hdr_parsing_completed)
Andrew Canadaya19d4852014-11-07 11:21:09 +0800698 lws_free_header_table(wsi);
Andy Green78f266a2014-04-05 16:48:48 +0100699 /* fallthru */
700 case LWS_SSL_CAPABLE_ERROR:
Andy Greenb5b23192013-02-11 17:13:32 +0800701 libwebsocket_close_and_free_session(
Andy Green78f266a2014-04-05 16:48:48 +0100702 context, wsi,
703 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greena1ce6be2013-01-18 11:43:21 +0800704 return 0;
Andy Green78f266a2014-04-05 16:48:48 +0100705 case LWS_SSL_CAPABLE_MORE_SERVICE:
Christian Schüldtfde93792014-10-09 08:37:12 +0800706 goto try_pollout;
Andy Greena1ce6be2013-01-18 11:43:21 +0800707 }
708
Andy Greena1a24d22014-04-10 14:25:24 +0800709 /* just ignore incoming if waiting for close */
710 if (wsi->state != WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
711
712 /* hm this may want to send (via HTTP callback for example) */
Andy Greena1a24d22014-04-10 14:25:24 +0800713 n = libwebsocket_read(context, wsi,
714 context->service_buffer, len);
715 if (n < 0)
716 /* we closed wsi */
717 return 0;
Andy Green2764eba2013-12-09 14:16:17 +0800718
Andy Greena1a24d22014-04-10 14:25:24 +0800719 /* hum he may have used up the writability above */
720 break;
721 }
Andy Greena1ce6be2013-01-18 11:43:21 +0800722 }
723
Christian Schüldtfde93792014-10-09 08:37:12 +0800724try_pollout:
Andy Greena1ce6be2013-01-18 11:43:21 +0800725 /* this handles POLLOUT for http serving fragments */
726
Patrick Ganstererb47f87b2014-03-30 09:18:05 +0200727 if (!(pollfd->revents & LWS_POLLOUT))
Andy Greena1ce6be2013-01-18 11:43:21 +0800728 break;
729
730 /* one shot */
Andy Green158e8042014-04-02 14:25:10 +0800731 if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
732 goto fail;
Andy Greena717df22014-04-11 13:14:37 +0800733
734 lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_WRITE);
Andy Green7a132792013-12-18 09:48:26 +0800735
Andy Green54cb3462013-02-14 22:23:54 +0800736 if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE) {
737 n = user_callback_handle_rxflow(
738 wsi->protocol->callback,
739 wsi->protocol->owning_server,
740 wsi, LWS_CALLBACK_HTTP_WRITEABLE,
741 wsi->user_space,
742 NULL,
743 0);
744 if (n < 0)
Andy Green28e2ab62014-11-30 13:35:24 +0800745 goto fail;
Andy Greena1ce6be2013-01-18 11:43:21 +0800746 break;
Andy Green54cb3462013-02-14 22:23:54 +0800747 }
Andy Greena1ce6be2013-01-18 11:43:21 +0800748
Andy Green91b05892014-10-17 08:38:44 +0800749 /* >0 == completion, <0 == error */
750 n = libwebsockets_serve_http_file_fragment(context, wsi);
751 if (n < 0 || (n > 0 && lws_http_transaction_completed(wsi)))
Andy Green28e2ab62014-11-30 13:35:24 +0800752 goto fail;
Andy Greena1ce6be2013-01-18 11:43:21 +0800753 break;
754
755 case LWS_CONNMODE_SERVER_LISTENER:
756
757 /* pollin means a client has connected to us then */
758
Patrick Ganstererb47f87b2014-03-30 09:18:05 +0200759 if (!(pollfd->revents & LWS_POLLIN))
Andy Greena1ce6be2013-01-18 11:43:21 +0800760 break;
761
762 /* listen socket got an unencrypted connection... */
763
764 clilen = sizeof(cli_addr);
Andy Greene000a702013-01-29 12:37:35 +0800765 lws_latency_pre(context, wsi);
Andy Greena1ce6be2013-01-18 11:43:21 +0800766 accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
767 &clilen);
Andy Greenb5b23192013-02-11 17:13:32 +0800768 lws_latency(context, wsi,
769 "unencrypted accept LWS_CONNMODE_SERVER_LISTENER",
770 accept_fd, accept_fd >= 0);
Andy Greena1ce6be2013-01-18 11:43:21 +0800771 if (accept_fd < 0) {
Patrick Gansterer2dbd8372014-02-28 12:37:52 +0100772 if (LWS_ERRNO == LWS_EAGAIN || LWS_ERRNO == LWS_EWOULDBLOCK) {
Andy Greene2160712013-01-28 12:19:10 +0800773 lwsl_debug("accept asks to try again\n");
774 break;
775 }
Patrick Gansterer2dbd8372014-02-28 12:37:52 +0100776 lwsl_warn("ERROR on accept: %s\n", strerror(LWS_ERRNO));
Andy Greena1ce6be2013-01-18 11:43:21 +0800777 break;
778 }
779
Andy Green158e8042014-04-02 14:25:10 +0800780 lws_plat_set_socket_options(context, accept_fd);
Andy Green6f047ee2013-01-28 11:23:52 +0800781
Andy Greena1ce6be2013-01-18 11:43:21 +0800782 /*
783 * look at who we connected to and give user code a chance
784 * to reject based on client IP. There's no protocol selected
785 * yet so we issue this to protocols[0]
786 */
787
788 if ((context->protocols[0].callback)(context, wsi,
789 LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
Edwin van den Oetelaar8c8a8e12013-02-20 20:56:59 +0800790 NULL, (void *)(long)accept_fd, 0)) {
Andy Greena1ce6be2013-01-18 11:43:21 +0800791 lwsl_debug("Callback denied network connection\n");
792 compatible_close(accept_fd);
793 break;
794 }
795
796 new_wsi = libwebsocket_create_new_server_wsi(context);
797 if (new_wsi == NULL) {
798 compatible_close(accept_fd);
799 break;
800 }
801
802 new_wsi->sock = accept_fd;
803
Andy Green176de272014-02-15 14:36:02 +0800804 /* the transport is accepted... give him time to negotiate */
805 libwebsocket_set_timeout(new_wsi,
806 PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
807 AWAITING_TIMEOUT);
808
Alexandre Erwin Ittnerd578f572014-02-06 23:15:51 -0200809 /*
810 * A new connection was accepted. Give the user a chance to
811 * set properties of the newly created wsi. There's no protocol
812 * selected yet so we issue this to protocols[0]
813 */
814
815 (context->protocols[0].callback)(context, new_wsi,
816 LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, NULL, NULL, 0);
817
Andy Greena717df22014-04-11 13:14:37 +0800818 lws_libev_accept(context, new_wsi, accept_fd);
Alexandre Erwin Ittnerd578f572014-02-06 23:15:51 -0200819
Andy Greencdb9bf92014-04-12 10:07:02 +0800820 if (!LWS_SSL_ENABLED(context)) {
Andy Greena1ce6be2013-01-18 11:43:21 +0800821 lwsl_debug("accepted new conn port %u on fd=%d\n",
822 ntohs(cli_addr.sin_port), accept_fd);
823
Andy Greene2160712013-01-28 12:19:10 +0800824 insert_wsi_socket_into_fds(context, new_wsi);
Andy Greene2160712013-01-28 12:19:10 +0800825 }
Andy Greena1ce6be2013-01-18 11:43:21 +0800826 break;
Andy Greene2160712013-01-28 12:19:10 +0800827
Andy Greena1ce6be2013-01-18 11:43:21 +0800828 default:
829 break;
830 }
Andy Greencdb9bf92014-04-12 10:07:02 +0800831
Andy Green62824f92014-08-10 09:50:42 +0800832 if (lws_server_socket_service_ssl(context, &wsi, new_wsi,
833 accept_fd, pollfd))
834 goto fail;
Andy Greencdb9bf92014-04-12 10:07:02 +0800835
Andy Greena1ce6be2013-01-18 11:43:21 +0800836 return 0;
Andy Green158e8042014-04-02 14:25:10 +0800837
838fail:
839 libwebsocket_close_and_free_session(context, wsi,
840 LWS_CLOSE_STATUS_NOSTATUS);
841 return 1;
Andy Greena1ce6be2013-01-18 11:43:21 +0800842}
Joakim Soderberg63ff1202013-02-11 17:52:23 +0100843
Andy Green917f43a2014-10-12 14:31:47 +0800844#include "lextable-strings.h"
845
846const unsigned char *lws_token_to_string(enum lws_token_indexes token)
847{
848 if ((unsigned int)token >= ARRAY_SIZE(set))
849 return NULL;
850
851 return (unsigned char *)set[token];
852}
853
854int lws_add_http_header_by_name(struct libwebsocket_context *context,
855 struct libwebsocket *wsi,
856 const unsigned char *name,
857 const unsigned char *value,
858 int length,
859 unsigned char **p,
860 unsigned char *end)
861{
862#ifdef LWS_USE_HTTP2
863 if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING)
864 return lws_add_http2_header_by_name(context, wsi, name, value, length, p, end);
865#endif
866 if (name) {
867 while (*p < end && *name)
868 *((*p)++) = *name++;
869
870 if (*p == end)
871 return 1;
872
873 *((*p)++) = ' ';
874 }
875 if (*p + length + 3 >= end)
876 return 1;
877
878 memcpy(*p, value, length);
879 *p += length;
880
881 *((*p)++) = '\x0d';
882 *((*p)++) = '\x0a';
883
884 return 0;
885}
886
887int lws_finalize_http_header(struct libwebsocket_context *context,
888 struct libwebsocket *wsi,
889 unsigned char **p,
890 unsigned char *end)
891{
892#ifdef LWS_USE_HTTP2
893 if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING)
894 return 0;
895#endif
896
897 if ((long)(end - *p) < 3)
898 return 1;
899
900 *((*p)++) = '\x0d';
901 *((*p)++) = '\x0a';
902
903 return 0;
904}
905
906int lws_add_http_header_by_token(struct libwebsocket_context *context,
907 struct libwebsocket *wsi,
908 enum lws_token_indexes token,
909 const unsigned char *value,
910 int length,
911 unsigned char **p,
912 unsigned char *end)
913{
914 const unsigned char *name;
915#ifdef LWS_USE_HTTP2
916 if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING)
917 return lws_add_http2_header_by_token(context, wsi, token, value, length, p, end);
918#endif
919 name = lws_token_to_string(token);
920 if (!name)
921 return 1;
922
923 return lws_add_http_header_by_name(context, wsi, name, value, length, p, end);
924}
Andy Green4e7a1332013-11-11 07:30:33 +0800925
Andy Green200f3852014-10-18 12:23:05 +0800926int lws_add_http_header_content_length(struct libwebsocket_context *context,
927 struct libwebsocket *wsi,
928 unsigned long content_length,
929 unsigned char **p,
930 unsigned char *end)
931{
932 char b[24];
933 int n;
934
935 n = sprintf(b, "%lu", content_length);
936 if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH, (unsigned char *)b, n, p, end))
937 return 1;
938 wsi->u.http.content_length = content_length;
939 wsi->u.http.content_remain = content_length;
940
941 return 0;
942}
943
Andy Green4e7a1332013-11-11 07:30:33 +0800944static const char *err400[] = {
945 "Bad Request",
946 "Unauthorized",
947 "Payment Required",
948 "Forbidden",
949 "Not Found",
950 "Method Not Allowed",
951 "Not Acceptable",
952 "Proxy Auth Required",
953 "Request Timeout",
954 "Conflict",
955 "Gone",
956 "Length Required",
957 "Precondition Failed",
958 "Request Entity Too Large",
959 "Request URI too Long",
960 "Unsupported Media Type",
961 "Requested Range Not Satisfiable",
962 "Expectation Failed"
963};
964
965static const char *err500[] = {
966 "Internal Server Error",
967 "Not Implemented",
968 "Bad Gateway",
969 "Service Unavailable",
970 "Gateway Timeout",
971 "HTTP Version Not Supported"
972};
973
Andy Green917f43a2014-10-12 14:31:47 +0800974int lws_add_http_header_status(struct libwebsocket_context *context,
975 struct libwebsocket *wsi,
976 unsigned int code,
977 unsigned char **p,
978 unsigned char *end)
979{
980 unsigned char code_and_desc[60];
981 const char *description = "";
982 int n;
983
984#ifdef LWS_USE_HTTP2
985 if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING)
986 return lws_add_http2_header_status(context, wsi, code, p, end);
987#endif
988 if (code >= 400 && code < (400 + ARRAY_SIZE(err400)))
989 description = err400[code - 400];
990 if (code >= 500 && code < (500 + ARRAY_SIZE(err500)))
991 description = err500[code - 500];
992
993 n = sprintf((char *)code_and_desc, "HTTP/1.0 %u %s", code, description);
994
995 return lws_add_http_header_by_name(context, wsi, NULL, code_and_desc, n, p, end);
996}
997
Andy Green4e7a1332013-11-11 07:30:33 +0800998/**
999 * libwebsockets_return_http_status() - Return simple http status
1000 * @context: libwebsockets context
1001 * @wsi: Websocket instance (available from user callback)
1002 * @code: Status index, eg, 404
Andy Green917f43a2014-10-12 14:31:47 +08001003 * @html_body: User-readable HTML description < 1KB, or NULL
Andy Green4e7a1332013-11-11 07:30:33 +08001004 *
1005 * Helper to report HTTP errors back to the client cleanly and
1006 * consistently
1007 */
Andy Green83725d82014-02-27 07:19:21 +08001008LWS_VISIBLE int libwebsockets_return_http_status(
Andy Green4e7a1332013-11-11 07:30:33 +08001009 struct libwebsocket_context *context, struct libwebsocket *wsi,
1010 unsigned int code, const char *html_body)
1011{
1012 int n, m;
Andy Green917f43a2014-10-12 14:31:47 +08001013
1014 unsigned char *p = context->service_buffer + LWS_SEND_BUFFER_PRE_PADDING;
1015 unsigned char *start = p;
1016 unsigned char *end = p + sizeof(context->service_buffer) -
1017 LWS_SEND_BUFFER_PRE_PADDING;
Andy Green4e7a1332013-11-11 07:30:33 +08001018
1019 if (!html_body)
1020 html_body = "";
1021
Andy Green917f43a2014-10-12 14:31:47 +08001022 if (lws_add_http_header_status(context, wsi, code, &p, end))
1023 return 1;
1024 if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_SERVER, (unsigned char *)"libwebsockets", 13, &p, end))
1025 return 1;
1026 if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)"text/html", 9, &p, end))
1027 return 1;
1028 if (lws_finalize_http_header(context, wsi, &p, end))
1029 return 1;
Andy Green4e7a1332013-11-11 07:30:33 +08001030
Andy Green917f43a2014-10-12 14:31:47 +08001031 m = libwebsocket_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
Andy Green3adeca82014-11-14 07:21:02 +08001032 if (m != (int)(p - start))
1033 return 1;
Andy Green4e7a1332013-11-11 07:30:33 +08001034
Andy Green917f43a2014-10-12 14:31:47 +08001035 n = sprintf((char *)start, "<html><body><h1>%u</h1>%s</body></html>", code, html_body);
1036 m = libwebsocket_write(wsi, start, n, LWS_WRITE_HTTP);
Andy Green4e7a1332013-11-11 07:30:33 +08001037
Andy Green3adeca82014-11-14 07:21:02 +08001038 return m != n;
Andy Green4e7a1332013-11-11 07:30:33 +08001039}
1040
1041/**
1042 * libwebsockets_serve_http_file() - Send a file back to the client using http
1043 * @context: libwebsockets context
1044 * @wsi: Websocket instance (available from user callback)
1045 * @file: The file to issue over http
1046 * @content_type: The http content type, eg, text/html
1047 * @other_headers: NULL or pointer to \0-terminated other header string
1048 *
1049 * This function is intended to be called from the callback in response
1050 * to http requests from the client. It allows the callback to issue
1051 * local files down the http link in a single step.
1052 *
1053 * Returning <0 indicates error and the wsi should be closed. Returning
Andy Green91b05892014-10-17 08:38:44 +08001054 * >0 indicates the file was completely sent and
1055 * lws_http_transaction_completed() called on the wsi (and close if != 0)
Andy Green4e7a1332013-11-11 07:30:33 +08001056 * ==0 indicates the file transfer is started and needs more service later,
1057 * the wsi should be left alone.
1058 */
1059
1060LWS_VISIBLE int libwebsockets_serve_http_file(
1061 struct libwebsocket_context *context,
1062 struct libwebsocket *wsi, const char *file,
Andy Green917f43a2014-10-12 14:31:47 +08001063 const char *content_type, const char *other_headers,
1064 int other_headers_len)
Andy Green4e7a1332013-11-11 07:30:33 +08001065{
Andy Green024eb6c2014-10-08 12:00:53 +08001066 unsigned char *response = context->service_buffer + LWS_SEND_BUFFER_PRE_PADDING;
1067 unsigned char *p = response;
Andy Green917f43a2014-10-12 14:31:47 +08001068 unsigned char *end = p + sizeof(context->service_buffer) -
1069 LWS_SEND_BUFFER_PRE_PADDING;
Andy Green4e7a1332013-11-11 07:30:33 +08001070 int ret = 0;
Andy Green4e7a1332013-11-11 07:30:33 +08001071
Andy Green158e8042014-04-02 14:25:10 +08001072 wsi->u.http.fd = lws_plat_open_file(file, &wsi->u.http.filelen);
Andy Green4e7a1332013-11-11 07:30:33 +08001073
Patrick Gansterer81338aa2014-02-27 03:21:50 +01001074 if (wsi->u.http.fd == LWS_INVALID_FILE) {
Andy Green4e7a1332013-11-11 07:30:33 +08001075 lwsl_err("Unable to open '%s'\n", file);
1076 libwebsockets_return_http_status(context, wsi,
1077 HTTP_STATUS_NOT_FOUND, NULL);
Andy Green4e7a1332013-11-11 07:30:33 +08001078 return -1;
1079 }
1080
Andy Green917f43a2014-10-12 14:31:47 +08001081 if (lws_add_http_header_status(context, wsi, 200, &p, end))
Andy Green91b05892014-10-17 08:38:44 +08001082 return -1;
Andy Green917f43a2014-10-12 14:31:47 +08001083 if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_SERVER, (unsigned char *)"libwebsockets", 13, &p, end))
Andy Green91b05892014-10-17 08:38:44 +08001084 return -1;
Andy Green917f43a2014-10-12 14:31:47 +08001085 if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)content_type, strlen(content_type), &p, end))
Andy Green91b05892014-10-17 08:38:44 +08001086 return -1;
Andy Green200f3852014-10-18 12:23:05 +08001087 if (lws_add_http_header_content_length(context, wsi, wsi->u.http.filelen, &p, end))
Andy Green91b05892014-10-17 08:38:44 +08001088 return -1;
Andy Green4e7a1332013-11-11 07:30:33 +08001089
Andy Green917f43a2014-10-12 14:31:47 +08001090 if (other_headers) {
1091 if ((end - p) < other_headers_len)
1092 return -1;
1093 memcpy(p, other_headers, other_headers_len);
1094 p += other_headers_len;
1095 }
1096
1097 if (lws_finalize_http_header(context, wsi, &p, end))
Andy Green91b05892014-10-17 08:38:44 +08001098 return -1;
Andy Green917f43a2014-10-12 14:31:47 +08001099
Andy Green024eb6c2014-10-08 12:00:53 +08001100 ret = libwebsocket_write(wsi, response,
1101 p - response, LWS_WRITE_HTTP_HEADERS);
1102 if (ret != (p - response)) {
1103 lwsl_err("_write returned %d from %d\n", ret, (p - response));
Andy Green4e7a1332013-11-11 07:30:33 +08001104 return -1;
1105 }
1106
1107 wsi->u.http.filepos = 0;
1108 wsi->state = WSI_STATE_HTTP_ISSUING_FILE;
1109
1110 return libwebsockets_serve_http_file_fragment(context, wsi);
1111}
1112
Andy Greend7340c12014-04-10 14:08:10 +08001113
1114int libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi,
1115 unsigned char *buf, size_t len)
1116{
1117 size_t n = 0;
1118 int m;
1119
1120#if 0
1121 lwsl_parser("received %d byte packet\n", (int)len);
1122 lwsl_hexdump(buf, len);
1123#endif
1124
1125 /* let the rx protocol state machine have as much as it needs */
1126
1127 while (n < len) {
1128 /*
1129 * we were accepting input but now we stopped doing so
1130 */
Andy Green024eb6c2014-10-08 12:00:53 +08001131 if (!(wsi->rxflow_change_to & LWS_RXFLOW_ALLOW)) {
1132 lws_rxflow_cache(wsi, buf, n, len);
Andy Greend7340c12014-04-10 14:08:10 +08001133
1134 return 1;
1135 }
1136
1137 /* account for what we're using in rxflow buffer */
Andy Green024eb6c2014-10-08 12:00:53 +08001138 if (wsi->rxflow_buffer)
1139 wsi->rxflow_pos++;
Andy Greend7340c12014-04-10 14:08:10 +08001140
1141 /* process the byte */
1142 m = libwebsocket_rx_sm(wsi, buf[n++]);
1143 if (m < 0)
1144 return -1;
1145 }
1146
1147 return 0;
Andy Greencdb9bf92014-04-12 10:07:02 +08001148}
1149
1150LWS_VISIBLE void
1151lws_server_get_canonical_hostname(struct libwebsocket_context *context,
1152 struct lws_context_creation_info *info)
1153{
1154 if (info->options & LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME)
1155 return;
1156
1157 /* find canonical hostname */
1158 gethostname((char *)context->canonical_hostname,
1159 sizeof(context->canonical_hostname) - 1);
1160
1161 lwsl_notice(" canonical_hostname = %s\n", context->canonical_hostname);
vpeter44dd8ada2014-04-27 13:28:22 +02001162}