2 * libwebsockets - small server side websockets and web server implementation
4 * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
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.
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.
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,
23 #include "private-libwebsockets.h"
26 lws_context_init_server(struct lws_context_creation_info *info,
27 struct lws_vhost *vhost)
30 int n, opt = 1, limit = 1;
32 lws_sockfd_type sockfd;
37 /* set up our external listening socket we serve on */
39 if (info->port == CONTEXT_PORT_NO_LISTEN)
42 vh = vhost->context->vhost_list;
44 if (vh->listen_port == info->port) {
45 if ((!info->iface && !vh->iface) ||
46 (info->iface && vh->iface &&
47 !strcmp(info->iface, vh->iface))) {
48 vhost->listen_port = info->port;
49 vhost->iface = info->iface;
50 lwsl_notice(" using listen skt from vhost %s\n",
59 #if defined(__linux__)
60 limit = vhost->context->count_threads;
63 for (m = 0; m < limit; m++) {
64 #ifdef LWS_USE_UNIX_SOCK
65 if (LWS_UNIX_SOCK_ENABLED(vhost))
66 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
70 if (LWS_IPV6_ENABLED(context))
71 sockfd = socket(AF_INET6, SOCK_STREAM, 0);
74 sockfd = socket(AF_INET, SOCK_STREAM, 0);
78 sockfd = mbed3_create_tcp_stream_socket();
79 if (!lws_sockfd_valid(sockfd)) {
81 lwsl_err("ERROR opening socket\n");
87 * allow us to restart even if old sockets in TIME_WAIT
89 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
90 (const void *)&opt, sizeof(opt)) < 0) {
91 compatible_close(sockfd);
94 #if defined(__linux__) && defined(SO_REUSEPORT) && LWS_MAX_SMP > 1
95 if (vhost->context->count_threads > 1)
96 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT,
97 (const void *)&opt, sizeof(opt)) < 0) {
98 compatible_close(sockfd);
103 lws_plat_set_socket_options(vhost, sockfd);
106 n = lws_socket_bind(vhost, sockfd, info->port, info->iface);
111 vhost->listen_port = info->port;
112 vhost->iface = info->iface;
114 wsi = lws_zalloc(sizeof(struct lws));
116 lwsl_err("Out of mem\n");
119 wsi->context = vhost->context;
121 wsi->mode = LWSCM_SERVER_LISTENER;
122 wsi->protocol = vhost->protocols;
127 vhost->context->pt[m].wsi_listening = wsi;
128 if (insert_wsi_socket_into_fds(vhost->context, wsi))
131 vhost->context->count_wsi_allocated++;
132 vhost->lserv_wsi = wsi;
135 listen(wsi->sock, LWS_SOMAXCONN);
136 } /* for each thread able to independently listen */
138 mbed3_tcp_stream_bind(wsi->sock, info->port, wsi);
140 if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) {
141 #ifdef LWS_USE_UNIX_SOCK
142 if (LWS_UNIX_SOCK_ENABLED(vhost))
143 lwsl_notice(" Listening on \"%s\"\n", info->iface);
146 lwsl_notice(" Listening on port %d\n", info->port);
152 compatible_close(sockfd);
158 _lws_server_listen_accept_flow_control(struct lws *twsi, int on)
160 struct lws_context_per_thread *pt = &twsi->context->pt[(int)twsi->tsi];
161 struct lws *wsi = pt->wsi_listening;
164 if (!wsi || twsi->context->being_destroyed)
167 lwsl_debug("%s: Thr %d: LISTEN wsi %p: state %d\n",
168 __func__, twsi->tsi, (void *)wsi, on);
171 n = lws_change_pollfd(wsi, 0, LWS_POLLIN);
173 n = lws_change_pollfd(wsi, LWS_POLLIN, 0);
179 lws_select_vhost(struct lws_context *context, int port, const char *servername)
181 struct lws_vhost *vhost = context->vhost_list;
184 if (port == vhost->listen_port &&
185 !strcmp(vhost->name, servername)) {
186 lwsl_info("SNI: Found: %s\n", servername);
189 vhost = vhost->vhost_next;
195 static const char * get_mimetype(const char *file)
197 int n = strlen(file);
202 if (!strcmp(&file[n - 4], ".ico"))
203 return "image/x-icon";
205 if (!strcmp(&file[n - 4], ".gif"))
208 if (!strcmp(&file[n - 3], ".js"))
209 return "text/javascript";
211 if (!strcmp(&file[n - 4], ".png"))
214 if (!strcmp(&file[n - 4], ".jpg"))
217 if (!strcmp(&file[n - 5], ".html"))
220 if (!strcmp(&file[n - 4], ".css"))
223 if (!strcmp(&file[n - 4], ".ttf"))
224 return "application/x-font-ttf";
229 int lws_http_serve(struct lws *wsi, char *uri, const char *origin)
231 const char *mimetype;
233 char path[256], sym[256];
234 unsigned char *p = (unsigned char *)sym + 32 + LWS_PRE, *start = p;
235 unsigned char *end = p + sizeof(sym) - 32 - LWS_PRE;
238 snprintf(path, sizeof(path) - 1, "%s/%s", origin, uri);
243 if (stat(path, &st)) {
244 lwsl_err("unable to stat %s\n", path);
248 lwsl_debug(" %s mode %d\n", path, S_IFMT & st.st_mode);
250 if ((S_IFMT & st.st_mode) == S_IFLNK) {
251 if (readlink(path, sym, sizeof(sym))) {
252 lwsl_err("Failed to read link %s\n", path);
255 lwsl_debug("symlink %s -> %s\n", path, sym);
256 snprintf(path, sizeof(path) - 1, "%s", sym);
259 if ((S_IFMT & st.st_mode) == S_IFDIR) {
260 lwsl_debug("default filename append to dir\n");
261 snprintf(path, sizeof(path) - 1, "%s/%s/index.html",
265 } while ((S_IFMT & st.st_mode) != S_IFREG && spin < 5);
268 lwsl_err("symlink loop %s \n", path);
270 n = sprintf(sym, "%08lX%08lX", (unsigned long)st.st_size,
271 (unsigned long)st.st_mtime);
273 if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_IF_NONE_MATCH)) {
275 * he thinks he has some version of it already,
276 * check if the tag matches
278 if (!strcmp(sym, lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_IF_NONE_MATCH))) {
280 lwsl_debug("%s: ETAG match %s %s\n", __func__,
283 /* we don't need to send the payload */
284 if (lws_add_http_header_status(wsi, 304, &p, end))
286 if (lws_add_http_header_by_token(wsi,
288 (unsigned char *)sym, n, &p, end))
290 if (lws_finalize_http_header(wsi, &p, end))
293 n = lws_write(wsi, start, p - start,
294 LWS_WRITE_HTTP_HEADERS);
295 if (n != (p - start)) {
296 lwsl_err("_write returned %d from %d\n", n, p - start);
300 return lws_http_transaction_completed(wsi);
304 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ETAG,
305 (unsigned char *)sym, n, &p, end))
308 mimetype = get_mimetype(path);
310 lwsl_err("unknown mimetype for %s", path);
314 n = lws_serve_http_file(wsi, path, mimetype, (char *)start, p - start);
316 if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi)))
317 return -1; /* error or can't reuse connection: close the socket */
321 lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
327 lws_http_action(struct lws *wsi)
329 struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
330 enum http_connection_type connection_type;
331 enum http_version request_version;
332 char content_length_str[32];
333 struct lws_http_mount *hm, *hit = NULL;
334 unsigned int n, count = 0;
335 char http_version_str[10];
336 char http_conn_str[20];
337 int http_version_len;
338 char *uri_ptr = NULL;
339 int uri_len = 0, best = 0;
342 static const unsigned char methods[] = {
345 WSI_TOKEN_OPTIONS_URI,
348 WSI_TOKEN_DELETE_URI,
350 WSI_TOKEN_HTTP_COLON_PATH,
353 #if defined(_DEBUG) || defined(LWS_WITH_ACCESS_LOG)
354 static const char * const method_names[] = {
355 "GET", "POST", "OPTIONS", "PUT", "PATCH", "DELETE",
362 /* it's not websocket.... shall we accept it as http? */
364 for (n = 0; n < ARRAY_SIZE(methods); n++)
365 if (lws_hdr_total_length(wsi, methods[n]))
368 lwsl_warn("Missing URI in HTTP request\n");
373 lwsl_warn("multiple methods?\n");
377 if (lws_ensure_user_space(wsi))
380 for (n = 0; n < ARRAY_SIZE(methods); n++)
381 if (lws_hdr_total_length(wsi, methods[n])) {
382 uri_ptr = lws_hdr_simple_ptr(wsi, methods[n]);
383 uri_len = lws_hdr_total_length(wsi, methods[n]);
384 lwsl_info("Method: %s request for '%s'\n",
385 method_names[n], uri_ptr);
392 /* we insist on absolute paths */
394 if (uri_ptr[0] != '/') {
395 lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
400 /* HTTP header had a content length? */
402 wsi->u.http.content_length = 0;
403 if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) ||
404 lws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI) ||
405 lws_hdr_total_length(wsi, WSI_TOKEN_PUT_URI))
406 wsi->u.http.content_length = 100 * 1024 * 1024;
408 if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
409 lws_hdr_copy(wsi, content_length_str,
410 sizeof(content_length_str) - 1,
411 WSI_TOKEN_HTTP_CONTENT_LENGTH);
412 wsi->u.http.content_length = atoi(content_length_str);
415 if (wsi->http2_substream) {
416 wsi->u.http.request_version = HTTP_VERSION_2;
418 /* http_version? Default to 1.0, override with token: */
419 request_version = HTTP_VERSION_1_0;
421 /* Works for single digit HTTP versions. : */
422 http_version_len = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP);
423 if (http_version_len > 7) {
424 lws_hdr_copy(wsi, http_version_str,
425 sizeof(http_version_str) - 1, WSI_TOKEN_HTTP);
426 if (http_version_str[5] == '1' && http_version_str[7] == '1')
427 request_version = HTTP_VERSION_1_1;
429 wsi->u.http.request_version = request_version;
431 /* HTTP/1.1 defaults to "keep-alive", 1.0 to "close" */
432 if (request_version == HTTP_VERSION_1_1)
433 connection_type = HTTP_CONNECTION_KEEP_ALIVE;
435 connection_type = HTTP_CONNECTION_CLOSE;
437 /* Override default if http "Connection:" header: */
438 if (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION)) {
439 lws_hdr_copy(wsi, http_conn_str, sizeof(http_conn_str) - 1,
440 WSI_TOKEN_CONNECTION);
441 http_conn_str[sizeof(http_conn_str) - 1] = '\0';
442 if (!strcasecmp(http_conn_str, "keep-alive"))
443 connection_type = HTTP_CONNECTION_KEEP_ALIVE;
445 if (!strcasecmp(http_conn_str, "close"))
446 connection_type = HTTP_CONNECTION_CLOSE;
448 wsi->u.http.connection_type = connection_type;
451 n = wsi->protocol->callback(wsi, LWS_CALLBACK_FILTER_HTTP_CONNECTION,
452 wsi->user_space, uri_ptr, uri_len);
454 lwsl_info("LWS_CALLBACK_HTTP closing\n");
459 * if there is content supposed to be coming,
460 * put a timeout on it having arrived
462 lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,
463 wsi->context->timeout_secs);
464 #ifdef LWS_OPENSSL_SUPPORT
465 if (wsi->redirect_to_https) {
467 * we accepted http:// only so we could redirect to
468 * https://, so issue the redirect. Create the redirection
469 * URI from the host: header and ignore the path part
471 unsigned char *start = pt->serv_buf + LWS_PRE, *p = start,
474 if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST))
477 n = sprintf((char *)end, "https://%s/",
478 lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));
480 n = lws_http_redirect(wsi, end, n, &p, end);
484 return lws_http_transaction_completed(wsi);
488 #ifdef LWS_WITH_ACCESS_LOG
490 * Produce Apache-compatible log string for wsi, like this:
492 * 2.31.234.19 - - [27/Mar/2016:03:22:44 +0800]
493 * "GET /aep-screen.png HTTP/1.1"
494 * 200 152987 "https://libwebsockets.org/index.html"
495 * "Mozilla/5.0 (Macint... Chrome/49.0.2623.87 Safari/537.36"
499 static const char * const hver[] = {
500 "http/1.0", "http/1.1", "http/2"
503 char ads[INET6_ADDRSTRLEN];
505 char ads[INET_ADDRSTRLEN];
510 time_t t = time(NULL);
513 if (wsi->access_log_pending)
516 wsi->access_log.header_log = lws_malloc(l);
520 strftime(da, sizeof(da), "%d/%b/%Y:%H:%M:%S %z", tmp);
522 strcpy(da, "01/Jan/1970:00:00:00 +0000");
524 pa = lws_get_peer_simple(wsi, ads, sizeof(ads));
529 me = method_names[meth];
533 snprintf(wsi->access_log.header_log, l,
534 "%s - - [%s] \"%s %s %s\"",
536 hver[wsi->u.http.request_version]);
538 l = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT);
540 wsi->access_log.user_agent = lws_malloc(l + 2);
541 lws_hdr_copy(wsi, wsi->access_log.user_agent,
542 l + 1, WSI_TOKEN_HTTP_USER_AGENT);
544 wsi->access_log_pending = 1;
548 /* can we serve it from the mount list? */
550 hm = wsi->vhost->mount_list;
552 if (uri_len >= hm->mountpoint_len &&
553 !strncmp(uri_ptr, hm->mountpoint, hm->mountpoint_len) &&
554 (uri_ptr[hm->mountpoint_len] == '\0' ||
555 uri_ptr[hm->mountpoint_len] == '/' ||
556 hm->mountpoint_len == 1)
558 if ((hm->origin_protocol == LWSMPRO_CGI ||
559 lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI)) &&
560 hm->mountpoint_len > best) {
561 best = hm->mountpoint_len;
568 char *s = uri_ptr + hit->mountpoint_len;
570 lwsl_debug("*** hit %d %d %s\n", hit->mountpoint_len,
571 hit->origin_protocol , hit->origin);
574 * if we have a mountpoint like https://xxx.com/yyy
575 * there is an implied / at the end for our purposes since
576 * we can only mount on a "directory".
578 * But if we just go with that, the browser cannot understand
579 * that he is actually looking down one "directory level", so
580 * even though we give him /yyy/abc.html he acts like the
581 * current directory level is /. So relative urls like "x.png"
582 * wrongly look outside the mountpoint.
584 * Therefore if we didn't come in on a url with an explicit
585 * / at the end, we must redirect to add it so the browser
586 * understands he is one "directory level" down.
588 if ((hit->mountpoint_len > 1 || (hit->origin_protocol & 4)) &&
589 (*s != '/' || (hit->origin_protocol & 4)) &&
590 (hit->origin_protocol != LWSMPRO_CGI)) {
591 unsigned char *start = pt->serv_buf + LWS_PRE,
592 *p = start, *end = p + 512;
593 static const char *oprot[] = {
594 "http://", "https://"
597 lwsl_debug("Doing 301 '%s' org %s\n", s, hit->origin);
599 if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST))
602 /* > at start indicates deal with by redirect */
603 if (hit->origin_protocol & 4)
604 n = snprintf((char *)end, 256, "%s%s",
605 oprot[hit->origin_protocol & 1],
608 n = snprintf((char *)end, 256,
610 lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST),
613 n = lws_http_redirect(wsi, end, n, &p, end);
617 return lws_http_transaction_completed(wsi);
621 /* did we hit something with a cgi:// origin? */
622 if (hit->origin_protocol == LWSMPRO_CGI) {
623 const char *cmd[] = {
624 NULL, /* replace with cgi path */
627 unsigned char *p, *end, buffer[256];
629 lwsl_debug("%s: cgi\n", __func__);
630 cmd[0] = hit->origin;
633 if (hit->cgi_timeout)
634 n = hit->cgi_timeout;
636 n = lws_cgi(wsi, cmd, hit->mountpoint_len, n,
639 lwsl_err("%s: cgi failed\n");
642 p = buffer + LWS_PRE;
643 end = p + sizeof(buffer) - LWS_PRE;
645 if (lws_add_http_header_status(wsi, 200, &p, end))
647 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_CONNECTION,
648 (unsigned char *)"close", 5, &p, end))
650 n = lws_write(wsi, buffer + LWS_PRE,
651 p - (buffer + LWS_PRE),
652 LWS_WRITE_HTTP_HEADERS);
659 if (s[0] == '\0' || (n == 1 && s[n - 1] == '/'))
660 s = (char *)hit->def;
664 wsi->cache_secs = hit->cache_max_age;
665 wsi->cache_reuse = hit->cache_reusable;
666 wsi->cache_revalidate = hit->cache_revalidate;
667 wsi->cache_intermediaries = hit->cache_intermediaries;
669 n = lws_http_serve(wsi, s, hit->origin);
671 n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP,
672 wsi->user_space, uri_ptr, uri_len);
675 lwsl_info("LWS_CALLBACK_HTTP closing\n");
684 * If we're not issuing a file, check for content_length or
685 * HTTP keep-alive. No keep-alive header allocation for
686 * ISSUING_FILE, as this uses HTTP/1.0.
688 * In any case, return 0 and let lws_read decide how to
689 * proceed based on state
691 if (wsi->state != LWSS_HTTP_ISSUING_FILE)
692 /* Prepare to read body if we have a content length: */
693 if (wsi->u.http.content_length > 0)
694 wsi->state = LWSS_HTTP_BODY;
699 /* we're closing, losing some rx is OK */
700 wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
701 lws_header_table_detach(wsi, 1);
708 lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
710 struct lws_context *context = lws_get_context(wsi);
711 struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
712 struct _lws_header_related hdr;
713 struct allocated_headers *ah;
714 int protocol_len, n, hit;
715 char protocol_list[128];
716 char protocol_name[32];
719 assert(len < 10000000);
720 assert(wsi->u.hdr.ah);
723 wsi->more_rx_waiting = !!len;
725 if (wsi->mode != LWSCM_HTTP_SERVING &&
726 wsi->mode != LWSCM_HTTP_SERVING_ACCEPTED) {
727 lwsl_err("%s: bad wsi mode %d\n", __func__, wsi->mode);
731 if (lws_parse(wsi, *(*buf)++)) {
732 lwsl_info("lws_parse failed\n");
736 if (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE)
739 lwsl_parser("%s: lws_parse sees parsing complete\n", __func__);
740 lwsl_debug("%s: wsi->more_rx_waiting=%d\n", __func__,
741 wsi->more_rx_waiting);
745 if (lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {
746 struct lws_vhost *vhost = lws_select_vhost(
747 context, wsi->vhost->listen_port,
748 lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));
755 if (!wsi->conn_stat_done) {
757 wsi->conn_stat_done = 1;
760 wsi->mode = LWSCM_PRE_WS_SERVING_ACCEPT;
761 lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
763 /* is this websocket protocol or normal http 1.0? */
765 if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {
766 if (!strcasecmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE),
768 wsi->vhost->ws_upgrades++;
769 lwsl_info("Upgrade to ws\n");
773 if (!strcasecmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE),
775 wsi->vhost->http2_upgrades++;
776 lwsl_info("Upgrade to h2c\n");
780 lwsl_err("Unknown upgrade\n");
781 /* dunno what he wanted to upgrade to */
785 /* no upgrade ack... he remained as HTTP */
787 lwsl_info("No upgrade\n");
790 lws_union_transition(wsi, LWSCM_HTTP_SERVING_ACCEPTED);
791 wsi->state = LWSS_HTTP;
792 wsi->u.http.fd = LWS_INVALID_FILE;
794 /* expose it at the same offset as u.hdr */
796 lwsl_debug("%s: wsi %p: ah %p\n", __func__, (void *)wsi,
797 (void *)wsi->u.hdr.ah);
799 n = lws_http_action(wsi);
805 if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP2_SETTINGS)) {
806 lwsl_err("missing http2_settings\n");
810 lwsl_err("h2c upgrade...\n");
812 p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP2_SETTINGS);
813 /* convert the peer's HTTP-Settings */
814 n = lws_b64_decode_string(p, protocol_list,
815 sizeof(protocol_list));
817 lwsl_parser("HTTP2_SETTINGS too long\n");
821 /* adopt the header info */
825 lws_union_transition(wsi, LWSCM_HTTP2_SERVING);
827 /* http2 union member has http union struct at start */
830 lws_http2_init(&wsi->u.http2.peer_settings);
831 lws_http2_init(&wsi->u.http2.my_settings);
835 lws_http2_interpret_settings_payload(&wsi->u.http2.peer_settings,
836 (unsigned char *)protocol_list, n);
838 strcpy(protocol_list,
839 "HTTP/1.1 101 Switching Protocols\x0d\x0a"
840 "Connection: Upgrade\x0d\x0a"
841 "Upgrade: h2c\x0d\x0a\x0d\x0a");
842 n = lws_issue_raw(wsi, (unsigned char *)protocol_list,
843 strlen(protocol_list));
844 if (n != strlen(protocol_list)) {
845 lwsl_debug("http2 switch: ERROR writing to socket\n");
849 wsi->state = LWSS_HTTP2_AWAIT_CLIENT_PREFACE;
856 lwsl_err("NULL protocol at lws_read\n");
861 * Select the first protocol we support from the list
862 * the client sent us.
864 * Copy it to remove header fragmentation
867 if (lws_hdr_copy(wsi, protocol_list, sizeof(protocol_list) - 1,
868 WSI_TOKEN_PROTOCOL) < 0) {
869 lwsl_err("protocol list too long");
873 protocol_len = lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL);
874 protocol_list[protocol_len] = '\0';
880 while (n < sizeof(protocol_name) - 1 && *p && *p !=',')
881 protocol_name[n++] = *p++;
882 protocol_name[n] = '\0';
886 lwsl_info("checking %s\n", protocol_name);
889 while (wsi->vhost->protocols[n].callback) {
890 if (wsi->vhost->protocols[n].name &&
891 !strcmp(wsi->vhost->protocols[n].name,
893 wsi->protocol = &wsi->vhost->protocols[n];
902 /* we didn't find a protocol he wanted? */
905 if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL)) {
906 lwsl_err("No protocol from \"%s\" supported\n",
911 * some clients only have one protocol and
912 * do not send the protocol list header...
913 * allow it and match to protocol 0
915 lwsl_info("defaulting to prot 0 handler\n");
917 wsi->protocol = &wsi->vhost->protocols[0];
920 /* allocate wsi->user storage */
921 if (lws_ensure_user_space(wsi))
925 * Give the user code a chance to study the request and
926 * have the opportunity to deny it
928 if ((wsi->protocol->callback)(wsi,
929 LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,
931 lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL), 0)) {
932 lwsl_warn("User code denied connection\n");
937 * Perform the handshake according to the protocol version the
941 switch (wsi->ietf_spec_revision) {
943 lwsl_parser("lws_parse calling handshake_04\n");
944 if (handshake_0405(context, wsi)) {
945 lwsl_info("hs0405 has failed the connection\n");
951 lwsl_warn("Unknown client spec version %d\n",
952 wsi->ietf_spec_revision);
957 * stitch protocol choice into the vh protocol linked list
958 * We always insert ourselves at the start of the list
963 //lwsl_err("%s: pre insert vhost start wsi %p, that wsi prev == %p\n",
965 // wsi->vhost->same_vh_protocol_list[n],
966 // wsi->same_vh_protocol_prev);
967 wsi->same_vh_protocol_prev = /* guy who points to us */
968 &wsi->vhost->same_vh_protocol_list[n];
969 wsi->same_vh_protocol_next = /* old first guy is our next */
970 wsi->vhost->same_vh_protocol_list[n];
971 /* we become the new first guy */
972 wsi->vhost->same_vh_protocol_list[n] = wsi;
974 if (wsi->same_vh_protocol_next)
975 /* old first guy points back to us now */
976 wsi->same_vh_protocol_next->same_vh_protocol_prev =
977 &wsi->same_vh_protocol_next;
981 /* we are upgrading to ws, so http/1.1 and keepalive +
982 * pipelined header considerations about keeping the ah around
983 * no longer apply. However it's common for the first ws
984 * protocol data to have been coalesced with the browser
985 * upgrade request and to already be in the ah rx buffer.
988 lwsl_info("%s: %p: inheriting ah in ws mode (rxpos:%d, rxlen:%d)\n",
989 __func__, wsi, wsi->u.hdr.ah->rxpos,
990 wsi->u.hdr.ah->rxlen);
994 lws_union_transition(wsi, LWSCM_WS_SERVING);
996 * first service is WS mode will notice this, use the RX and
997 * then detach the ah (caution: we are not in u.hdr union
998 * mode any more then... ah_temp member is at start the same
1001 * Because rxpos/rxlen shows something in the ah, we will get
1002 * service guaranteed next time around the event loop
1004 * All union members begin with hdr, so we can use it even
1005 * though we transitioned to ws union mode (the ah detach
1006 * code uses it anyway).
1012 * create the frame buffer for this connection according to the
1013 * size mentioned in the protocol definition. If 0 there, use
1014 * a big default for compatibility
1017 n = wsi->protocol->rx_buffer_size;
1019 n = LWS_MAX_SOCKET_IO_BUF;
1021 wsi->u.ws.rx_ubuf = lws_malloc(n + 4 /* 0x0000ffff zlib */);
1022 if (!wsi->u.ws.rx_ubuf) {
1023 lwsl_err("Out of Mem allocating rx buffer %d\n", n);
1026 wsi->u.ws.rx_ubuf_alloc = n;
1027 lwsl_info("Allocating RX buffer %d\n", n);
1029 if (setsockopt(wsi->sock, SOL_SOCKET, SO_SNDBUF,
1030 (const char *)&n, sizeof n)) {
1031 lwsl_warn("Failed to set SNDBUF to %d", n);
1035 lwsl_parser("accepted v%02d connection\n",
1036 wsi->ietf_spec_revision);
1039 } /* while all chars are handled */
1044 /* drop the header info */
1045 /* we're closing, losing some rx is OK */
1046 wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
1047 lws_header_table_detach(wsi, 1);
1053 lws_get_idlest_tsi(struct lws_context *context)
1055 unsigned int lowest = ~0;
1056 int n = 0, hit = -1;
1058 for (; n < context->count_threads; n++) {
1059 if ((unsigned int)context->pt[n].fds_count !=
1060 context->fd_limit_per_thread - 1 &&
1061 (unsigned int)context->pt[n].fds_count < lowest) {
1062 lowest = context->pt[n].fds_count;
1071 lws_create_new_server_wsi(struct lws_vhost *vhost)
1073 struct lws *new_wsi;
1074 int n = lws_get_idlest_tsi(vhost->context);
1077 lwsl_err("no space for new conn\n");
1081 new_wsi = lws_zalloc(sizeof(struct lws));
1082 if (new_wsi == NULL) {
1083 lwsl_err("Out of memory for new connection\n");
1088 lwsl_info("Accepted %p to tsi %d\n", new_wsi, new_wsi->tsi);
1090 new_wsi->vhost = vhost;
1091 new_wsi->context = vhost->context;
1092 new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
1093 new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
1095 /* intialize the instance struct */
1097 new_wsi->state = LWSS_HTTP;
1098 new_wsi->mode = LWSCM_HTTP_SERVING;
1099 new_wsi->hdr_parsing_completed = 0;
1101 #ifdef LWS_OPENSSL_SUPPORT
1102 new_wsi->use_ssl = LWS_SSL_ENABLED(vhost);
1106 * these can only be set once the protocol is known
1107 * we set an unestablished connection's protocol pointer
1108 * to the start of the supported list, so it can look
1109 * for matching ones during the handshake
1111 new_wsi->protocol = vhost->protocols;
1112 new_wsi->user_space = NULL;
1113 new_wsi->ietf_spec_revision = 0;
1114 new_wsi->sock = LWS_SOCK_INVALID;
1115 vhost->context->count_wsi_allocated++;
1118 * outermost create notification for wsi
1119 * no user_space because no protocol selection
1121 vhost->protocols[0].callback(new_wsi, LWS_CALLBACK_WSI_CREATE,
1128 * lws_http_transaction_completed() - wait for new http transaction or close
1129 * @wsi: websocket connection
1131 * Returns 1 if the HTTP connection must close now
1132 * Returns 0 and resets connection to wait for new HTTP header /
1133 * transaction if possible
1136 LWS_VISIBLE int LWS_WARN_UNUSED_RESULT
1137 lws_http_transaction_completed(struct lws *wsi)
1139 int n = NO_PENDING_TIMEOUT;
1141 lws_access_log(wsi);
1143 lwsl_debug("%s: wsi %p\n", __func__, wsi);
1144 /* if we can't go back to accept new headers, drop the connection */
1145 if (wsi->u.http.connection_type != HTTP_CONNECTION_KEEP_ALIVE) {
1146 lwsl_info("%s: %p: close connection\n", __func__, wsi);
1150 /* otherwise set ourselves up ready to go again */
1151 wsi->state = LWSS_HTTP;
1152 wsi->mode = LWSCM_HTTP_SERVING;
1153 wsi->u.http.content_length = 0;
1154 wsi->hdr_parsing_completed = 0;
1155 #ifdef LWS_WITH_ACCESS_LOG
1156 wsi->access_log.sent = 0;
1159 if (wsi->vhost->keepalive_timeout)
1160 n = PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE;
1161 lws_set_timeout(wsi, n, wsi->vhost->keepalive_timeout);
1164 * We already know we are on http1.1 / keepalive and the next thing
1165 * coming will be another header set.
1167 * If there is no pending rx and we still have the ah, drop it and
1168 * reacquire a new ah when the new headers start to arrive. (Otherwise
1169 * we needlessly hog an ah indefinitely.)
1171 * However if there is pending rx and we know from the keepalive state
1172 * that is already at least the start of another header set, simply
1173 * reset the existing header table and keep it.
1175 if (wsi->u.hdr.ah) {
1176 lwsl_info("%s: wsi->more_rx_waiting=%d\n", __func__,
1177 wsi->more_rx_waiting);
1179 if (!wsi->more_rx_waiting) {
1180 wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
1181 lws_header_table_detach(wsi, 1);
1183 lws_header_table_reset(wsi, 1);
1186 /* If we're (re)starting on headers, need other implied init */
1187 wsi->u.hdr.ues = URIES_IDLE;
1189 lwsl_info("%s: %p: keep-alive await new transaction\n", __func__, wsi);
1195 lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)
1197 struct lws_context *context = vh->context;
1198 struct lws *new_wsi = lws_create_new_server_wsi(vh);
1201 compatible_close(accept_fd);
1205 lwsl_info("%s: new wsi %p, sockfd %d\n", __func__, new_wsi, accept_fd);
1207 new_wsi->sock = accept_fd;
1209 /* the transport is accepted... give him time to negotiate */
1210 lws_set_timeout(new_wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
1211 context->timeout_secs);
1214 mbed3_tcp_stream_accept(accept_fd, new_wsi);
1218 * A new connection was accepted. Give the user a chance to
1219 * set properties of the newly created wsi. There's no protocol
1220 * selected yet so we issue this to protocols[0]
1222 if ((context->vhost_list->protocols[0].callback)(new_wsi,
1223 LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, NULL, NULL, 0)) {
1224 compatible_close(new_wsi->sock);
1229 lws_libev_accept(new_wsi, new_wsi->sock);
1230 lws_libuv_accept(new_wsi, new_wsi->sock);
1232 if (!LWS_SSL_ENABLED(new_wsi->vhost)) {
1233 if (insert_wsi_socket_into_fds(context, new_wsi)) {
1234 lwsl_err("%s: fail inserting socket\n", __func__);
1238 new_wsi->mode = LWSCM_SSL_INIT;
1239 if (lws_server_socket_service_ssl(new_wsi, accept_fd)) {
1240 lwsl_err("%s: fail ssl negotiation\n", __func__);
1245 if (!lws_header_table_attach(new_wsi, 0))
1246 lwsl_debug("Attached ah immediately\n");
1251 lws_close_free_wsi(new_wsi, LWS_CLOSE_STATUS_NOSTATUS);
1257 * lws_adopt_socket() - adopt foreign socket as if listen socket accepted it
1258 * @context: lws context
1259 * @accept_fd: fd of already-accepted socket to adopt
1261 * Either returns new wsi bound to accept_fd, or closes accept_fd and
1262 * returns NULL, having cleaned up any new wsi pieces.
1264 * LWS adopts the socket in http serving mode, it's ready to accept an upgrade
1265 * to ws or just serve http.
1268 LWS_VISIBLE struct lws *
1269 lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd)
1271 return lws_adopt_socket_vhost(context->vhost_list, accept_fd);
1276 * lws_adopt_socket_readbuf() - adopt foreign socket and first rx as if listen socket accepted it
1277 * @context: lws context
1278 * @accept_fd: fd of already-accepted socket to adopt
1279 * @readbuf: NULL or pointer to data that must be drained before reading from
1281 * @len: The length of the data held at @readbuf
1283 * Either returns new wsi bound to accept_fd, or closes accept_fd and
1284 * returns NULL, having cleaned up any new wsi pieces.
1286 * LWS adopts the socket in http serving mode, it's ready to accept an upgrade
1287 * to ws or just serve http.
1289 * If your external code did not already read from the socket, you can use
1290 * lws_adopt_socket() instead.
1292 * This api is guaranteed to use the data at @readbuf first, before reading from
1295 * @readbuf is limited to the size of the ah rx buf, currently 2048 bytes.
1298 LWS_VISIBLE LWS_EXTERN struct lws *
1299 lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,
1300 const char *readbuf, size_t len)
1302 struct lws *wsi = lws_adopt_socket(context, accept_fd);
1303 struct lws_context_per_thread *pt;
1304 struct allocated_headers *ah;
1305 struct lws_pollfd *pfd;
1313 if (len > sizeof(ah->rx)) {
1314 lwsl_err("%s: rx in too big\n", __func__);
1318 * we can't process the initial read data until we can attach an ah.
1320 * if one is available, get it and place the data in his ah rxbuf...
1321 * wsi with ah that have pending rxbuf get auto-POLLIN service.
1323 * no autoservice because we didn't get a chance to attach the
1324 * readbuf data to wsi or ah yet, and we will do it next if we get
1327 if (wsi->u.hdr.ah || !lws_header_table_attach(wsi, 0)) {
1329 memcpy(ah->rx, readbuf, len);
1333 lwsl_notice("%s: calling service on readbuf ah\n", __func__);
1334 pt = &context->pt[(int)wsi->tsi];
1336 /* unlike a normal connect, we have the headers already
1337 * (or the first part of them anyway).
1338 * libuv won't come back and service us without a network
1339 * event, so we need to do the header service right here.
1341 pfd = &pt->fds[wsi->position_in_fds_table];
1342 pfd->revents |= LWS_POLLIN;
1343 lwsl_err("%s: calling service\n", __func__);
1344 if (lws_service_fd_tsi(context, pfd, wsi->tsi))
1345 /* service closed us */
1350 lwsl_err("%s: deferring handling ah\n", __func__);
1352 * hum if no ah came, we are on the wait list and must defer
1353 * dealing with this until the ah arrives.
1355 * later successful lws_header_table_attach() will apply the
1356 * below to the rx buffer (via lws_header_table_reset()).
1358 wsi->u.hdr.preamble_rx = lws_malloc(len);
1359 memcpy(wsi->u.hdr.preamble_rx, readbuf, len);
1360 wsi->u.hdr.preamble_rx_len = len;
1365 lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
1371 lws_server_socket_service(struct lws_context *context, struct lws *wsi,
1372 struct lws_pollfd *pollfd)
1374 struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
1375 lws_sockfd_type accept_fd = LWS_SOCK_INVALID;
1376 struct allocated_headers *ah;
1378 struct sockaddr_in cli_addr;
1383 switch (wsi->mode) {
1385 case LWSCM_HTTP_SERVING:
1386 case LWSCM_HTTP_SERVING_ACCEPTED:
1387 case LWSCM_HTTP2_SERVING:
1389 /* handle http headers coming in */
1391 /* pending truncated sends have uber priority */
1393 if (wsi->trunc_len) {
1394 if (!(pollfd->revents & LWS_POLLOUT))
1397 if (lws_issue_raw(wsi, wsi->trunc_alloc +
1399 wsi->trunc_len) < 0)
1402 * we can't afford to allow input processing to send
1403 * something new, so spin around he event loop until
1404 * he doesn't have any partials
1409 /* any incoming data ready? */
1411 if (!(pollfd->revents & pollfd->events & LWS_POLLIN))
1414 /* these states imply we MUST have an ah attached */
1416 if (wsi->state == LWSS_HTTP ||
1417 wsi->state == LWSS_HTTP_ISSUING_FILE ||
1418 wsi->state == LWSS_HTTP_HEADERS) {
1420 /* no autoservice beacuse we will do it next */
1421 if (lws_header_table_attach(wsi, 0))
1426 lwsl_debug("%s: %p: rxpos:%d rxlen:%d\n", __func__, wsi,
1427 ah->rxpos, ah->rxlen);
1429 /* if nothing in ah rx buffer, get some fresh rx */
1430 if (ah->rxpos == ah->rxlen) {
1431 ah->rxlen = lws_ssl_capable_read(wsi, ah->rx,
1434 lwsl_debug("%s: wsi %p, ah->rxlen = %d\r\n",
1435 __func__, wsi, ah->rxlen);
1436 switch (ah->rxlen) {
1438 lwsl_info("%s: read 0 len\n", __func__);
1439 /* lwsl_info(" state=%d\n", wsi->state); */
1440 // if (!wsi->hdr_parsing_completed)
1441 // lws_header_table_detach(wsi);
1443 case LWS_SSL_CAPABLE_ERROR:
1445 case LWS_SSL_CAPABLE_MORE_SERVICE:
1446 ah->rxlen = ah->rxpos = 0;
1450 assert(ah->rxpos != ah->rxlen && ah->rxlen);
1451 /* just ignore incoming if waiting for close */
1452 if (wsi->state != LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
1453 n = lws_read(wsi, ah->rx + ah->rxpos,
1454 ah->rxlen - ah->rxpos);
1455 if (n < 0) /* we closed wsi */
1457 if (wsi->u.hdr.ah) {
1458 if ( wsi->u.hdr.ah->rxlen)
1459 wsi->u.hdr.ah->rxpos += n;
1461 if (wsi->u.hdr.ah->rxpos == wsi->u.hdr.ah->rxlen &&
1462 (wsi->mode != LWSCM_HTTP_SERVING &&
1463 wsi->mode != LWSCM_HTTP_SERVING_ACCEPTED &&
1464 wsi->mode != LWSCM_HTTP2_SERVING))
1465 lws_header_table_detach(wsi, 1);
1473 len = lws_ssl_capable_read(wsi, pt->serv_buf,
1474 LWS_MAX_SOCKET_IO_BUF);
1475 lwsl_debug("%s: wsi %p read %d\r\n", __func__, wsi, len);
1478 lwsl_info("%s: read 0 len\n", __func__);
1479 /* lwsl_info(" state=%d\n", wsi->state); */
1480 // if (!wsi->hdr_parsing_completed)
1481 // lws_header_table_detach(wsi);
1483 case LWS_SSL_CAPABLE_ERROR:
1485 case LWS_SSL_CAPABLE_MORE_SERVICE:
1489 /* just ignore incoming if waiting for close */
1490 if (wsi->state != LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
1492 * hm this may want to send
1493 * (via HTTP callback for example)
1495 n = lws_read(wsi, pt->serv_buf, len);
1496 if (n < 0) /* we closed wsi */
1498 /* hum he may have used up the
1499 * writability above */
1504 /* this handles POLLOUT for http serving fragments */
1506 if (!(pollfd->revents & LWS_POLLOUT))
1510 if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
1511 lwsl_notice("%s a\n", __func__);
1515 if (!wsi->hdr_parsing_completed)
1518 if (wsi->state != LWSS_HTTP_ISSUING_FILE) {
1519 n = user_callback_handle_rxflow(wsi->protocol->callback,
1520 wsi, LWS_CALLBACK_HTTP_WRITEABLE,
1521 wsi->user_space, NULL, 0);
1523 lwsl_info("writeable_fail\n");
1529 /* >0 == completion, <0 == error */
1530 n = lws_serve_http_file_fragment(wsi);
1531 if (n < 0 || (n > 0 && lws_http_transaction_completed(wsi))) {
1532 lwsl_info("completed\n");
1537 case LWSCM_SERVER_LISTENER:
1540 /* pollin means a client has connected to us then */
1543 if (!(pollfd->revents & LWS_POLLIN) || !(pollfd->events & LWS_POLLIN))
1546 /* listen socket got an unencrypted connection... */
1548 clilen = sizeof(cli_addr);
1549 lws_latency_pre(context, wsi);
1550 accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
1552 lws_latency(context, wsi, "listener accept", accept_fd,
1554 if (accept_fd < 0) {
1555 if (LWS_ERRNO == LWS_EAGAIN ||
1556 LWS_ERRNO == LWS_EWOULDBLOCK) {
1557 lwsl_err("accept asks to try again\n");
1560 lwsl_err("ERROR on accept: %s\n", strerror(LWS_ERRNO));
1564 lws_plat_set_socket_options(wsi->vhost, accept_fd);
1566 lwsl_debug("accepted new conn port %u on fd=%d\n",
1567 ntohs(cli_addr.sin_port), accept_fd);
1570 /* not very beautiful... */
1571 accept_fd = (lws_sockfd_type)pollfd;
1574 * look at who we connected to and give user code a chance
1575 * to reject based on client IP. There's no protocol selected
1576 * yet so we issue this to protocols[0]
1578 if ((wsi->vhost->protocols[0].callback)(wsi,
1579 LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
1580 NULL, (void *)(long)accept_fd, 0)) {
1581 lwsl_debug("Callback denied network connection\n");
1582 compatible_close(accept_fd);
1586 if (!lws_adopt_socket_vhost(wsi->vhost, accept_fd))
1587 /* already closed cleanly as necessary */
1591 } while (pt->fds_count < context->fd_limit_per_thread - 1 &&
1592 lws_poll_listen_fd(&pt->fds[wsi->position_in_fds_table]) > 0);
1600 if (!lws_server_socket_service_ssl(wsi, accept_fd))
1604 lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
1610 * lws_serve_http_file() - Send a file back to the client using http
1611 * @wsi: Websocket instance (available from user callback)
1612 * @file: The file to issue over http
1613 * @content_type: The http content type, eg, text/html
1614 * @other_headers: NULL or pointer to header string
1615 * @other_headers_len: length of the other headers if non-NULL
1617 * This function is intended to be called from the callback in response
1618 * to http requests from the client. It allows the callback to issue
1619 * local files down the http link in a single step.
1621 * Returning <0 indicates error and the wsi should be closed. Returning
1622 * >0 indicates the file was completely sent and
1623 * lws_http_transaction_completed() called on the wsi (and close if != 0)
1624 * ==0 indicates the file transfer is started and needs more service later,
1625 * the wsi should be left alone.
1629 lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
1630 const char *other_headers, int other_headers_len)
1632 static const char * const intermediates[] = { "private", "public" };
1633 struct lws_context *context = lws_get_context(wsi);
1634 struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
1635 char cache_control[50], *cc = "no-store";
1636 unsigned char *response = pt->serv_buf + LWS_PRE;
1637 unsigned char *p = response;
1638 unsigned char *end = p + LWS_MAX_SOCKET_IO_BUF - LWS_PRE;
1639 int ret = 0, cclen = 8;
1641 wsi->u.http.fd = lws_plat_file_open(wsi, file, &wsi->u.http.filelen,
1644 if (wsi->u.http.fd == LWS_INVALID_FILE) {
1645 lwsl_err("Unable to open '%s'\n", file);
1646 lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
1651 if (lws_add_http_header_status(wsi, 200, &p, end))
1653 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
1654 (unsigned char *)content_type,
1655 strlen(content_type), &p, end))
1657 if (lws_add_http_header_content_length(wsi, wsi->u.http.filelen, &p, end))
1660 if (wsi->cache_secs && wsi->cache_reuse) {
1661 if (wsi->cache_revalidate) {
1663 cclen = sprintf(cache_control, "%s max-age: %u",
1664 intermediates[wsi->cache_intermediaries],
1672 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CACHE_CONTROL,
1673 (unsigned char *)cc, cclen, &p, end))
1676 if (other_headers) {
1677 if ((end - p) < other_headers_len)
1679 memcpy(p, other_headers, other_headers_len);
1680 p += other_headers_len;
1683 if (lws_finalize_http_header(wsi, &p, end))
1686 ret = lws_write(wsi, response, p - response, LWS_WRITE_HTTP_HEADERS);
1687 if (ret != (p - response)) {
1688 lwsl_err("_write returned %d from %d\n", ret, (p - response));
1692 wsi->u.http.filepos = 0;
1693 wsi->state = LWSS_HTTP_ISSUING_FILE;
1695 return lws_serve_http_file_fragment(wsi);
1699 lws_interpret_incoming_packet(struct lws *wsi, unsigned char **buf, size_t len)
1703 lwsl_parser("%s: received %d byte packet\n", __func__, (int)len);
1705 lwsl_hexdump(*buf, len);
1708 /* let the rx protocol state machine have as much as it needs */
1712 * we were accepting input but now we stopped doing so
1714 if (!(wsi->rxflow_change_to & LWS_RXFLOW_ALLOW)) {
1715 lws_rxflow_cache(wsi, *buf, 0, len);
1716 lwsl_parser("%s: cached %d\n", __func__, len);
1720 if (wsi->u.ws.rx_draining_ext) {
1721 m = lws_rx_sm(wsi, 0);
1727 /* account for what we're using in rxflow buffer */
1728 if (wsi->rxflow_buffer)
1731 /* consume payload bytes efficiently */
1732 if (wsi->lws_rx_parse_state ==
1733 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED)
1734 lws_payload_until_length_exhausted(wsi, buf, &len);
1736 /* process the byte */
1737 m = lws_rx_sm(wsi, *(*buf)++);
1743 lwsl_parser("%s: exit with %d unused\n", __func__, (int)len);
1749 lws_server_get_canonical_hostname(struct lws_context *context,
1750 struct lws_context_creation_info *info)
1752 if (lws_check_opt(info->options, LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME))
1755 /* find canonical hostname */
1756 gethostname((char *)context->canonical_hostname,
1757 sizeof(context->canonical_hostname) - 1);
1759 lwsl_notice(" canonical_hostname = %s\n", context->canonical_hostname);