2693cc0b826ee14902472774b495bc6fe16a4c18
[platform/upstream/libwebsockets.git] / lib / server.c
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010-2016 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
25 #if defined (LWS_WITH_ESP8266)
26 #undef memcpy
27 void *memcpy(void *dest, const void *src, size_t n)
28 {
29         return ets_memcpy(dest, src, n);
30 }
31 #endif
32
33 int
34 lws_context_init_server(struct lws_context_creation_info *info,
35                         struct lws_vhost *vhost)
36 {
37 #if LWS_POSIX
38         int n, opt = 1, limit = 1;
39 #endif
40         lws_sockfd_type sockfd;
41         struct lws_vhost *vh;
42         struct lws *wsi;
43         int m = 0;
44
45         (void)opt;
46         /* set up our external listening socket we serve on */
47
48         if (info->port == CONTEXT_PORT_NO_LISTEN || info->port == CONTEXT_PORT_NO_LISTEN_SERVER)
49                 return 0;
50
51         vh = vhost->context->vhost_list;
52         while (vh) {
53                 if (vh->listen_port == info->port) {
54                         if ((!info->iface && !vh->iface) ||
55                             (info->iface && vh->iface &&
56                             !strcmp(info->iface, vh->iface))) {
57                                 vhost->listen_port = info->port;
58                                 vhost->iface = info->iface;
59                                 lwsl_notice(" using listen skt from vhost %s\n",
60                                             vh->name);
61                                 return 0;
62                         }
63                 }
64                 vh = vh->vhost_next;
65         }
66
67 #if LWS_POSIX
68 #if defined(__linux__)
69         limit = vhost->context->count_threads;
70 #endif
71
72         for (m = 0; m < limit; m++) {
73 #ifdef LWS_USE_UNIX_SOCK
74         if (LWS_UNIX_SOCK_ENABLED(vhost))
75                 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
76         else
77 #endif
78 #ifdef LWS_USE_IPV6
79         if (LWS_IPV6_ENABLED(vhost))
80                 sockfd = socket(AF_INET6, SOCK_STREAM, 0);
81         else
82 #endif
83                 sockfd = socket(AF_INET, SOCK_STREAM, 0);
84
85         if (sockfd == -1) {
86 #else
87 #if defined(LWS_WITH_ESP8266)
88         sockfd = esp8266_create_tcp_listen_socket(vhost);
89         if (!lws_sockfd_valid(sockfd)) {
90 #endif
91 #endif
92                 lwsl_err("ERROR opening socket\n");
93                 return 1;
94         }
95 #if LWS_POSIX && !defined(LWS_WITH_ESP32)
96         /*
97          * allow us to restart even if old sockets in TIME_WAIT
98          */
99         if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
100                        (const void *)&opt, sizeof(opt)) < 0) {
101                 lwsl_err("reuseaddr failed\n");
102                 compatible_close(sockfd);
103                 return 1;
104         }
105
106 #if defined(LWS_USE_IPV6) && defined(IPV6_V6ONLY)
107         if (LWS_IPV6_ENABLED(vhost)) {
108                 if (vhost->options & LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY) {
109                         int value = (vhost->options & LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE) ? 1 : 0;
110                         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
111                                         (const void*)&value, sizeof(value)) < 0) {
112                                 compatible_close(sockfd);
113                                 return 1;
114                         }
115                 }
116         }
117 #endif
118
119 #if defined(__linux__) && defined(SO_REUSEPORT) && LWS_MAX_SMP > 1
120         if (vhost->context->count_threads > 1)
121                 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT,
122                                 (const void *)&opt, sizeof(opt)) < 0) {
123                         compatible_close(sockfd);
124                         return 1;
125                 }
126 #endif
127 #endif
128         lws_plat_set_socket_options(vhost, sockfd);
129
130 #if LWS_POSIX
131         n = lws_socket_bind(vhost, sockfd, info->port, info->iface);
132         if (n < 0)
133                 goto bail;
134         info->port = n;
135 #endif
136         vhost->listen_port = info->port;
137         vhost->iface = info->iface;
138
139         wsi = lws_zalloc(sizeof(struct lws));
140         if (wsi == NULL) {
141                 lwsl_err("Out of mem\n");
142                 goto bail;
143         }
144         wsi->context = vhost->context;
145         wsi->desc.sockfd = sockfd;
146         wsi->mode = LWSCM_SERVER_LISTENER;
147         wsi->protocol = vhost->protocols;
148         wsi->tsi = m;
149         wsi->vhost = vhost;
150         wsi->listener = 1;
151
152 #ifdef LWS_USE_LIBUV
153         if (LWS_LIBUV_ENABLED(vhost->context))
154                 lws_uv_initvhost(vhost, wsi);
155 #endif
156
157         if (insert_wsi_socket_into_fds(vhost->context, wsi))
158                 goto bail;
159
160         vhost->context->count_wsi_allocated++;
161         vhost->lserv_wsi = wsi;
162
163 #if LWS_POSIX
164         n = listen(wsi->desc.sockfd, LWS_SOMAXCONN);
165         if (n < 0) {
166                 lwsl_err("listen failed with error %d\n", LWS_ERRNO);
167                 vhost->lserv_wsi = NULL;
168                 vhost->context->count_wsi_allocated--;
169                 remove_wsi_socket_from_fds(wsi);
170                 goto bail;
171         }
172         } /* for each thread able to independently listen */
173 #else
174 #if defined(LWS_WITH_ESP8266)
175         esp8266_tcp_stream_bind(wsi->desc.sockfd, info->port, wsi);
176 #endif
177 #endif
178         if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) {
179 #ifdef LWS_USE_UNIX_SOCK
180                 if (LWS_UNIX_SOCK_ENABLED(vhost))
181                         lwsl_notice(" Listening on \"%s\"\n", info->iface);
182                 else
183 #endif
184                         lwsl_notice(" Listening on port %d\n", info->port);
185         }
186
187         return 0;
188
189 bail:
190         compatible_close(sockfd);
191
192         return 1;
193 }
194
195 #if defined(LWS_WITH_ESP8266)
196 #undef strchr
197 #define strchr ets_strchr
198 #endif
199
200 struct lws_vhost *
201 lws_select_vhost(struct lws_context *context, int port, const char *servername)
202 {
203         struct lws_vhost *vhost = context->vhost_list;
204         const char *p;
205         int n, m, colon;
206
207         n = strlen(servername);
208         colon = n;
209         p = strchr(servername, ':');
210         if (p)
211                 colon = p - servername;
212
213         /* Priotity 1: first try exact matches */
214
215         while (vhost) {
216                 if (port == vhost->listen_port &&
217                     !strncmp(vhost->name, servername, colon)) {
218                         lwsl_info("SNI: Found: %s\n", servername);
219                         return vhost;
220                 }
221                 vhost = vhost->vhost_next;
222         }
223
224         /*
225          * Priority 2: if no exact matches, try matching *.vhost-name
226          * unintentional matches are possible but resolve to x.com for *.x.com
227          * which is reasonable.  If exact match exists we already chose it and
228          * never reach here.  SSL will still fail it if the cert doesn't allow
229          * *.x.com.
230          */
231
232         vhost = context->vhost_list;
233         while (vhost) {
234                 m = strlen(vhost->name);
235                 if (port == vhost->listen_port &&
236                     m <= (colon - 2) &&
237                     servername[colon - m - 1] == '.' &&
238                     !strncmp(vhost->name, servername + colon - m, m)) {
239                         lwsl_info("SNI: Found %s on wildcard: %s\n",
240                                     servername, vhost->name);
241                         return vhost;
242                 }
243                 vhost = vhost->vhost_next;
244         }
245
246         /* Priority 3: match the first vhost on our port */
247
248         vhost = context->vhost_list;
249         while (vhost) {
250                 if (port == vhost->listen_port) {
251                         lwsl_info("vhost match to %s based on port %d\n",
252                                         vhost->name, port);
253                         return vhost;
254                 }
255                 vhost = vhost->vhost_next;
256         }
257
258         /* no match */
259
260         return NULL;
261 }
262
263 LWS_VISIBLE LWS_EXTERN const char *
264 lws_get_mimetype(const char *file, const struct lws_http_mount *m)
265 {
266         int n = strlen(file);
267         const struct lws_protocol_vhost_options *pvo = NULL;
268
269         if (m)
270                 pvo = m->extra_mimetypes;
271
272         if (n < 5)
273                 return NULL;
274
275         if (!strcmp(&file[n - 4], ".ico"))
276                 return "image/x-icon";
277
278         if (!strcmp(&file[n - 4], ".gif"))
279                 return "image/gif";
280
281         if (!strcmp(&file[n - 3], ".js"))
282                 return "text/javascript";
283
284         if (!strcmp(&file[n - 4], ".png"))
285                 return "image/png";
286
287         if (!strcmp(&file[n - 4], ".jpg"))
288                 return "image/jpeg";
289
290         if (!strcmp(&file[n - 3], ".gz"))
291                 return "application/gzip";
292
293         if (!strcmp(&file[n - 4], ".JPG"))
294                 return "image/jpeg";
295
296         if (!strcmp(&file[n - 5], ".html"))
297                 return "text/html";
298
299         if (!strcmp(&file[n - 4], ".css"))
300                 return "text/css";
301
302         if (!strcmp(&file[n - 4], ".txt"))
303                 return "text/plain";
304
305         if (!strcmp(&file[n - 4], ".svg"))
306                 return "image/svg+xml";
307
308         if (!strcmp(&file[n - 4], ".ttf"))
309                 return "application/x-font-ttf";
310
311         if (!strcmp(&file[n - 4], ".otf"))
312                 return "application/font-woff";
313
314         if (!strcmp(&file[n - 5], ".woff"))
315                 return "application/font-woff";
316
317         if (!strcmp(&file[n - 4], ".xml"))
318                 return "application/xml";
319
320         while (pvo) {
321                 if (pvo->name[0] == '*') /* ie, match anything */
322                         return pvo->value;
323
324                 if (!strcmp(&file[n - strlen(pvo->name)], pvo->name))
325                         return pvo->value;
326
327                 pvo = pvo->next;
328         }
329
330         return NULL;
331 }
332 static lws_fop_flags_t
333 lws_vfs_prepare_flags(struct lws *wsi)
334 {
335         lws_fop_flags_t f = 0;
336
337         if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING))
338                 return f;
339
340         if (strstr(lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING),
341                    "gzip")) {
342                 lwsl_info("client indicates GZIP is acceptable\n");
343                 f |= LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP;
344         }
345
346         return f;
347 }
348
349 static int
350 lws_http_serve(struct lws *wsi, char *uri, const char *origin,
351                const struct lws_http_mount *m)
352 {
353         const struct lws_protocol_vhost_options *pvo = m->interpret;
354         struct lws_process_html_args args;
355         const char *mimetype;
356 #if !defined(_WIN32_WCE) && !defined(LWS_WITH_ESP8266)
357         const struct lws_plat_file_ops *fops;
358         const char *vpath;
359         lws_fop_flags_t fflags = LWS_O_RDONLY;
360 #if defined(WIN32) && defined(LWS_HAVE__STAT32I64)
361         struct _stat32i64 st;
362 #else
363         struct stat st;
364 #endif
365         int spin = 0;
366 #endif
367         char path[256], sym[512];
368         unsigned char *p = (unsigned char *)sym + 32 + LWS_PRE, *start = p;
369         unsigned char *end = p + sizeof(sym) - 32 - LWS_PRE;
370 #if !defined(WIN32) && LWS_POSIX && !defined(LWS_WITH_ESP32)
371         size_t len;
372 #endif
373         int n;
374
375         lws_snprintf(path, sizeof(path) - 1, "%s/%s", origin, uri);
376
377 #if !defined(_WIN32_WCE) && !defined(LWS_WITH_ESP8266)
378
379         fflags |= lws_vfs_prepare_flags(wsi);
380
381         do {
382                 spin++;
383                 fops = lws_vfs_select_fops(wsi->context->fops, path, &vpath);
384
385                 if (wsi->u.http.fop_fd)
386                         lws_vfs_file_close(&wsi->u.http.fop_fd);
387
388                 wsi->u.http.fop_fd = fops->LWS_FOP_OPEN(wsi->context->fops,
389                                                         path, vpath, &fflags);
390                 if (!wsi->u.http.fop_fd) {
391                         lwsl_err("Unable to open '%s'\n", path);
392
393                         return -1;
394                 }
395
396                 /* if it can't be statted, don't try */
397                 if (fflags & LWS_FOP_FLAG_VIRTUAL)
398                         break;
399 #if defined(LWS_WITH_ESP32)
400                 break;
401 #endif
402 #if !defined(WIN32)
403                 if (fstat(wsi->u.http.fop_fd->fd, &st)) {
404                         lwsl_info("unable to stat %s\n", path);
405                         goto bail;
406                 }
407 #else
408 #if defined(LWS_HAVE__STAT32I64)
409                 if (_stat32i64(path, &st)) {
410                         lwsl_info("unable to stat %s\n", path);
411                         goto bail;
412                 }
413 #else
414                 if (stat(path, &st)) {
415                         lwsl_info("unable to stat %s\n", path);
416                         goto bail;
417                 }
418 #endif
419 #endif
420
421                 wsi->u.http.fop_fd->mod_time = (uint32_t)st.st_mtime;
422                 fflags |= LWS_FOP_FLAG_MOD_TIME_VALID;
423
424                 lwsl_debug(" %s mode %d\n", path, S_IFMT & st.st_mode);
425 #if !defined(WIN32) && LWS_POSIX && !defined(LWS_WITH_ESP32)
426                 if ((S_IFMT & st.st_mode) == S_IFLNK) {
427                         len = readlink(path, sym, sizeof(sym) - 1);
428                         if (len) {
429                                 lwsl_err("Failed to read link %s\n", path);
430                                 goto bail;
431                         }
432                         sym[len] = '\0';
433                         lwsl_debug("symlink %s -> %s\n", path, sym);
434                         lws_snprintf(path, sizeof(path) - 1, "%s", sym);
435                 }
436 #endif
437                 if ((S_IFMT & st.st_mode) == S_IFDIR) {
438                         lwsl_debug("default filename append to dir\n");
439                         lws_snprintf(path, sizeof(path) - 1, "%s/%s/index.html",
440                                  origin, uri);
441                 }
442
443         } while ((S_IFMT & st.st_mode) != S_IFREG && spin < 5);
444
445         if (spin == 5)
446                 lwsl_err("symlink loop %s \n", path);
447
448         n = sprintf(sym, "%08lX%08lX",
449                     (unsigned long)lws_vfs_get_length(wsi->u.http.fop_fd),
450                     (unsigned long)lws_vfs_get_mod_time(wsi->u.http.fop_fd));
451
452         /* disable ranges if IF_RANGE token invalid */
453
454         if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_IF_RANGE))
455                 if (strcmp(sym, lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_IF_RANGE)))
456                         /* differs - defeat Range: */
457                         wsi->u.http.ah->frag_index[WSI_TOKEN_HTTP_RANGE] = 0;
458
459         if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_IF_NONE_MATCH)) {
460                 /*
461                  * he thinks he has some version of it already,
462                  * check if the tag matches
463                  */
464                 if (!strcmp(sym, lws_hdr_simple_ptr(wsi,
465                                         WSI_TOKEN_HTTP_IF_NONE_MATCH))) {
466
467                         lwsl_debug("%s: ETAG match %s %s\n", __func__,
468                                    uri, origin);
469
470                         /* we don't need to send the payload */
471                         if (lws_add_http_header_status(wsi,
472                                         HTTP_STATUS_NOT_MODIFIED, &p, end))
473                                 return -1;
474
475                         if (lws_add_http_header_by_token(wsi,
476                                         WSI_TOKEN_HTTP_ETAG,
477                                         (unsigned char *)sym, n, &p, end))
478                                 return -1;
479
480                         if (lws_finalize_http_header(wsi, &p, end))
481                                 return -1;
482
483                         n = lws_write(wsi, start, p - start,
484                                       LWS_WRITE_HTTP_HEADERS);
485                         if (n != (p - start)) {
486                                 lwsl_err("_write returned %d from %ld\n", n,
487                                          (long)(p - start));
488                                 return -1;
489                         }
490
491                         lws_vfs_file_close(&wsi->u.http.fop_fd);
492
493                         return lws_http_transaction_completed(wsi);
494                 }
495         }
496
497         if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ETAG,
498                         (unsigned char *)sym, n, &p, end))
499                 return -1;
500 #endif
501
502         mimetype = lws_get_mimetype(path, m);
503         if (!mimetype) {
504                 lwsl_err("unknown mimetype for %s\n", path);
505                goto bail;
506         }
507         if (!mimetype[0])
508                 lwsl_debug("sending no mimetype for %s\n", path);
509
510         wsi->sending_chunked = 0;
511
512         /*
513          * check if this is in the list of file suffixes to be interpreted by
514          * a protocol
515          */
516         while (pvo) {
517                 n = strlen(path);
518                 if (n > (int)strlen(pvo->name) &&
519                     !strcmp(&path[n - strlen(pvo->name)], pvo->name)) {
520                         wsi->sending_chunked = 1;
521                         wsi->protocol_interpret_idx = (char)(long)pvo->value;
522                         lwsl_info("want %s interpreted by %s\n", path,
523                                     wsi->vhost->protocols[(int)(long)(pvo->value)].name);
524                         wsi->protocol = &wsi->vhost->protocols[(int)(long)(pvo->value)];
525                         if (lws_ensure_user_space(wsi))
526                                 return -1;
527                         break;
528                 }
529                 pvo = pvo->next;
530         }
531
532         if (m->protocol) {
533                 const struct lws_protocols *pp = lws_vhost_name_to_protocol(
534                                                         wsi->vhost, m->protocol);
535
536                 if (lws_bind_protocol(wsi, pp))
537                         return 1;
538                 args.p = (char *)p;
539                 args.max_len = end - p;
540                 if (pp->callback(wsi, LWS_CALLBACK_ADD_HEADERS,
541                                           wsi->user_space, &args, 0))
542                         return -1;
543                 p = (unsigned char *)args.p;
544         }
545
546         n = lws_serve_http_file(wsi, path, mimetype, (char *)start, p - start);
547
548         if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi)))
549                 return -1; /* error or can't reuse connection: close the socket */
550
551         return 0;
552 bail:
553
554         return -1;
555 }
556
557 const struct lws_http_mount *
558 lws_find_mount(struct lws *wsi, const char *uri_ptr, int uri_len)
559 {
560         const struct lws_http_mount *hm, *hit = NULL;
561         int best = 0;
562
563         hm = wsi->vhost->mount_list;
564         while (hm) {
565                 if (uri_len >= hm->mountpoint_len &&
566                     !strncmp(uri_ptr, hm->mountpoint, hm->mountpoint_len) &&
567                     (uri_ptr[hm->mountpoint_len] == '\0' ||
568                      uri_ptr[hm->mountpoint_len] == '/' ||
569                      hm->mountpoint_len == 1)
570                     ) {
571                         if (hm->origin_protocol == LWSMPRO_CALLBACK ||
572                             ((hm->origin_protocol == LWSMPRO_CGI ||
573                              lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) ||
574                              hm->protocol) &&
575                             hm->mountpoint_len > best)) {
576                                 best = hm->mountpoint_len;
577                                 hit = hm;
578                         }
579                 }
580                 hm = hm->mount_next;
581         }
582
583         return hit;
584 }
585
586 #if LWS_POSIX
587
588 static int
589 lws_find_string_in_file(const char *filename, const char *string, int stringlen)
590 {
591         char buf[128];
592         int fd, match = 0, pos = 0, n = 0, hit = 0;
593
594         fd = open(filename, O_RDONLY);
595         if (fd < 0) {
596                 lwsl_err("can't open auth file: %s\n", filename);
597                 return 1;
598         }
599
600         while (1) {
601                 if (pos == n) {
602                         n = read(fd, buf, sizeof(buf));
603                         if (n <= 0) {
604                                 if (match == stringlen)
605                                         hit = 1;
606                                 break;
607                         }
608                         pos = 0;
609                 }
610
611                 if (match == stringlen) {
612                         if (buf[pos] == '\r' || buf[pos] == '\n') {
613                                 hit = 1;
614                                 break;
615                         }
616                         match = 0;
617                 }
618
619                 if (buf[pos] == string[match])
620                         match++;
621                 else
622                         match = 0;
623
624                 pos++;
625         }
626
627         close(fd);
628
629         return hit;
630 }
631
632 static int
633 lws_unauthorised_basic_auth(struct lws *wsi)
634 {
635         struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
636         unsigned char *start = pt->serv_buf + LWS_PRE,
637                       *p = start, *end = p + 512;
638         char buf[64];
639         int n;
640
641         /* no auth... tell him it is required */
642
643         if (lws_add_http_header_status(wsi, HTTP_STATUS_UNAUTHORIZED, &p, end))
644                 return -1;
645
646         n = lws_snprintf(buf, sizeof(buf), "Basic realm=\"lwsws\"");
647         if (lws_add_http_header_by_token(wsi,
648                         WSI_TOKEN_HTTP_WWW_AUTHENTICATE,
649                         (unsigned char *)buf, n, &p, end))
650                 return -1;
651
652         if (lws_finalize_http_header(wsi, &p, end))
653                 return -1;
654
655         n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
656         if (n < 0)
657                 return -1;
658
659         return lws_http_transaction_completed(wsi);
660
661 }
662
663 #endif
664
665 int lws_clean_url(char *p)
666 {
667         while (*p) {
668                 if (p[0] == '/' && p[1] == '/') {
669                         char *p1 = p;
670                         while (*p1) {
671                                 *p1 = p1[1];
672                                 p1++;
673                         }
674                         continue;
675                 }
676                 p++;
677         }
678
679         return 0;
680 }
681
682 int
683 lws_http_action(struct lws *wsi)
684 {
685         struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
686         enum http_connection_type connection_type;
687         enum http_version request_version;
688         char content_length_str[32];
689         struct lws_process_html_args args;
690         const struct lws_http_mount *hit = NULL;
691         unsigned int n, count = 0;
692         char http_version_str[10];
693         char http_conn_str[20];
694         int http_version_len;
695         char *uri_ptr = NULL, *s;
696         int uri_len = 0;
697         int meth = -1;
698
699         static const unsigned char methods[] = {
700                 WSI_TOKEN_GET_URI,
701                 WSI_TOKEN_POST_URI,
702                 WSI_TOKEN_OPTIONS_URI,
703                 WSI_TOKEN_PUT_URI,
704                 WSI_TOKEN_PATCH_URI,
705                 WSI_TOKEN_DELETE_URI,
706                 WSI_TOKEN_CONNECT,
707 #ifdef LWS_USE_HTTP2
708                 WSI_TOKEN_HTTP_COLON_PATH,
709 #endif
710         };
711 #if defined(_DEBUG) || defined(LWS_WITH_ACCESS_LOG)
712         static const char * const method_names[] = {
713                 "GET", "POST", "OPTIONS", "PUT", "PATCH", "DELETE", "CONNECT",
714 #ifdef LWS_USE_HTTP2
715                 ":path",
716 #endif
717         };
718 #endif
719         static const char * const oprot[] = {
720                 "http://", "https://"
721         };
722
723         /* it's not websocket.... shall we accept it as http? */
724
725         for (n = 0; n < ARRAY_SIZE(methods); n++)
726                 if (lws_hdr_total_length(wsi, methods[n]))
727                         count++;
728         if (!count) {
729                 lwsl_warn("Missing URI in HTTP request\n");
730                 goto bail_nuke_ah;
731         }
732
733         if (count != 1) {
734                 lwsl_warn("multiple methods?\n");
735                 goto bail_nuke_ah;
736         }
737
738         if (lws_ensure_user_space(wsi))
739                 goto bail_nuke_ah;
740
741         for (n = 0; n < ARRAY_SIZE(methods); n++)
742                 if (lws_hdr_total_length(wsi, methods[n])) {
743                         uri_ptr = lws_hdr_simple_ptr(wsi, methods[n]);
744                         uri_len = lws_hdr_total_length(wsi, methods[n]);
745                         lwsl_info("Method: %s request for '%s'\n",
746                                         method_names[n], uri_ptr);
747                         meth = n;
748                         break;
749                 }
750
751         (void)meth;
752
753         /* we insist on absolute paths */
754
755         if (uri_ptr[0] != '/') {
756                 lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
757
758                 goto bail_nuke_ah;
759         }
760
761         /* HTTP header had a content length? */
762
763         wsi->u.http.content_length = 0;
764         if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) ||
765                 lws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI) ||
766                 lws_hdr_total_length(wsi, WSI_TOKEN_PUT_URI))
767                 wsi->u.http.content_length = 100 * 1024 * 1024;
768
769         if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
770                 lws_hdr_copy(wsi, content_length_str,
771                              sizeof(content_length_str) - 1,
772                              WSI_TOKEN_HTTP_CONTENT_LENGTH);
773                 wsi->u.http.content_length = atoll(content_length_str);
774         }
775
776         if (wsi->http2_substream) {
777                 wsi->u.http.request_version = HTTP_VERSION_2;
778         } else {
779                 /* http_version? Default to 1.0, override with token: */
780                 request_version = HTTP_VERSION_1_0;
781
782                 /* Works for single digit HTTP versions. : */
783                 http_version_len = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP);
784                 if (http_version_len > 7) {
785                         lws_hdr_copy(wsi, http_version_str,
786                                         sizeof(http_version_str) - 1, WSI_TOKEN_HTTP);
787                         if (http_version_str[5] == '1' && http_version_str[7] == '1')
788                                 request_version = HTTP_VERSION_1_1;
789                 }
790                 wsi->u.http.request_version = request_version;
791
792                 /* HTTP/1.1 defaults to "keep-alive", 1.0 to "close" */
793                 if (request_version == HTTP_VERSION_1_1)
794                         connection_type = HTTP_CONNECTION_KEEP_ALIVE;
795                 else
796                         connection_type = HTTP_CONNECTION_CLOSE;
797
798                 /* Override default if http "Connection:" header: */
799                 if (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION)) {
800                         lws_hdr_copy(wsi, http_conn_str, sizeof(http_conn_str) - 1,
801                                      WSI_TOKEN_CONNECTION);
802                         http_conn_str[sizeof(http_conn_str) - 1] = '\0';
803                         if (!strcasecmp(http_conn_str, "keep-alive"))
804                                 connection_type = HTTP_CONNECTION_KEEP_ALIVE;
805                         else
806                                 if (!strcasecmp(http_conn_str, "close"))
807                                         connection_type = HTTP_CONNECTION_CLOSE;
808                 }
809                 wsi->u.http.connection_type = connection_type;
810         }
811
812         n = wsi->protocol->callback(wsi, LWS_CALLBACK_FILTER_HTTP_CONNECTION,
813                                     wsi->user_space, uri_ptr, uri_len);
814         if (n) {
815                 lwsl_info("LWS_CALLBACK_HTTP closing\n");
816
817                 return 1;
818         }
819         /*
820          * if there is content supposed to be coming,
821          * put a timeout on it having arrived
822          */
823         lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,
824                         wsi->context->timeout_secs);
825 #ifdef LWS_OPENSSL_SUPPORT
826         if (wsi->redirect_to_https) {
827                 /*
828                  * we accepted http:// only so we could redirect to
829                  * https://, so issue the redirect.  Create the redirection
830                  * URI from the host: header and ignore the path part
831                  */
832                 unsigned char *start = pt->serv_buf + LWS_PRE, *p = start,
833                               *end = p + 512;
834
835                 if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST))
836                         goto bail_nuke_ah;
837
838                 n = sprintf((char *)end, "https://%s/",
839                             lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));
840
841                 n = lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,
842                                       end, n, &p, end);
843                 if ((int)n < 0)
844                         goto bail_nuke_ah;
845
846                 return lws_http_transaction_completed(wsi);
847         }
848 #endif
849
850 #ifdef LWS_WITH_ACCESS_LOG
851         /*
852          * Produce Apache-compatible log string for wsi, like this:
853          *
854          * 2.31.234.19 - - [27/Mar/2016:03:22:44 +0800]
855          * "GET /aep-screen.png HTTP/1.1"
856          * 200 152987 "https://libwebsockets.org/index.html"
857          * "Mozilla/5.0 (Macint... Chrome/49.0.2623.87 Safari/537.36"
858          *
859          */
860         {
861                 static const char * const hver[] = {
862                         "http/1.0", "http/1.1", "http/2"
863                 };
864 #ifdef LWS_USE_IPV6
865                 char ads[INET6_ADDRSTRLEN];
866 #else
867                 char ads[INET_ADDRSTRLEN];
868 #endif
869                 char da[64];
870                 const char *pa, *me;
871                 struct tm *tmp;
872                 time_t t = time(NULL);
873                 int l = 256;
874
875                 if (wsi->access_log_pending)
876                         lws_access_log(wsi);
877
878                 wsi->access_log.header_log = lws_malloc(l);
879                 if (wsi->access_log.header_log) {
880
881                         tmp = localtime(&t);
882                         if (tmp)
883                                 strftime(da, sizeof(da), "%d/%b/%Y:%H:%M:%S %z", tmp);
884                         else
885                                 strcpy(da, "01/Jan/1970:00:00:00 +0000");
886
887                         pa = lws_get_peer_simple(wsi, ads, sizeof(ads));
888                         if (!pa)
889                                 pa = "(unknown)";
890
891                         if (meth >= 0)
892                                 me = method_names[meth];
893                         else
894                                 me = "unknown";
895
896                         lws_snprintf(wsi->access_log.header_log, l,
897                                  "%s - - [%s] \"%s %s %s\"",
898                                  pa, da, me, uri_ptr,
899                                  hver[wsi->u.http.request_version]);
900
901                         l = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT);
902                         if (l) {
903                                 wsi->access_log.user_agent = lws_malloc(l + 2);
904                                 if (wsi->access_log.user_agent)
905                                         lws_hdr_copy(wsi, wsi->access_log.user_agent,
906                                                         l + 1, WSI_TOKEN_HTTP_USER_AGENT);
907                                 else
908                                         lwsl_err("OOM getting user agent\n");
909                         }
910                         wsi->access_log_pending = 1;
911                 }
912         }
913 #endif
914
915         /* can we serve it from the mount list? */
916
917         hit = lws_find_mount(wsi, uri_ptr, uri_len);
918         if (!hit) {
919                 /* deferred cleanup and reset to protocols[0] */
920
921                 lwsl_info("no hit\n");
922
923                 if (lws_bind_protocol(wsi, &wsi->vhost->protocols[0]))
924                         return 1;
925
926                 n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP,
927                                     wsi->user_space, uri_ptr, uri_len);
928
929                 goto after;
930         }
931
932         s = uri_ptr + hit->mountpoint_len;
933
934         /*
935          * if we have a mountpoint like https://xxx.com/yyy
936          * there is an implied / at the end for our purposes since
937          * we can only mount on a "directory".
938          *
939          * But if we just go with that, the browser cannot understand
940          * that he is actually looking down one "directory level", so
941          * even though we give him /yyy/abc.html he acts like the
942          * current directory level is /.  So relative urls like "x.png"
943          * wrongly look outside the mountpoint.
944          *
945          * Therefore if we didn't come in on a url with an explicit
946          * / at the end, we must redirect to add it so the browser
947          * understands he is one "directory level" down.
948          */
949         if ((hit->mountpoint_len > 1 ||
950              (hit->origin_protocol == LWSMPRO_REDIR_HTTP ||
951               hit->origin_protocol == LWSMPRO_REDIR_HTTPS)) &&
952             (*s != '/' ||
953              (hit->origin_protocol == LWSMPRO_REDIR_HTTP ||
954               hit->origin_protocol == LWSMPRO_REDIR_HTTPS)) &&
955             (hit->origin_protocol != LWSMPRO_CGI &&
956              hit->origin_protocol != LWSMPRO_CALLBACK //&&
957              //hit->protocol == NULL
958              )) {
959                 unsigned char *start = pt->serv_buf + LWS_PRE,
960                               *p = start, *end = p + 512;
961
962                 lwsl_debug("Doing 301 '%s' org %s\n", s, hit->origin);
963
964                 if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST))
965                         goto bail_nuke_ah;
966
967                 /* > at start indicates deal with by redirect */
968                 if (hit->origin_protocol == LWSMPRO_REDIR_HTTP ||
969                     hit->origin_protocol == LWSMPRO_REDIR_HTTPS)
970                         n = lws_snprintf((char *)end, 256, "%s%s",
971                                     oprot[hit->origin_protocol & 1],
972                                     hit->origin);
973                 else
974                         n = lws_snprintf((char *)end, 256,
975                             "%s%s%s/", oprot[lws_is_ssl(wsi)],
976                             lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST),
977                             uri_ptr);
978                 lws_clean_url((char *)end);
979
980                 n = lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,
981                                       end, n, &p, end);
982                 if ((int)n < 0)
983                         goto bail_nuke_ah;
984
985                 return lws_http_transaction_completed(wsi);
986         }
987
988 #if LWS_POSIX
989         /* basic auth? */
990
991         if (hit->basic_auth_login_file) {
992                 char b64[160], plain[(sizeof(b64) * 3) / 4];
993                 int m;
994
995                 /* Did he send auth? */
996                 if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_AUTHORIZATION))
997                         return lws_unauthorised_basic_auth(wsi);
998
999                 n = HTTP_STATUS_FORBIDDEN;
1000
1001                 m = lws_hdr_copy(wsi, b64, sizeof(b64), WSI_TOKEN_HTTP_AUTHORIZATION);
1002                 if (m < 7) {
1003                         lwsl_err("b64 auth too long\n");
1004                         goto transaction_result_n;
1005                 }
1006
1007                 b64[5] = '\0';
1008                 if (strcasecmp(b64, "Basic")) {
1009                         lwsl_err("auth missing basic: %s\n", b64);
1010                         goto transaction_result_n;
1011                 }
1012
1013                 /* It'll be like Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l */
1014
1015                 m = lws_b64_decode_string(b64 + 6, plain, sizeof(plain));
1016                 if (m < 0) {
1017                         lwsl_err("plain auth too long\n");
1018                         goto transaction_result_n;
1019                 }
1020
1021 //              lwsl_notice(plain);
1022
1023                 if (!lws_find_string_in_file(hit->basic_auth_login_file, plain, m)) {
1024                         lwsl_err("basic auth lookup failed\n");
1025                         return lws_unauthorised_basic_auth(wsi);
1026                 }
1027
1028                 lwsl_notice("basic auth accepted\n");
1029
1030                 /* accept the auth */
1031         }
1032 #endif
1033
1034 #if defined(LWS_WITH_HTTP_PROXY)
1035         /*
1036          * The mount is a reverse proxy?
1037          */
1038
1039         if (hit->origin_protocol == LWSMPRO_HTTPS ||
1040             hit->origin_protocol == LWSMPRO_HTTP)  {
1041                 struct lws_client_connect_info i;
1042                 char ads[96], rpath[256], *pcolon, *pslash, *p;
1043                 int n, na;
1044
1045                 memset(&i, 0, sizeof(i));
1046                 i.context = lws_get_context(wsi);
1047
1048                 pcolon = strchr(hit->origin, ':');
1049                 pslash = strchr(hit->origin, '/');
1050                 if (!pslash) {
1051                         lwsl_err("Proxy mount origin '%s' must have /\n", hit->origin);
1052                         return -1;
1053                 }
1054                 if (pcolon > pslash)
1055                         pcolon = NULL;
1056                 
1057                 if (pcolon)
1058                         n = pcolon - hit->origin;
1059                 else
1060                         n = pslash - hit->origin;
1061
1062                 if (n >= sizeof(ads) - 2)
1063                         n = sizeof(ads) - 2;
1064
1065                 memcpy(ads, hit->origin, n);
1066                 ads[n] = '\0';
1067
1068                 i.address = ads;
1069                 i.port = 80;
1070                 if (hit->origin_protocol == LWSMPRO_HTTPS) { 
1071                         i.port = 443;
1072                         i.ssl_connection = 1;
1073                 }
1074                 if (pcolon)
1075                         i.port = atoi(pcolon + 1);
1076                 
1077                 lws_snprintf(rpath, sizeof(rpath) - 1, "/%s/%s", pslash + 1, uri_ptr + hit->mountpoint_len);
1078                 lws_clean_url(rpath);
1079                 na = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_URI_ARGS);
1080                 if (na) {
1081                         p = rpath + strlen(rpath);
1082                         *p++ = '?';
1083                         lws_hdr_copy(wsi, p, &rpath[sizeof(rpath) - 1] - p, WSI_TOKEN_HTTP_URI_ARGS);
1084                         while (--na) {
1085                                 if (*p == '\0')
1086                                         *p = '&';
1087                                 p++;
1088                         }
1089                 }
1090                                 
1091
1092                 i.path = rpath;
1093                 i.host = i.address;
1094                 i.origin = NULL;
1095                 i.method = "GET";
1096                 i.parent_wsi = wsi;
1097                 i.uri_replace_from = hit->origin;
1098                 i.uri_replace_to = hit->mountpoint;
1099
1100                 lwsl_notice("proxying to %s port %d url %s, ssl %d, from %s, to %s\n",
1101                                 i.address, i.port, i.path, i.ssl_connection, i.uri_replace_from, i.uri_replace_to);
1102         
1103                 if (!lws_client_connect_via_info(&i)) {
1104                         lwsl_err("proxy connect fail\n");
1105                         return 1;
1106                 }
1107
1108                 return 0;
1109         }
1110 #endif
1111
1112         /*
1113          * A particular protocol callback is mounted here?
1114          *
1115          * For the duration of this http transaction, bind us to the
1116          * associated protocol
1117          */
1118         if (hit->origin_protocol == LWSMPRO_CALLBACK || hit->protocol) {
1119                 const struct lws_protocols *pp;
1120                 const char *name = hit->origin;
1121                 if (hit->protocol)
1122                         name = hit->protocol;
1123
1124                 pp = lws_vhost_name_to_protocol(wsi->vhost, name);
1125                 if (!pp) {
1126                         n = -1;
1127                         lwsl_err("Unable to find plugin '%s'\n",
1128                                  hit->origin);
1129                         return 1;
1130                 }
1131
1132                 if (lws_bind_protocol(wsi, pp))
1133                         return 1;
1134
1135                 args.p = uri_ptr;
1136                 args.len = uri_len;
1137                 args.max_len = hit->auth_mask;
1138                 args.final = 0; /* used to signal callback dealt with it */
1139
1140                 n = wsi->protocol->callback(wsi, LWS_CALLBACK_CHECK_ACCESS_RIGHTS,
1141                                             wsi->user_space, &args, 0);
1142                 if (n) {
1143                         lws_return_http_status(wsi, HTTP_STATUS_UNAUTHORIZED,
1144                                                NULL);
1145                         goto bail_nuke_ah;
1146                 }
1147                 if (args.final) /* callback completely handled it well */
1148                         return 0;
1149
1150                 if (hit->cgienv && wsi->protocol->callback(wsi,
1151                                 LWS_CALLBACK_HTTP_PMO,
1152                                 wsi->user_space, (void *)hit->cgienv, 0))
1153                         return 1;
1154
1155                 if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
1156                         n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP,
1157                                             wsi->user_space,
1158                                             uri_ptr + hit->mountpoint_len,
1159                                             uri_len - hit->mountpoint_len);
1160                         goto after;
1161                 }
1162         }
1163
1164 #ifdef LWS_WITH_CGI
1165         /* did we hit something with a cgi:// origin? */
1166         if (hit->origin_protocol == LWSMPRO_CGI) {
1167                 const char *cmd[] = {
1168                         NULL, /* replace with cgi path */
1169                         NULL
1170                 };
1171
1172                 lwsl_debug("%s: cgi\n", __func__);
1173                 cmd[0] = hit->origin;
1174
1175                 n = 5;
1176                 if (hit->cgi_timeout)
1177                         n = hit->cgi_timeout;
1178
1179                 n = lws_cgi(wsi, cmd, hit->mountpoint_len, n,
1180                             hit->cgienv);
1181                 if (n) {
1182                         lwsl_err("%s: cgi failed\n", __func__);
1183                         return -1;
1184                 }
1185
1186                 goto deal_body;
1187         }
1188 #endif
1189
1190         n = strlen(s);
1191         if (s[0] == '\0' || (n == 1 && s[n - 1] == '/'))
1192                 s = (char *)hit->def;
1193         if (!s)
1194                 s = "index.html";
1195
1196         wsi->cache_secs = hit->cache_max_age;
1197         wsi->cache_reuse = hit->cache_reusable;
1198         wsi->cache_revalidate = hit->cache_revalidate;
1199         wsi->cache_intermediaries = hit->cache_intermediaries;
1200
1201         n = lws_http_serve(wsi, s, hit->origin, hit);
1202         if (n) {
1203                 /*
1204                  *      lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
1205                  */
1206                 if (hit->protocol) {
1207                         const struct lws_protocols *pp = lws_vhost_name_to_protocol(
1208                                         wsi->vhost, hit->protocol);
1209
1210                         if (lws_bind_protocol(wsi, pp))
1211                                 return 1;
1212
1213                         n = pp->callback(wsi, LWS_CALLBACK_HTTP,
1214                                          wsi->user_space,
1215                                          uri_ptr + hit->mountpoint_len,
1216                                          uri_len - hit->mountpoint_len);
1217                 } else
1218                         n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP,
1219                                     wsi->user_space, uri_ptr, uri_len);
1220         }
1221
1222 after:
1223         if (n) {
1224                 lwsl_info("LWS_CALLBACK_HTTP closing\n");
1225
1226                 return 1;
1227         }
1228
1229 #ifdef LWS_WITH_CGI
1230 deal_body:
1231 #endif
1232         /*
1233          * If we're not issuing a file, check for content_length or
1234          * HTTP keep-alive. No keep-alive header allocation for
1235          * ISSUING_FILE, as this uses HTTP/1.0.
1236          *
1237          * In any case, return 0 and let lws_read decide how to
1238          * proceed based on state
1239          */
1240         if (wsi->state != LWSS_HTTP_ISSUING_FILE)
1241                 /* Prepare to read body if we have a content length: */
1242                 if (wsi->u.http.content_length > 0)
1243                         wsi->state = LWSS_HTTP_BODY;
1244
1245         return 0;
1246
1247 bail_nuke_ah:
1248         /* we're closing, losing some rx is OK */
1249         wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
1250         // lwsl_notice("%s: drop1\n", __func__);
1251         lws_header_table_detach(wsi, 1);
1252
1253         return 1;
1254 #if LWS_POSIX
1255 transaction_result_n:
1256         lws_return_http_status(wsi, n, NULL);
1257
1258         return lws_http_transaction_completed(wsi);
1259 #endif
1260 }
1261
1262 int
1263 lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
1264 {
1265         int protocol_len, n = 0, hit, non_space_char_found = 0, m;
1266         struct lws_context *context = lws_get_context(wsi);
1267         struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
1268         struct _lws_header_related hdr;
1269         struct allocated_headers *ah;
1270         unsigned char *obuf = *buf;
1271         char protocol_list[128];
1272         char protocol_name[64];
1273         size_t olen = len;
1274         char *p;
1275
1276         if (len >= 10000000) {
1277                 lwsl_err("%s: assert: len %ld\n", __func__, (long)len);
1278                 assert(0);
1279         }
1280
1281         if (!wsi->u.hdr.ah) {
1282                 lwsl_err("%s: assert: NULL ah\n", __func__);
1283                 assert(0);
1284         }
1285
1286         while (len--) {
1287                 wsi->more_rx_waiting = !!len;
1288
1289                 if (wsi->mode != LWSCM_HTTP_SERVING &&
1290                     wsi->mode != LWSCM_HTTP_SERVING_ACCEPTED) {
1291                         lwsl_err("%s: bad wsi mode %d\n", __func__, wsi->mode);
1292                         goto bail_nuke_ah;
1293                 }
1294
1295                 m = lws_parse(wsi, *(*buf)++);
1296                 if (m) {
1297                         if (m == 2) {
1298                                 /*
1299                                  * we are transitioning from http with
1300                                  * an AH, to raw.  Drop the ah and set
1301                                  * the mode.
1302                                  */
1303 raw_transition:
1304                                 lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
1305                                 lws_bind_protocol(wsi, &wsi->vhost->protocols[
1306                                                         wsi->vhost->
1307                                                         raw_protocol_index]);
1308                                 lwsl_info("transition to raw vh %s prot %d\n",
1309                                           wsi->vhost->name,
1310                                           wsi->vhost->raw_protocol_index);
1311                                 if ((wsi->protocol->callback)(wsi,
1312                                                 LWS_CALLBACK_RAW_ADOPT,
1313                                                 wsi->user_space, NULL, 0))
1314                                         goto bail_nuke_ah;
1315
1316                                 wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
1317                                 lws_union_transition(wsi, LWSCM_RAW);
1318                                 lws_header_table_detach(wsi, 1);
1319
1320                                 if (m == 2 && (wsi->protocol->callback)(wsi,
1321                                                 LWS_CALLBACK_RAW_RX,
1322                                                 wsi->user_space, obuf, olen))
1323                                         return 1;
1324
1325                                 return 0;
1326                         }
1327                         lwsl_info("lws_parse failed\n");
1328                         goto bail_nuke_ah;
1329                 }
1330
1331                 if (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE)
1332                         continue;
1333
1334                 lwsl_parser("%s: lws_parse sees parsing complete\n", __func__);
1335                 lwsl_debug("%s: wsi->more_rx_waiting=%d\n", __func__,
1336                                 wsi->more_rx_waiting);
1337
1338                 /* check for unwelcome guests */
1339
1340                 if (wsi->context->reject_service_keywords) {
1341                         const struct lws_protocol_vhost_options *rej =
1342                                         wsi->context->reject_service_keywords;
1343                         char ua[384], *msg = NULL;
1344
1345                         if (lws_hdr_copy(wsi, ua, sizeof(ua) - 1,
1346                                           WSI_TOKEN_HTTP_USER_AGENT) > 0) {
1347                                 ua[sizeof(ua) - 1] = '\0';
1348                                 while (rej) {
1349                                         if (strstr(ua, rej->name)) {
1350                                                 msg = strchr(rej->value, ' ');
1351                                                 if (msg)
1352                                                         msg++;
1353                                                 lws_return_http_status(wsi, atoi(rej->value), msg);
1354
1355                                                 wsi->vhost->conn_stats.rejected++;
1356
1357                                                 goto bail_nuke_ah;
1358                                         }
1359                                         rej = rej->next;
1360                                 }
1361                         }
1362                 }
1363
1364                 /* select vhost */
1365
1366                 if (lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {
1367                         struct lws_vhost *vhost = lws_select_vhost(
1368                                 context, wsi->vhost->listen_port,
1369                                 lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));
1370
1371                         if (vhost)
1372                                 wsi->vhost = vhost;
1373                 } else
1374                         lwsl_info("no host\n");
1375
1376                 wsi->vhost->conn_stats.trans++;
1377                 if (!wsi->conn_stat_done) {
1378                         wsi->vhost->conn_stats.conn++;
1379                         wsi->conn_stat_done = 1;
1380                 }
1381
1382                 if (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECT)) {
1383                         lwsl_info("Changing to RAW mode\n");
1384                         m = 0;
1385                         goto raw_transition;
1386                 }
1387
1388                 wsi->mode = LWSCM_PRE_WS_SERVING_ACCEPT;
1389                 lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
1390
1391                 /* is this websocket protocol or normal http 1.0? */
1392
1393                 if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {
1394                         if (!strcasecmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE),
1395                                         "websocket")) {
1396                                 wsi->vhost->conn_stats.ws_upg++;
1397                                 lwsl_info("Upgrade to ws\n");
1398                                 goto upgrade_ws;
1399                         }
1400 #ifdef LWS_USE_HTTP2
1401                         if (!strcasecmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE),
1402                                         "h2c")) {
1403                                 wsi->vhost->conn_stats.http2_upg++;
1404                                 lwsl_info("Upgrade to h2c\n");
1405                                 goto upgrade_h2c;
1406                         }
1407 #endif
1408                         lwsl_info("Unknown upgrade\n");
1409                         /* dunno what he wanted to upgrade to */
1410                         goto bail_nuke_ah;
1411                 }
1412
1413                 /* no upgrade ack... he remained as HTTP */
1414
1415                 lwsl_info("No upgrade\n");
1416                 ah = wsi->u.hdr.ah;
1417
1418                 lws_union_transition(wsi, LWSCM_HTTP_SERVING_ACCEPTED);
1419                 wsi->state = LWSS_HTTP;
1420                 wsi->u.http.fop_fd = NULL;
1421
1422                 /* expose it at the same offset as u.hdr */
1423                 wsi->u.http.ah = ah;
1424                 lwsl_debug("%s: wsi %p: ah %p\n", __func__, (void *)wsi,
1425                            (void *)wsi->u.hdr.ah);
1426
1427                 n = lws_http_action(wsi);
1428
1429                 return n;
1430
1431 #ifdef LWS_USE_HTTP2
1432 upgrade_h2c:
1433                 if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP2_SETTINGS)) {
1434                         lwsl_info("missing http2_settings\n");
1435                         goto bail_nuke_ah;
1436                 }
1437
1438                 lwsl_info("h2c upgrade...\n");
1439
1440                 p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP2_SETTINGS);
1441                 /* convert the peer's HTTP-Settings */
1442                 n = lws_b64_decode_string(p, protocol_list,
1443                                           sizeof(protocol_list));
1444                 if (n < 0) {
1445                         lwsl_parser("HTTP2_SETTINGS too long\n");
1446                         return 1;
1447                 }
1448
1449                 /* adopt the header info */
1450
1451                 ah = wsi->u.hdr.ah;
1452
1453                 lws_union_transition(wsi, LWSCM_HTTP2_SERVING);
1454
1455                 /* http2 union member has http union struct at start */
1456                 wsi->u.http.ah = ah;
1457
1458                 lws_http2_init(&wsi->u.http2.peer_settings);
1459                 lws_http2_init(&wsi->u.http2.my_settings);
1460
1461                 /* HTTP2 union */
1462
1463                 lws_http2_interpret_settings_payload(&wsi->u.http2.peer_settings,
1464                                 (unsigned char *)protocol_list, n);
1465
1466                 strcpy(protocol_list,
1467                        "HTTP/1.1 101 Switching Protocols\x0d\x0a"
1468                       "Connection: Upgrade\x0d\x0a"
1469                       "Upgrade: h2c\x0d\x0a\x0d\x0a");
1470                 n = lws_issue_raw(wsi, (unsigned char *)protocol_list,
1471                                         strlen(protocol_list));
1472                 if (n != strlen(protocol_list)) {
1473                         lwsl_debug("http2 switch: ERROR writing to socket\n");
1474                         return 1;
1475                 }
1476
1477                 wsi->state = LWSS_HTTP2_AWAIT_CLIENT_PREFACE;
1478
1479                 return 0;
1480 #endif
1481
1482 upgrade_ws:
1483                 if (!wsi->protocol)
1484                         lwsl_err("NULL protocol at lws_read\n");
1485
1486                 /*
1487                  * It's websocket
1488                  *
1489                  * Select the first protocol we support from the list
1490                  * the client sent us.
1491                  *
1492                  * Copy it to remove header fragmentation
1493                  */
1494
1495                 if (lws_hdr_copy(wsi, protocol_list, sizeof(protocol_list) - 1,
1496                                  WSI_TOKEN_PROTOCOL) < 0) {
1497                         lwsl_err("protocol list too long");
1498                         goto bail_nuke_ah;
1499                 }
1500
1501                 protocol_len = lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL);
1502                 protocol_list[protocol_len] = '\0';
1503                 p = protocol_list;
1504                 hit = 0;
1505
1506                 while (*p && !hit) {
1507                         n = 0;
1508                         non_space_char_found = 0;
1509                         while (n < sizeof(protocol_name) - 1 && *p &&
1510                                *p != ',') {
1511                                 // ignore leading spaces
1512                                 if (!non_space_char_found && *p == ' ') {
1513                                         n++;
1514                                         continue;
1515                                 }
1516                                 non_space_char_found = 1;
1517                                 protocol_name[n++] = *p++;
1518                         }
1519                         protocol_name[n] = '\0';
1520                         if (*p)
1521                                 p++;
1522
1523                         lwsl_info("checking %s\n", protocol_name);
1524
1525                         n = 0;
1526                         while (wsi->vhost->protocols[n].callback) {
1527                                 lwsl_info("try %s\n", wsi->vhost->protocols[n].name);
1528
1529                                 if (wsi->vhost->protocols[n].name &&
1530                                     !strcmp(wsi->vhost->protocols[n].name,
1531                                             protocol_name)) {
1532                                         wsi->protocol = &wsi->vhost->protocols[n];
1533                                         hit = 1;
1534                                         break;
1535                                 }
1536
1537                                 n++;
1538                         }
1539                 }
1540
1541                 /* we didn't find a protocol he wanted? */
1542
1543                 if (!hit) {
1544                         if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL)) {
1545                                 lwsl_info("No protocol from \"%s\" supported\n",
1546                                          protocol_list);
1547                                 goto bail_nuke_ah;
1548                         }
1549                         /*
1550                          * some clients only have one protocol and
1551                          * do not send the protocol list header...
1552                          * allow it and match to the vhost's default
1553                          * protocol (which itself defaults to zero)
1554                          */
1555                         lwsl_info("defaulting to prot handler %d\n",
1556                                 wsi->vhost->default_protocol_index);
1557                         n = wsi->vhost->default_protocol_index;
1558                         wsi->protocol = &wsi->vhost->protocols[
1559                                       (int)wsi->vhost->default_protocol_index];
1560                 }
1561
1562                 /* allocate wsi->user storage */
1563                 if (lws_ensure_user_space(wsi))
1564                         goto bail_nuke_ah;
1565
1566                 /*
1567                  * Give the user code a chance to study the request and
1568                  * have the opportunity to deny it
1569                  */
1570                 if ((wsi->protocol->callback)(wsi,
1571                                 LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,
1572                                 wsi->user_space,
1573                               lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL), 0)) {
1574                         lwsl_warn("User code denied connection\n");
1575                         goto bail_nuke_ah;
1576                 }
1577
1578                 /*
1579                  * Perform the handshake according to the protocol version the
1580                  * client announced
1581                  */
1582
1583                 switch (wsi->ietf_spec_revision) {
1584                 case 13:
1585                         lwsl_parser("lws_parse calling handshake_04\n");
1586                         if (handshake_0405(context, wsi)) {
1587                                 lwsl_info("hs0405 has failed the connection\n");
1588                                 goto bail_nuke_ah;
1589                         }
1590                         break;
1591
1592                 default:
1593                         lwsl_info("Unknown client spec version %d\n",
1594                                   wsi->ietf_spec_revision);
1595                         goto bail_nuke_ah;
1596                 }
1597
1598                 lws_same_vh_protocol_insert(wsi, n);
1599
1600                 /* we are upgrading to ws, so http/1.1 and keepalive +
1601                  * pipelined header considerations about keeping the ah around
1602                  * no longer apply.  However it's common for the first ws
1603                  * protocol data to have been coalesced with the browser
1604                  * upgrade request and to already be in the ah rx buffer.
1605                  */
1606
1607                 lwsl_info("%s: %p: inheriting ah in ws mode (rxpos:%d, rxlen:%d)\n",
1608                           __func__, wsi, wsi->u.hdr.ah->rxpos,
1609                           wsi->u.hdr.ah->rxlen);
1610                 lws_pt_lock(pt);
1611                 hdr = wsi->u.hdr;
1612
1613                 lws_union_transition(wsi, LWSCM_WS_SERVING);
1614                 /*
1615                  * first service is WS mode will notice this, use the RX and
1616                  * then detach the ah (caution: we are not in u.hdr union
1617                  * mode any more then... ah_temp member is at start the same
1618                  * though)
1619                  *
1620                  * Because rxpos/rxlen shows something in the ah, we will get
1621                  * service guaranteed next time around the event loop
1622                  *
1623                  * All union members begin with hdr, so we can use it even
1624                  * though we transitioned to ws union mode (the ah detach
1625                  * code uses it anyway).
1626                  */
1627                 wsi->u.hdr = hdr;
1628                 lws_pt_unlock(pt);
1629
1630                 lws_restart_ws_ping_pong_timer(wsi);
1631
1632                 /*
1633                  * create the frame buffer for this connection according to the
1634                  * size mentioned in the protocol definition.  If 0 there, use
1635                  * a big default for compatibility
1636                  */
1637
1638                 n = wsi->protocol->rx_buffer_size;
1639                 if (!n)
1640                         n = context->pt_serv_buf_size;
1641                 n += LWS_PRE;
1642                 wsi->u.ws.rx_ubuf = lws_malloc(n + 4 /* 0x0000ffff zlib */);
1643                 if (!wsi->u.ws.rx_ubuf) {
1644                         lwsl_err("Out of Mem allocating rx buffer %d\n", n);
1645                         return 1;
1646                 }
1647                 wsi->u.ws.rx_ubuf_alloc = n;
1648                 lwsl_debug("Allocating RX buffer %d\n", n);
1649 #if LWS_POSIX && !defined(LWS_WITH_ESP32)
1650                 if (setsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_SNDBUF,
1651                                (const char *)&n, sizeof n)) {
1652                         lwsl_warn("Failed to set SNDBUF to %d", n);
1653                         return 1;
1654                 }
1655 #endif
1656
1657                 lwsl_parser("accepted v%02d connection\n",
1658                             wsi->ietf_spec_revision);
1659
1660                 /* notify user code that we're ready to roll */
1661
1662                 if (wsi->protocol->callback)
1663                         if (wsi->protocol->callback(wsi, LWS_CALLBACK_ESTABLISHED,
1664                                                     wsi->user_space,
1665 #ifdef LWS_OPENSSL_SUPPORT
1666                                                     wsi->ssl,
1667 #else
1668                                                     NULL,
1669 #endif
1670                                                     0))
1671                                 return 1;
1672
1673                 /* !!! drop ah unreservedly after ESTABLISHED */
1674                 if (!wsi->more_rx_waiting) {
1675                         wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
1676
1677                         //lwsl_notice("%p: dropping ah EST\n", wsi);
1678                         lws_header_table_detach(wsi, 1);
1679                 }
1680
1681                 return 0;
1682         } /* while all chars are handled */
1683
1684         return 0;
1685
1686 bail_nuke_ah:
1687         /* drop the header info */
1688         /* we're closing, losing some rx is OK */
1689         wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
1690         //lwsl_notice("%s: drop2\n", __func__);
1691         lws_header_table_detach(wsi, 1);
1692
1693         return 1;
1694 }
1695
1696 static int
1697 lws_get_idlest_tsi(struct lws_context *context)
1698 {
1699         unsigned int lowest = ~0;
1700         int n = 0, hit = -1;
1701
1702         for (; n < context->count_threads; n++) {
1703                 if ((unsigned int)context->pt[n].fds_count !=
1704                     context->fd_limit_per_thread - 1 &&
1705                     (unsigned int)context->pt[n].fds_count < lowest) {
1706                         lowest = context->pt[n].fds_count;
1707                         hit = n;
1708                 }
1709         }
1710
1711         return hit;
1712 }
1713
1714 struct lws *
1715 lws_create_new_server_wsi(struct lws_vhost *vhost)
1716 {
1717         struct lws *new_wsi;
1718         int n = lws_get_idlest_tsi(vhost->context);
1719
1720         if (n < 0) {
1721                 lwsl_err("no space for new conn\n");
1722                 return NULL;
1723         }
1724
1725         new_wsi = lws_zalloc(sizeof(struct lws));
1726         if (new_wsi == NULL) {
1727                 lwsl_err("Out of memory for new connection\n");
1728                 return NULL;
1729         }
1730
1731         new_wsi->tsi = n;
1732         lwsl_debug("Accepted wsi %p to context %p, tsi %d\n", new_wsi,
1733                     vhost->context, new_wsi->tsi);
1734
1735         new_wsi->vhost = vhost;
1736         new_wsi->context = vhost->context;
1737         new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
1738         new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
1739
1740         /* initialize the instance struct */
1741
1742         new_wsi->state = LWSS_HTTP;
1743         new_wsi->mode = LWSCM_HTTP_SERVING;
1744         new_wsi->hdr_parsing_completed = 0;
1745
1746 #ifdef LWS_OPENSSL_SUPPORT
1747         new_wsi->use_ssl = LWS_SSL_ENABLED(vhost);
1748 #endif
1749
1750         /*
1751          * these can only be set once the protocol is known
1752          * we set an unestablished connection's protocol pointer
1753          * to the start of the supported list, so it can look
1754          * for matching ones during the handshake
1755          */
1756         new_wsi->protocol = vhost->protocols;
1757         new_wsi->user_space = NULL;
1758         new_wsi->ietf_spec_revision = 0;
1759         new_wsi->desc.sockfd = LWS_SOCK_INVALID;
1760         vhost->context->count_wsi_allocated++;
1761
1762         /*
1763          * outermost create notification for wsi
1764          * no user_space because no protocol selection
1765          */
1766         vhost->protocols[0].callback(new_wsi, LWS_CALLBACK_WSI_CREATE,
1767                                        NULL, NULL, 0);
1768
1769         return new_wsi;
1770 }
1771
1772 LWS_VISIBLE int LWS_WARN_UNUSED_RESULT
1773 lws_http_transaction_completed(struct lws *wsi)
1774 {
1775         int n = NO_PENDING_TIMEOUT;
1776
1777         lws_access_log(wsi);
1778
1779         lwsl_info("%s: wsi %p\n", __func__, wsi);
1780         /* if we can't go back to accept new headers, drop the connection */
1781         if (wsi->u.http.connection_type != HTTP_CONNECTION_KEEP_ALIVE) {
1782                 lwsl_info("%s: %p: close connection\n", __func__, wsi);
1783                 return 1;
1784         }
1785
1786         if (lws_bind_protocol(wsi, &wsi->vhost->protocols[0]))
1787                 return 1;
1788
1789         /* otherwise set ourselves up ready to go again */
1790         wsi->state = LWSS_HTTP;
1791         wsi->mode = LWSCM_HTTP_SERVING;
1792         wsi->u.http.content_length = 0;
1793         wsi->u.http.content_remain = 0;
1794         wsi->hdr_parsing_completed = 0;
1795 #ifdef LWS_WITH_ACCESS_LOG
1796         wsi->access_log.sent = 0;
1797 #endif
1798
1799         if (wsi->vhost->keepalive_timeout)
1800                 n = PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE;
1801         lws_set_timeout(wsi, n, wsi->vhost->keepalive_timeout);
1802
1803         /*
1804          * We already know we are on http1.1 / keepalive and the next thing
1805          * coming will be another header set.
1806          *
1807          * If there is no pending rx and we still have the ah, drop it and
1808          * reacquire a new ah when the new headers start to arrive.  (Otherwise
1809          * we needlessly hog an ah indefinitely.)
1810          *
1811          * However if there is pending rx and we know from the keepalive state
1812          * that is already at least the start of another header set, simply
1813          * reset the existing header table and keep it.
1814          */
1815         if (wsi->u.hdr.ah) {
1816                 lwsl_info("%s: wsi->more_rx_waiting=%d\n", __func__,
1817                                 wsi->more_rx_waiting);
1818
1819                 if (!wsi->more_rx_waiting) {
1820                         wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
1821                         lws_header_table_detach(wsi, 1);
1822 #ifdef LWS_OPENSSL_SUPPORT
1823                         /*
1824                          * additionally... if we are hogging an SSL instance
1825                          * with no pending pipelined headers (or ah now), and
1826                          * SSL is scarce, drop this connection without waiting
1827                          */
1828
1829                         if (wsi->vhost->use_ssl &&
1830                             wsi->context->simultaneous_ssl_restriction &&
1831                             wsi->context->simultaneous_ssl ==
1832                                    wsi->context->simultaneous_ssl_restriction) {
1833                                 lwsl_info("%s: simultaneous_ssl_restriction and nothing pipelined\n", __func__);
1834                                 return 1;
1835                         }
1836 #endif
1837                 } else
1838                         lws_header_table_reset(wsi, 1);
1839         }
1840
1841         /* If we're (re)starting on headers, need other implied init */
1842         wsi->u.hdr.ues = URIES_IDLE;
1843
1844         lwsl_info("%s: %p: keep-alive await new transaction\n", __func__, wsi);
1845
1846         return 0;
1847 }
1848
1849 /* if not a socket, it's a raw, non-ssl file descriptor */
1850
1851 LWS_VISIBLE struct lws *
1852 lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
1853                            lws_sock_file_fd_type fd, const char *vh_prot_name,
1854                            struct lws *parent)
1855 {
1856         struct lws_context *context = vh->context;
1857         struct lws *new_wsi = lws_create_new_server_wsi(vh);
1858         struct lws_context_per_thread *pt;
1859         int n, ssl = 0;
1860
1861         if (!new_wsi) {
1862                 if (type & LWS_ADOPT_SOCKET)
1863                         compatible_close(fd.sockfd);
1864                 return NULL;
1865         }
1866         pt = &context->pt[(int)new_wsi->tsi];
1867         lws_stats_atomic_bump(context, pt, LWSSTATS_C_CONNECTIONS, 1);
1868
1869         if (parent) {
1870                 new_wsi->parent = parent;
1871                 new_wsi->sibling_list = parent->child_list;
1872                 parent->child_list = new_wsi;
1873         }
1874
1875         new_wsi->desc = fd;
1876
1877         if (vh_prot_name) {
1878                 new_wsi->protocol = lws_vhost_name_to_protocol(new_wsi->vhost,
1879                                                                vh_prot_name);
1880                 if (!new_wsi->protocol) {
1881                         lwsl_err("Protocol %s not enabled on vhost %s\n",
1882                                  vh_prot_name, new_wsi->vhost->name);
1883                         goto bail;
1884                 }
1885                if (lws_ensure_user_space(new_wsi)) {
1886                        lwsl_notice("OOM trying to get user_space\n");
1887                         goto bail;
1888                }
1889         } else
1890                 if (type & LWS_ADOPT_HTTP) /* he will transition later */
1891                         new_wsi->protocol =
1892                                 &vh->protocols[vh->default_protocol_index];
1893                 else { /* this is the only time he will transition */
1894                         lws_bind_protocol(new_wsi,
1895                                 &vh->protocols[vh->raw_protocol_index]);
1896                         lws_union_transition(new_wsi, LWSCM_RAW);
1897                 }
1898
1899         if (type & LWS_ADOPT_SOCKET) { /* socket desc */
1900                 lwsl_debug("%s: new wsi %p, sockfd %d\n", __func__, new_wsi,
1901                            (int)(size_t)fd.sockfd);
1902
1903                 if (type & LWS_ADOPT_HTTP)
1904                         /* the transport is accepted...
1905                          * give him time to negotiate */
1906                         lws_set_timeout(new_wsi,
1907                                         PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
1908                                         context->timeout_secs);
1909
1910 #if LWS_POSIX == 0
1911 #if defined(LWS_WITH_ESP8266)
1912                 esp8266_tcp_stream_accept(accept_fd, new_wsi);
1913 #endif
1914 #endif
1915         } else /* file desc */
1916                 lwsl_debug("%s: new wsi %p, filefd %d\n", __func__, new_wsi,
1917                            (int)(size_t)fd.filefd);
1918
1919         /*
1920          * A new connection was accepted. Give the user a chance to
1921          * set properties of the newly created wsi. There's no protocol
1922          * selected yet so we issue this to the vhosts's default protocol,
1923          * itself by default protocols[0]
1924          */
1925         n = LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED;
1926         if (!(type & LWS_ADOPT_HTTP)) {
1927                 if (!(type & LWS_ADOPT_SOCKET))
1928                         n = LWS_CALLBACK_RAW_ADOPT_FILE;
1929                 else
1930                         n = LWS_CALLBACK_RAW_ADOPT;
1931         }
1932
1933         if (!LWS_SSL_ENABLED(new_wsi->vhost) || !(type & LWS_ADOPT_ALLOW_SSL) ||
1934             !(type & LWS_ADOPT_SOCKET)) {
1935                 /* non-SSL */
1936                 if (!(type & LWS_ADOPT_HTTP)) {
1937                         if (!(type & LWS_ADOPT_SOCKET))
1938                                 new_wsi->mode = LWSCM_RAW_FILEDESC;
1939                         else
1940                                 new_wsi->mode = LWSCM_RAW;
1941                 }
1942         } else {
1943                 /* SSL */
1944                 if (!(type & LWS_ADOPT_HTTP))
1945                         new_wsi->mode = LWSCM_SSL_INIT_RAW;
1946                 else
1947                         new_wsi->mode = LWSCM_SSL_INIT;
1948
1949                 ssl = 1;
1950         }
1951
1952         lws_libev_accept(new_wsi, new_wsi->desc);
1953         lws_libuv_accept(new_wsi, new_wsi->desc);
1954         lws_libevent_accept(new_wsi, new_wsi->desc);
1955
1956         if (!ssl) {
1957                 if (insert_wsi_socket_into_fds(context, new_wsi)) {
1958                         lwsl_err("%s: fail inserting socket\n", __func__);
1959                         goto fail;
1960                 }
1961         } else
1962                 if (lws_server_socket_service_ssl(new_wsi, fd.sockfd)) {
1963                         lwsl_err("%s: fail ssl negotiation\n", __func__);
1964                         goto fail;
1965                 }
1966
1967         /*
1968          *  by deferring callback to this point, after insertion to fds,
1969          * lws_callback_on_writable() can work from the callback
1970          */
1971         if ((new_wsi->protocol->callback)(
1972                         new_wsi, n, new_wsi->user_space, NULL, 0))
1973                 goto fail;
1974
1975         if (type & LWS_ADOPT_HTTP) {
1976                 if (!lws_header_table_attach(new_wsi, 0)) {
1977                         lwsl_debug("Attached ah immediately\n");
1978                 } else {
1979                         lwsl_notice("%s: waiting for ah\n", __func__);
1980                 }
1981         }
1982
1983         return new_wsi;
1984
1985 fail:
1986         if (type & LWS_ADOPT_SOCKET)
1987                 lws_close_free_wsi(new_wsi, LWS_CLOSE_STATUS_NOSTATUS);
1988
1989         return NULL;
1990
1991 bail:
1992        lwsl_notice("%s: exiting on bail\n", __func__);
1993         if (parent)
1994                 parent->child_list = new_wsi->sibling_list;
1995         if (new_wsi->user_space)
1996                 lws_free(new_wsi->user_space);
1997         lws_free(new_wsi);
1998        compatible_close(fd.sockfd);
1999
2000         return NULL;
2001 }
2002
2003 LWS_VISIBLE struct lws *
2004 lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)
2005 {
2006         lws_sock_file_fd_type fd;
2007
2008         fd.sockfd = accept_fd;
2009         return lws_adopt_descriptor_vhost(vh, LWS_ADOPT_SOCKET |
2010                         LWS_ADOPT_HTTP | LWS_ADOPT_ALLOW_SSL, fd, NULL, NULL);
2011 }
2012
2013 LWS_VISIBLE struct lws *
2014 lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd)
2015 {
2016         return lws_adopt_socket_vhost(context->vhost_list, accept_fd);
2017 }
2018
2019 /* Common read-buffer adoption for lws_adopt_*_readbuf */
2020 static struct lws*
2021 adopt_socket_readbuf(struct lws *wsi, const char *readbuf, size_t len)
2022 {
2023         struct lws_context_per_thread *pt;
2024         struct allocated_headers *ah;
2025         struct lws_pollfd *pfd;
2026
2027         if (!wsi)
2028                 return NULL;
2029
2030         if (!readbuf || len == 0)
2031                 return wsi;
2032
2033         if (len > sizeof(ah->rx)) {
2034                 lwsl_err("%s: rx in too big\n", __func__);
2035                 goto bail;
2036         }
2037
2038         /*
2039          * we can't process the initial read data until we can attach an ah.
2040          *
2041          * if one is available, get it and place the data in his ah rxbuf...
2042          * wsi with ah that have pending rxbuf get auto-POLLIN service.
2043          *
2044          * no autoservice because we didn't get a chance to attach the
2045          * readbuf data to wsi or ah yet, and we will do it next if we get
2046          * the ah.
2047          */
2048         if (wsi->u.hdr.ah || !lws_header_table_attach(wsi, 0)) {
2049                 ah = wsi->u.hdr.ah;
2050                 memcpy(ah->rx, readbuf, len);
2051                 ah->rxpos = 0;
2052                 ah->rxlen = len;
2053
2054                 lwsl_notice("%s: calling service on readbuf ah\n", __func__);
2055                 pt = &wsi->context->pt[(int)wsi->tsi];
2056
2057                 /* unlike a normal connect, we have the headers already
2058                  * (or the first part of them anyway).
2059                  * libuv won't come back and service us without a network
2060                  * event, so we need to do the header service right here.
2061                  */
2062                 pfd = &pt->fds[wsi->position_in_fds_table];
2063                 pfd->revents |= LWS_POLLIN;
2064                 lwsl_err("%s: calling service\n", __func__);
2065                 if (lws_service_fd_tsi(wsi->context, pfd, wsi->tsi))
2066                         /* service closed us */
2067                         return NULL;
2068
2069                 return wsi;
2070         }
2071         lwsl_err("%s: deferring handling ah\n", __func__);
2072         /*
2073          * hum if no ah came, we are on the wait list and must defer
2074          * dealing with this until the ah arrives.
2075          *
2076          * later successful lws_header_table_attach() will apply the
2077          * below to the rx buffer (via lws_header_table_reset()).
2078          */
2079         wsi->u.hdr.preamble_rx = lws_malloc(len);
2080         if (!wsi->u.hdr.preamble_rx) {
2081                 lwsl_err("OOM\n");
2082                 goto bail;
2083         }
2084         memcpy(wsi->u.hdr.preamble_rx, readbuf, len);
2085         wsi->u.hdr.preamble_rx_len = len;
2086
2087         return wsi;
2088
2089 bail:
2090         lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
2091
2092         return NULL;
2093 }
2094
2095 LWS_VISIBLE struct lws *
2096 lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,
2097                          const char *readbuf, size_t len)
2098 {
2099         return adopt_socket_readbuf(lws_adopt_socket(context, accept_fd), readbuf, len);
2100 }
2101
2102 LWS_VISIBLE struct lws *
2103 lws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost, lws_sockfd_type accept_fd,
2104                          const char *readbuf, size_t len)
2105 {
2106         return adopt_socket_readbuf(lws_adopt_socket_vhost(vhost, accept_fd), readbuf, len);
2107 }
2108
2109 LWS_VISIBLE int
2110 lws_server_socket_service(struct lws_context *context, struct lws *wsi,
2111                           struct lws_pollfd *pollfd)
2112 {
2113         struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
2114         lws_sockfd_type accept_fd = LWS_SOCK_INVALID;
2115         struct allocated_headers *ah;
2116         lws_sock_file_fd_type fd;
2117         int opts = LWS_ADOPT_SOCKET | LWS_ADOPT_ALLOW_SSL;
2118 #if LWS_POSIX
2119         struct sockaddr_storage cli_addr;
2120         socklen_t clilen;
2121 #endif
2122         int n, len;
2123         
2124         // lwsl_notice("%s: mode %d\n", __func__, wsi->mode);
2125
2126         switch (wsi->mode) {
2127
2128         case LWSCM_HTTP_SERVING:
2129         case LWSCM_HTTP_SERVING_ACCEPTED:
2130         case LWSCM_HTTP2_SERVING:
2131         case LWSCM_RAW:
2132
2133                 /* handle http headers coming in */
2134
2135                 /* pending truncated sends have uber priority */
2136
2137                 if (wsi->trunc_len) {
2138                         if (!(pollfd->revents & LWS_POLLOUT))
2139                                 break;
2140
2141                         if (lws_issue_raw(wsi, wsi->trunc_alloc +
2142                                                wsi->trunc_offset,
2143                                           wsi->trunc_len) < 0)
2144                                 goto fail;
2145                         /*
2146                          * we can't afford to allow input processing to send
2147                          * something new, so spin around he event loop until
2148                          * he doesn't have any partials
2149                          */
2150                         break;
2151                 }
2152
2153                 /* any incoming data ready? */
2154
2155                 if (!(pollfd->revents & pollfd->events & LWS_POLLIN))
2156                         goto try_pollout;
2157
2158                 /*
2159                  * If we previously just did POLLIN when IN and OUT were
2160                  * signalled (because POLLIN processing may have used up
2161                  * the POLLOUT), don't let that happen twice in a row...
2162                  * next time we see the situation favour POLLOUT
2163                  */
2164 #if !defined(LWS_WITH_ESP8266)
2165                 if (wsi->favoured_pollin &&
2166                     (pollfd->revents & pollfd->events & LWS_POLLOUT)) {
2167                         wsi->favoured_pollin = 0;
2168                         goto try_pollout;
2169                 }
2170 #endif
2171
2172                 /* these states imply we MUST have an ah attached */
2173
2174                 if (wsi->mode != LWSCM_RAW && (wsi->state == LWSS_HTTP ||
2175                     wsi->state == LWSS_HTTP_ISSUING_FILE ||
2176                     wsi->state == LWSS_HTTP_HEADERS)) {
2177                         if (!wsi->u.hdr.ah) {
2178                                 
2179                                 //lwsl_err("wsi %p: missing ah\n", wsi);
2180                                 /* no autoservice beacuse we will do it next */
2181                                 if (lws_header_table_attach(wsi, 0)) {
2182                                         lwsl_info("wsi %p: failed to acquire ah\n", wsi);
2183                                         goto try_pollout;
2184                                 }
2185                         }
2186                         ah = wsi->u.hdr.ah;
2187
2188                         //lwsl_notice("%s: %p: rxpos:%d rxlen:%d\n", __func__, wsi,
2189                         //         ah->rxpos, ah->rxlen);
2190
2191                         /* if nothing in ah rx buffer, get some fresh rx */
2192                         if (ah->rxpos == ah->rxlen) {
2193                                 ah->rxlen = lws_ssl_capable_read(wsi, ah->rx,
2194                                                    sizeof(ah->rx));
2195                                 ah->rxpos = 0;
2196                                 //lwsl_notice("%s: wsi %p, ah->rxlen = %d\r\n",
2197                                 //         __func__, wsi, ah->rxlen);
2198                                 switch (ah->rxlen) {
2199                                 case 0:
2200                                         lwsl_info("%s: read 0 len\n", __func__);
2201                                         /* lwsl_info("   state=%d\n", wsi->state); */
2202 //                                      if (!wsi->hdr_parsing_completed)
2203 //                                              lws_header_table_detach(wsi);
2204                                         /* fallthru */
2205                                 case LWS_SSL_CAPABLE_ERROR:
2206                                         goto fail;
2207                                 case LWS_SSL_CAPABLE_MORE_SERVICE:
2208                                         ah->rxlen = ah->rxpos = 0;
2209                                         goto try_pollout;
2210                                 }
2211                         }
2212
2213                         if (!(ah->rxpos != ah->rxlen && ah->rxlen)) {
2214                                 lwsl_err("%s: assert: rxpos %d, rxlen %d\n",
2215                                          __func__, ah->rxpos, ah->rxlen);
2216
2217                                 assert(0);
2218                         }
2219                         
2220                         /* just ignore incoming if waiting for close */
2221                         if (wsi->state != LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
2222                                 n = lws_read(wsi, ah->rx + ah->rxpos,
2223                                              ah->rxlen - ah->rxpos);
2224                                 if (n < 0) /* we closed wsi */
2225                                         return 1;
2226                                 if (wsi->u.hdr.ah) {
2227                                         if ( wsi->u.hdr.ah->rxlen)
2228                                                  wsi->u.hdr.ah->rxpos += n;
2229
2230                                         lwsl_debug("%s: wsi %p: ah read rxpos %d, rxlen %d\n", __func__, wsi, wsi->u.hdr.ah->rxpos, wsi->u.hdr.ah->rxlen);
2231
2232                                         if (wsi->u.hdr.ah->rxpos == wsi->u.hdr.ah->rxlen &&
2233                                             (wsi->mode != LWSCM_HTTP_SERVING &&
2234                                              wsi->mode != LWSCM_HTTP_SERVING_ACCEPTED &&
2235                                              wsi->mode != LWSCM_HTTP2_SERVING))
2236                                                 lws_header_table_detach(wsi, 1);
2237                                 }
2238                                 break;
2239                         }
2240
2241                         goto try_pollout;
2242                 }
2243
2244                 len = lws_ssl_capable_read(wsi, pt->serv_buf,
2245                                            context->pt_serv_buf_size);
2246                 lwsl_debug("%s: wsi %p read %d\r\n", __func__, wsi, len);
2247                 switch (len) {
2248                 case 0:
2249                         lwsl_info("%s: read 0 len\n", __func__);
2250                         /* lwsl_info("   state=%d\n", wsi->state); */
2251 //                      if (!wsi->hdr_parsing_completed)
2252 //                              lws_header_table_detach(wsi);
2253                         /* fallthru */
2254                 case LWS_SSL_CAPABLE_ERROR:
2255                         goto fail;
2256                 case LWS_SSL_CAPABLE_MORE_SERVICE:
2257                         goto try_pollout;
2258                 }
2259                 
2260                 if (wsi->mode == LWSCM_RAW) {
2261                         n = user_callback_handle_rxflow(wsi->protocol->callback,
2262                                         wsi, LWS_CALLBACK_RAW_RX,
2263                                         wsi->user_space, pt->serv_buf, len);
2264                         if (n < 0) {
2265                                 lwsl_info("LWS_CALLBACK_RAW_RX_fail\n");
2266                                 goto fail;
2267                         }
2268                         goto try_pollout;
2269                 }
2270
2271                 /* just ignore incoming if waiting for close */
2272                 if (wsi->state != LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
2273                         /*
2274                          * this may want to send
2275                          * (via HTTP callback for example)
2276                          */
2277                         n = lws_read(wsi, pt->serv_buf, len);
2278                         if (n < 0) /* we closed wsi */
2279                                 return 1;
2280                         /*
2281                          *  he may have used up the
2282                          * writability above, if we will defer POLLOUT
2283                          * processing in favour of POLLIN, note it
2284                          */
2285                         if (pollfd->revents & LWS_POLLOUT)
2286                                 wsi->favoured_pollin = 1;
2287                         break;
2288                 }
2289
2290 try_pollout:
2291                 
2292                 /* this handles POLLOUT for http serving fragments */
2293
2294                 if (!(pollfd->revents & LWS_POLLOUT))
2295                         break;
2296
2297                 /* one shot */
2298                 if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
2299                         lwsl_notice("%s a\n", __func__);
2300                         goto fail;
2301                 }
2302
2303                 if (wsi->mode == LWSCM_RAW) {
2304                         lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB, 1);
2305 #if defined(LWS_WITH_STATS)
2306                         {
2307                                 uint64_t ul = time_in_microseconds() - wsi->active_writable_req_us;
2308
2309                                 lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_WRITABLE_DELAY, ul);
2310                                 lws_stats_atomic_max(wsi->context, pt, LWSSTATS_MS_WORST_WRITABLE_DELAY, ul);
2311                                 wsi->active_writable_req_us = 0;
2312                         }
2313 #endif
2314                         n = user_callback_handle_rxflow(wsi->protocol->callback,
2315                                         wsi, LWS_CALLBACK_RAW_WRITEABLE,
2316                                         wsi->user_space, NULL, 0);
2317                         if (n < 0) {
2318                                 lwsl_info("writeable_fail\n");
2319                                 goto fail;
2320                         }
2321                         break;
2322                 }
2323
2324                 if (!wsi->hdr_parsing_completed)
2325                         break;
2326
2327                 if (wsi->state != LWSS_HTTP_ISSUING_FILE) {
2328
2329                         lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB, 1);
2330 #if defined(LWS_WITH_STATS)
2331                         {
2332                                 uint64_t ul = time_in_microseconds() - wsi->active_writable_req_us;
2333
2334                                 lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_WRITABLE_DELAY, ul);
2335                                 lws_stats_atomic_max(wsi->context, pt, LWSSTATS_MS_WORST_WRITABLE_DELAY, ul);
2336                                 wsi->active_writable_req_us = 0;
2337                         }
2338 #endif
2339
2340                         n = user_callback_handle_rxflow(wsi->protocol->callback,
2341                                         wsi, LWS_CALLBACK_HTTP_WRITEABLE,
2342                                         wsi->user_space, NULL, 0);
2343                         if (n < 0) {
2344                                 lwsl_info("writeable_fail\n");
2345                                 goto fail;
2346                         }
2347                         break;
2348                 }
2349
2350                 /* >0 == completion, <0 == error */
2351                 n = lws_serve_http_file_fragment(wsi);
2352                 if (n < 0 || (n > 0 && lws_http_transaction_completed(wsi))) {
2353                         lwsl_info("completed\n");
2354                         goto fail;
2355                 }
2356
2357                 break;
2358
2359         case LWSCM_SERVER_LISTENER:
2360
2361 #if LWS_POSIX
2362                 /* pollin means a client has connected to us then */
2363
2364                 do {
2365                         if (!(pollfd->revents & LWS_POLLIN) || !(pollfd->events & LWS_POLLIN))
2366                                 break;
2367
2368 #ifdef LWS_OPENSSL_SUPPORT
2369                         /*
2370                          * can we really accept it, with regards to SSL limit?
2371                          * another vhost may also have had POLLIN on his listener this
2372                          * round and used it up already
2373                          */
2374
2375                         if (wsi->vhost->use_ssl &&
2376                             context->simultaneous_ssl_restriction &&
2377                             context->simultaneous_ssl ==
2378                                           context->simultaneous_ssl_restriction)
2379                                 /* no... ignore it, he won't come again until we are
2380                                  * below the simultaneous_ssl_restriction limit and
2381                                  * POLLIN is enabled on him again
2382                                  */
2383                                 break;
2384 #endif
2385                         /* listen socket got an unencrypted connection... */
2386
2387                         clilen = sizeof(cli_addr);
2388                         lws_latency_pre(context, wsi);
2389                         accept_fd  = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
2390                                             &clilen);
2391                         lws_latency(context, wsi, "listener accept", accept_fd,
2392                                     accept_fd >= 0);
2393                         if (accept_fd < 0) {
2394                                 if (LWS_ERRNO == LWS_EAGAIN ||
2395                                     LWS_ERRNO == LWS_EWOULDBLOCK) {
2396 //                                      lwsl_err("accept asks to try again\n");
2397                                         break;
2398                                 }
2399                                 lwsl_err("ERROR on accept: %s\n", strerror(LWS_ERRNO));
2400                                 break;
2401                         }
2402
2403                         lws_plat_set_socket_options(wsi->vhost, accept_fd);
2404
2405 #if defined(LWS_USE_IPV6)
2406                         lwsl_debug("accepted new conn port %u on fd=%d\n",
2407                                           ((cli_addr.ss_family == AF_INET6) ?
2408                                           ntohs(((struct sockaddr_in6 *) &cli_addr)->sin6_port) :
2409                                           ntohs(((struct sockaddr_in *) &cli_addr)->sin_port)),
2410                                           accept_fd);
2411 #else
2412                         lwsl_debug("accepted new conn port %u on fd=%d\n",
2413                                           ntohs(((struct sockaddr_in *) &cli_addr)->sin_port),
2414                                           accept_fd);
2415 #endif
2416
2417 #else
2418                         /* not very beautiful... */
2419                         accept_fd = (lws_sockfd_type)pollfd;
2420 #endif
2421                         /*
2422                          * look at who we connected to and give user code a chance
2423                          * to reject based on client IP.  There's no protocol selected
2424                          * yet so we issue this to protocols[0]
2425                          */
2426                         if ((wsi->vhost->protocols[0].callback)(wsi,
2427                                         LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
2428                                         NULL, (void *)(long)accept_fd, 0)) {
2429                                 lwsl_debug("Callback denied network connection\n");
2430                                 compatible_close(accept_fd);
2431                                 break;
2432                         }
2433
2434                         if (!(wsi->vhost->options & LWS_SERVER_OPTION_ONLY_RAW))
2435                                 opts |= LWS_ADOPT_HTTP;
2436
2437                         fd.sockfd = accept_fd;
2438                         if (!lws_adopt_descriptor_vhost(wsi->vhost, opts, fd,
2439                                                         NULL, NULL))
2440                                 /* already closed cleanly as necessary */
2441                                 return 1;
2442
2443 #if LWS_POSIX
2444                 } while (pt->fds_count < context->fd_limit_per_thread - 1 &&
2445                          lws_poll_listen_fd(&pt->fds[wsi->position_in_fds_table]) > 0);
2446 #endif
2447                 return 0;
2448
2449         default:
2450                 break;
2451         }
2452
2453         if (!lws_server_socket_service_ssl(wsi, accept_fd))
2454                 return 0;
2455
2456 fail:
2457         lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
2458
2459         return 1;
2460 }
2461
2462 LWS_VISIBLE int
2463 lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
2464                     const char *other_headers, int other_headers_len)
2465 {
2466         static const char * const intermediates[] = { "private", "public" };
2467         struct lws_context *context = lws_get_context(wsi);
2468         struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
2469 #if defined(LWS_WITH_RANGES)
2470         struct lws_range_parsing *rp = &wsi->u.http.range;
2471 #endif
2472         char cache_control[50], *cc = "no-store";
2473         unsigned char *response = pt->serv_buf + LWS_PRE;
2474         unsigned char *p = response;
2475         unsigned char *end = p + context->pt_serv_buf_size - LWS_PRE;
2476         lws_filepos_t computed_total_content_length;
2477         int ret = 0, cclen = 8, n = HTTP_STATUS_OK;
2478         lws_fop_flags_t fflags = LWS_O_RDONLY;
2479 #if defined(LWS_WITH_RANGES)
2480         int ranges;
2481 #endif
2482         const struct lws_plat_file_ops *fops;
2483         const char *vpath;
2484
2485         /*
2486          * We either call the platform fops .open with first arg platform fops,
2487          * or we call fops_zip .open with first arg platform fops, and fops_zip
2488          * open will decide whether to switch to fops_zip or stay with fops_def.
2489          *
2490          * If wsi->u.http.fop_fd is already set, the caller already opened it
2491          */
2492         if (!wsi->u.http.fop_fd) {
2493                 fops = lws_vfs_select_fops(wsi->context->fops, file, &vpath);
2494                 fflags |= lws_vfs_prepare_flags(wsi);
2495                 wsi->u.http.fop_fd = fops->LWS_FOP_OPEN(wsi->context->fops,
2496                                                         file, vpath, &fflags);
2497                 if (!wsi->u.http.fop_fd) {
2498                         lwsl_err("Unable to open '%s'\n", file);
2499
2500                         return -1;
2501                 }
2502         }
2503         wsi->u.http.filelen = lws_vfs_get_length(wsi->u.http.fop_fd);
2504         computed_total_content_length = wsi->u.http.filelen;
2505
2506 #if defined(LWS_WITH_RANGES)
2507         ranges = lws_ranges_init(wsi, rp, wsi->u.http.filelen);
2508
2509         lwsl_debug("Range count %d\n", ranges);
2510         /*
2511          * no ranges -> 200;
2512          *  1 range  -> 206 + Content-Type: normal; Content-Range;
2513          *  more     -> 206 + Content-Type: multipart/byteranges
2514          *              Repeat the true Content-Type in each multipart header
2515          *              along with Content-Range
2516          */
2517         if (ranges < 0) {
2518                 /* it means he expressed a range in Range:, but it was illegal */
2519                 lws_return_http_status(wsi, HTTP_STATUS_REQ_RANGE_NOT_SATISFIABLE, NULL);
2520                 if (lws_http_transaction_completed(wsi))
2521                         return -1; /* <0 means just hang up */
2522
2523                 lws_vfs_file_close(&wsi->u.http.fop_fd);
2524
2525                 return 0; /* == 0 means we dealt with the transaction complete */
2526         }
2527         if (ranges)
2528                 n = HTTP_STATUS_PARTIAL_CONTENT;
2529 #endif
2530
2531         if (lws_add_http_header_status(wsi, n, &p, end))
2532                 return -1;
2533
2534         if ((wsi->u.http.fop_fd->flags & (LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP |
2535                        LWS_FOP_FLAG_COMPR_IS_GZIP)) ==
2536             (LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP | LWS_FOP_FLAG_COMPR_IS_GZIP)) {
2537                 if (lws_add_http_header_by_token(wsi,
2538                         WSI_TOKEN_HTTP_CONTENT_ENCODING,
2539                         (unsigned char *)"gzip", 4, &p, end))
2540                         return -1;
2541                 lwsl_info("file is being provided in gzip\n");
2542         }
2543
2544 #if defined(LWS_WITH_RANGES)
2545         if (ranges < 2 && content_type && content_type[0])
2546                 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
2547                                                  (unsigned char *)content_type,
2548                                                  strlen(content_type), &p, end))
2549                         return -1;
2550
2551         if (ranges >= 2) { /* multipart byteranges */
2552                 strncpy(wsi->u.http.multipart_content_type, content_type,
2553                         sizeof(wsi->u.http.multipart_content_type) - 1);
2554                 wsi->u.http.multipart_content_type[
2555                          sizeof(wsi->u.http.multipart_content_type) - 1] = '\0';
2556                 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
2557                                                  (unsigned char *)"multipart/byteranges; boundary=_lws",
2558                                                  20, &p, end))
2559                         return -1;
2560
2561                 /*
2562                  *  our overall content length has to include
2563                  *
2564                  *  - (n + 1) x "_lws\r\n"
2565                  *  - n x Content-Type: xxx/xxx\r\n
2566                  *  - n x Content-Range: bytes xxx-yyy/zzz\r\n
2567                  *  - n x /r/n
2568                  *  - the actual payloads (aggregated in rp->agg)
2569                  *
2570                  *  Precompute it for the main response header
2571                  */
2572
2573                 computed_total_content_length = (lws_filepos_t)rp->agg +
2574                                                 6 /* final _lws\r\n */;
2575
2576                 lws_ranges_reset(rp);
2577                 while (lws_ranges_next(rp)) {
2578                         n = lws_snprintf(cache_control, sizeof(cache_control),
2579                                         "bytes %llu-%llu/%llu",
2580                                         rp->start, rp->end, rp->extent);
2581
2582                         computed_total_content_length +=
2583                                         6 /* header _lws\r\n */ +
2584                                         14 + strlen(content_type) + 2 + /* Content-Type: xxx/xxx\r\n */
2585                                         15 + n + 2 + /* Content-Range: xxxx\r\n */
2586                                         2; /* /r/n */
2587                 }
2588
2589                 lws_ranges_reset(rp);
2590                 lws_ranges_next(rp);
2591         }
2592
2593         if (ranges == 1) {
2594                 computed_total_content_length = (lws_filepos_t)rp->agg;
2595                 n = lws_snprintf(cache_control, sizeof(cache_control), "bytes %llu-%llu/%llu",
2596                                 rp->start, rp->end, rp->extent);
2597
2598                 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_RANGE,
2599                                                  (unsigned char *)cache_control,
2600                                                  n, &p, end))
2601                         return -1;
2602         }
2603
2604         wsi->u.http.range.inside = 0;
2605
2606         if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ACCEPT_RANGES,
2607                                          (unsigned char *)"bytes", 5, &p, end))
2608                 return -1;
2609 #endif
2610
2611         if (!wsi->sending_chunked) {
2612                 if (lws_add_http_header_content_length(wsi,
2613                                                        computed_total_content_length,
2614                                                        &p, end))
2615                         return -1;
2616         } else {
2617                 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_TRANSFER_ENCODING,
2618                                                  (unsigned char *)"chunked",
2619                                                  7, &p, end))
2620                         return -1;
2621         }
2622
2623         if (wsi->cache_secs && wsi->cache_reuse) {
2624                 if (wsi->cache_revalidate) {
2625                         cc = cache_control;
2626                         cclen = sprintf(cache_control, "%s max-age: %u",
2627                                     intermediates[wsi->cache_intermediaries],
2628                                     wsi->cache_secs);
2629                 } else {
2630                         cc = "no-cache";
2631                         cclen = 8;
2632                 }
2633         }
2634
2635         if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CACHE_CONTROL,
2636                         (unsigned char *)cc, cclen, &p, end))
2637                 return -1;
2638
2639         if (wsi->u.http.connection_type == HTTP_CONNECTION_KEEP_ALIVE)
2640                 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_CONNECTION,
2641                                 (unsigned char *)"keep-alive", 10, &p, end))
2642                         return -1;
2643
2644         if (other_headers) {
2645                 if ((end - p) < other_headers_len)
2646                         return -1;
2647                 memcpy(p, other_headers, other_headers_len);
2648                 p += other_headers_len;
2649         }
2650
2651         if (lws_finalize_http_header(wsi, &p, end))
2652                 return -1;
2653
2654         ret = lws_write(wsi, response, p - response, LWS_WRITE_HTTP_HEADERS);
2655         if (ret != (p - response)) {
2656                 lwsl_err("_write returned %d from %ld\n", ret, (long)(p - response));
2657                 return -1;
2658         }
2659
2660         wsi->u.http.filepos = 0;
2661         wsi->state = LWSS_HTTP_ISSUING_FILE;
2662
2663         return lws_serve_http_file_fragment(wsi);
2664 }
2665
2666 int
2667 lws_interpret_incoming_packet(struct lws *wsi, unsigned char **buf, size_t len)
2668 {
2669         int m;
2670
2671         lwsl_parser("%s: received %d byte packet\n", __func__, (int)len);
2672 #if 0
2673         lwsl_hexdump(*buf, len);
2674 #endif
2675
2676         /* let the rx protocol state machine have as much as it needs */
2677
2678         while (len) {
2679                 /*
2680                  * we were accepting input but now we stopped doing so
2681                  */
2682                 if (!(wsi->rxflow_change_to & LWS_RXFLOW_ALLOW)) {
2683                         lws_rxflow_cache(wsi, *buf, 0, len);
2684                         lwsl_parser("%s: cached %ld\n", __func__, (long)len);
2685                         return 1;
2686                 }
2687
2688                 if (wsi->u.ws.rx_draining_ext) {
2689                         // lwsl_notice("draining with 0\n");
2690                         m = lws_rx_sm(wsi, 0);
2691                         if (m < 0)
2692                                 return -1;
2693                         continue;
2694                 }
2695
2696                 /* account for what we're using in rxflow buffer */
2697                 if (wsi->rxflow_buffer)
2698                         wsi->rxflow_pos++;
2699
2700                 /* consume payload bytes efficiently */
2701                 if (
2702                     wsi->lws_rx_parse_state ==
2703                     LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED) {
2704                         m = lws_payload_until_length_exhausted(wsi, buf, &len);
2705                         if (wsi->rxflow_buffer)
2706                                 wsi->rxflow_pos += m;
2707                 }
2708
2709                 /* process the byte */
2710                 m = lws_rx_sm(wsi, *(*buf)++);
2711                 if (m < 0)
2712                         return -1;
2713                 len--;
2714         }
2715
2716         lwsl_parser("%s: exit with %d unused\n", __func__, (int)len);
2717
2718         return 0;
2719 }
2720
2721 LWS_VISIBLE void
2722 lws_server_get_canonical_hostname(struct lws_context *context,
2723                                   struct lws_context_creation_info *info)
2724 {
2725         if (lws_check_opt(info->options, LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME))
2726                 return;
2727 #if LWS_POSIX && !defined(LWS_WITH_ESP32)
2728         /* find canonical hostname */
2729         gethostname((char *)context->canonical_hostname,
2730                     sizeof(context->canonical_hostname) - 1);
2731
2732         lwsl_notice(" canonical_hostname = %s\n", context->canonical_hostname);
2733 #else
2734         (void)context;
2735 #endif
2736 }
2737
2738 #define LWS_MAX_ELEM_NAME 32
2739
2740 enum urldecode_stateful {
2741         US_NAME,
2742         US_IDLE,
2743         US_PC1,
2744         US_PC2,
2745
2746         MT_LOOK_BOUND_IN,
2747         MT_HNAME,
2748         MT_DISP,
2749         MT_TYPE,
2750         MT_IGNORE1,
2751         MT_IGNORE2,
2752 };
2753
2754 static const char * const mp_hdr[] = {
2755         "content-disposition: ",
2756         "content-type: ",
2757         "\x0d\x0a"
2758 };
2759
2760 typedef int (*lws_urldecode_stateful_cb)(void *data,
2761                 const char *name, char **buf, int len, int final);
2762
2763 struct lws_urldecode_stateful {
2764         char *out;
2765         void *data;
2766         char name[LWS_MAX_ELEM_NAME];
2767         char temp[LWS_MAX_ELEM_NAME];
2768         char content_type[32];
2769         char content_disp[32];
2770         char content_disp_filename[256];
2771         char mime_boundary[128];
2772         int out_len;
2773         int pos;
2774         int hdr_idx;
2775         int mp;
2776         int sum;
2777
2778         unsigned int multipart_form_data:1;
2779         unsigned int inside_quote:1;
2780         unsigned int subname:1;
2781         unsigned int boundary_real_crlf:1;
2782
2783         enum urldecode_stateful state;
2784
2785         lws_urldecode_stateful_cb output;
2786 };
2787
2788 static struct lws_urldecode_stateful *
2789 lws_urldecode_s_create(struct lws *wsi, char *out, int out_len, void *data,
2790                        lws_urldecode_stateful_cb output)
2791 {
2792         struct lws_urldecode_stateful *s = lws_zalloc(sizeof(*s));
2793         char buf[200], *p;
2794         int m = 0;
2795
2796         if (!s)
2797                 return NULL;
2798
2799         s->out = out;
2800         s->out_len  = out_len;
2801         s->output = output;
2802         s->pos = 0;
2803         s->sum = 0;
2804         s->mp = 0;
2805         s->state = US_NAME;
2806         s->name[0] = '\0';
2807         s->data = data;
2808
2809         if (lws_hdr_copy(wsi, buf, sizeof(buf), WSI_TOKEN_HTTP_CONTENT_TYPE) > 0) {
2810                 /* multipart/form-data; boundary=----WebKitFormBoundarycc7YgAPEIHvgE9Bf */
2811
2812                 if (!strncmp(buf, "multipart/form-data", 19)) {
2813                         s->multipart_form_data = 1;
2814                         s->state = MT_LOOK_BOUND_IN;
2815                         s->mp = 2;
2816                         p = strstr(buf, "boundary=");
2817                         if (p) {
2818                                 p += 9;
2819                                 s->mime_boundary[m++] = '\x0d';
2820                                 s->mime_boundary[m++] = '\x0a';
2821                                 s->mime_boundary[m++] = '-';
2822                                 s->mime_boundary[m++] = '-';
2823                                 while (m < sizeof(s->mime_boundary) - 1 &&
2824                                        *p && *p != ' ')
2825                                         s->mime_boundary[m++] = *p++;
2826
2827                                 s->mime_boundary[m] = '\0';
2828
2829                                 lwsl_notice("boundary '%s'\n", s->mime_boundary);
2830                         }
2831                 }
2832         }
2833
2834         return s;
2835 }
2836
2837 static int
2838 lws_urldecode_s_process(struct lws_urldecode_stateful *s, const char *in, int len)
2839 {
2840         int n, m, hit = 0;
2841         char c, was_end = 0;
2842
2843         while (len--) {
2844                 if (s->pos == s->out_len - s->mp - 1) {
2845                         if (s->output(s->data, s->name, &s->out, s->pos, 0))
2846                                 return -1;
2847
2848                         was_end = s->pos;
2849                         s->pos = 0;
2850                 }
2851                 switch (s->state) {
2852
2853                 /* states for url arg style */
2854
2855                 case US_NAME:
2856                         s->inside_quote = 0;
2857                         if (*in == '=') {
2858                                 s->name[s->pos] = '\0';
2859                                 s->pos = 0;
2860                                 s->state = US_IDLE;
2861                                 in++;
2862                                 continue;
2863                         }
2864                         if (*in == '&') {
2865                                 s->name[s->pos] = '\0';
2866                                 if (s->output(s->data, s->name, &s->out, s->pos, 1))
2867                                         return -1;
2868                                 s->pos = 0;
2869                                 s->state = US_IDLE;
2870                                 in++;
2871                                 continue;
2872                         }
2873                         if (s->pos >= sizeof(s->name) - 1) {
2874                                 lwsl_notice("Name too long\n");
2875                                 return -1;
2876                         }
2877                         s->name[s->pos++] = *in++;
2878                         break;
2879                 case US_IDLE:
2880                         if (*in == '%') {
2881                                 s->state++;
2882                                 in++;
2883                                 continue;
2884                         }
2885                         if (*in == '&') {
2886                                 s->out[s->pos] = '\0';
2887                                 if (s->output(s->data, s->name, &s->out, s->pos, 1))
2888                                         return -1;
2889                                 s->pos = 0;
2890                                 s->state = US_NAME;
2891                                 in++;
2892                                 continue;
2893                         }
2894                         if (*in == '+') {
2895                                 in++;
2896                                 s->out[s->pos++] = ' ';
2897                                 continue;
2898                         }
2899                         s->out[s->pos++] = *in++;
2900                         break;
2901                 case US_PC1:
2902                         n = char_to_hex(*in);
2903                         if (n < 0)
2904                                 return -1;
2905
2906                         in++;
2907                         s->sum = n << 4;
2908                         s->state++;
2909                         break;
2910
2911                 case US_PC2:
2912                         n = char_to_hex(*in);
2913                         if (n < 0)
2914                                 return -1;
2915
2916                         in++;
2917                         s->out[s->pos++] = s->sum | n;
2918                         s->state = US_IDLE;
2919                         break;
2920
2921
2922                 /* states for multipart / mime style */
2923
2924                 case MT_LOOK_BOUND_IN:
2925 retry_as_first:
2926                         if (*in == s->mime_boundary[s->mp] &&
2927                             s->mime_boundary[s->mp]) {
2928                                 in++;
2929                                 s->mp++;
2930                                 if (!s->mime_boundary[s->mp]) {
2931                                         s->mp = 0;
2932                                         s->state = MT_IGNORE1;
2933
2934                                         if (s->pos || was_end)
2935                                                 if (s->output(s->data, s->name,
2936                                                       &s->out, s->pos, 1))
2937                                                         return -1;
2938
2939                                         s->pos = 0;
2940
2941                                         s->content_disp[0] = '\0';
2942                                         s->name[0] = '\0';
2943                                         s->content_disp_filename[0] = '\0';
2944                                         s->boundary_real_crlf = 1;
2945                                 }
2946                                 continue;
2947                         }
2948                         if (s->mp) {
2949                                 n = 0;
2950                                 if (!s->boundary_real_crlf)
2951                                         n = 2;
2952
2953                                 memcpy(s->out + s->pos, s->mime_boundary + n, s->mp - n);
2954                                 s->pos += s->mp;
2955                                 s->mp = 0;
2956                                 goto retry_as_first;
2957                         }
2958
2959                         s->out[s->pos++] = *in;
2960                         in++;
2961                         s->mp = 0;
2962                         break;
2963
2964                 case MT_HNAME:
2965                         m = 0;
2966                         c =*in;
2967                         if (c >= 'A' && c <= 'Z')
2968                                 c += 'a' - 'A';
2969                         for (n = 0; n < ARRAY_SIZE(mp_hdr); n++)
2970                                 if (c == mp_hdr[n][s->mp]) {
2971                                         m++;
2972                                         hit = n;
2973                                 }
2974                         in++;
2975                         if (!m) {
2976                                 s->mp = 0;
2977                                 continue;
2978                         }
2979
2980                         s->mp++;
2981                         if (m != 1)
2982                                 continue;
2983
2984                         if (mp_hdr[hit][s->mp])
2985                                 continue;
2986
2987                         s->mp = 0;
2988                         s->temp[0] = '\0';
2989                         s->subname = 0;
2990
2991                         if (hit == 2)
2992                                 s->state = MT_LOOK_BOUND_IN;
2993                         else
2994                                 s->state += hit + 1;
2995                         break;
2996
2997                 case MT_DISP:
2998                         /* form-data; name="file"; filename="t.txt" */
2999
3000                         if (*in == '\x0d') {
3001 //                              lwsl_notice("disp: '%s', '%s', '%s'\n",
3002 //                                 s->content_disp, s->name,
3003 //                                 s->content_disp_filename);
3004
3005                                 if (s->content_disp_filename[0])
3006                                         if (s->output(s->data, s->name,
3007                                                       &s->out, s->pos, LWS_UFS_OPEN))
3008                                                 return -1;
3009                                 s->state = MT_IGNORE2;
3010                                 goto done;
3011                         }
3012                         if (*in == ';') {
3013                                 s->subname = 1;
3014                                 s->temp[0] = '\0';
3015                                 s->mp = 0;
3016                                 goto done;
3017                         }
3018
3019                         if (*in == '\"') {
3020                                 s->inside_quote ^= 1;
3021                                 goto done;
3022                         }
3023
3024                         if (s->subname) {
3025                                 if (*in == '=') {
3026                                         s->temp[s->mp] = '\0';
3027                                         s->subname = 0;
3028                                         s->mp = 0;
3029                                         goto done;
3030                                 }
3031                                 if (s->mp < sizeof(s->temp) - 1 &&
3032                                     (*in != ' ' || s->inside_quote))
3033                                         s->temp[s->mp++] = *in;
3034                                 goto done;
3035                         }
3036
3037                         if (!s->temp[0]) {
3038                                 if (s->mp < sizeof(s->content_disp) - 1)
3039                                         s->content_disp[s->mp++] = *in;
3040                                 s->content_disp[s->mp] = '\0';
3041                                 goto done;
3042                         }
3043
3044                         if (!strcmp(s->temp, "name")) {
3045                                 if (s->mp < sizeof(s->name) - 1)
3046                                         s->name[s->mp++] = *in;
3047                                 s->name[s->mp] = '\0';
3048                                 goto done;
3049                         }
3050
3051                         if (!strcmp(s->temp, "filename")) {
3052                                 if (s->mp < sizeof(s->content_disp_filename) - 1)
3053                                         s->content_disp_filename[s->mp++] = *in;
3054                                 s->content_disp_filename[s->mp] = '\0';
3055                                 goto done;
3056                         }
3057 done:
3058                         in++;
3059                         break;
3060
3061                 case MT_TYPE:
3062                         if (*in == '\x0d')
3063                                 s->state = MT_IGNORE2;
3064                         else {
3065                                 if (s->mp < sizeof(s->content_type) - 1)
3066                                         s->content_type[s->mp++] = *in;
3067                                 s->content_type[s->mp] = '\0';
3068                         }
3069                         in++;
3070                         break;
3071
3072                 case MT_IGNORE1:
3073                         if (*in == '\x0d')
3074                                 s->state = MT_IGNORE2;
3075                         in++;
3076                         break;
3077
3078                 case MT_IGNORE2:
3079                         s->mp = 0;
3080                         if (*in == '\x0a')
3081                                 s->state = MT_HNAME;
3082                         in++;
3083                         break;
3084                 }
3085         }
3086
3087         return 0;
3088 }
3089
3090 static int
3091 lws_urldecode_s_destroy(struct lws_urldecode_stateful *s)
3092 {
3093         int ret = 0;
3094
3095         if (s->state != US_IDLE)
3096                 ret = -1;
3097
3098         if (!ret)
3099                 if (s->output(s->data, s->name, &s->out, s->pos, 1))
3100                         ret = -1;
3101
3102         lws_free(s);
3103
3104         return ret;
3105 }
3106
3107 struct lws_spa {
3108         struct lws_urldecode_stateful *s;
3109         lws_spa_fileupload_cb opt_cb;
3110         const char * const *param_names;
3111         int count_params;
3112         char **params;
3113         int *param_length;
3114         void *opt_data;
3115
3116         char *storage;
3117         char *end;
3118         int max_storage;
3119
3120         char finalized;
3121 };
3122
3123 static int
3124 lws_urldecode_spa_lookup(struct lws_spa *spa,
3125                          const char *name)
3126 {
3127         int n;
3128
3129         for (n = 0; n < spa->count_params; n++)
3130                 if (!strcmp(spa->param_names[n], name))
3131                         return n;
3132
3133         return -1;
3134 }
3135
3136 static int
3137 lws_urldecode_spa_cb(void *data, const char *name, char **buf, int len,
3138                      int final)
3139 {
3140         struct lws_spa *spa =
3141                         (struct lws_spa *)data;
3142         int n;
3143
3144         if (spa->s->content_disp_filename[0]) {
3145                 if (spa->opt_cb) {
3146                         n = spa->opt_cb(spa->opt_data, name,
3147                                         spa->s->content_disp_filename,
3148                                         *buf, len, final);
3149
3150                         if (n < 0)
3151                                 return -1;
3152                 }
3153                 return 0;
3154         }
3155         n = lws_urldecode_spa_lookup(spa, name);
3156
3157         if (n == -1 || !len) /* unrecognized */
3158                 return 0;
3159
3160         if (!spa->params[n])
3161                 spa->params[n] = *buf;
3162
3163         if ((*buf) + len >= spa->end) {
3164                 lwsl_notice("%s: exceeded storage\n", __func__);
3165                 return -1;
3166         }
3167
3168         spa->param_length[n] += len;
3169
3170         /* move it on inside storage */
3171         (*buf) += len;
3172         *((*buf)++) = '\0';
3173
3174         spa->s->out_len -= len + 1;
3175
3176         return 0;
3177 }
3178
3179 LWS_VISIBLE LWS_EXTERN struct lws_spa *
3180 lws_spa_create(struct lws *wsi, const char * const *param_names,
3181                          int count_params, int max_storage,
3182                          lws_spa_fileupload_cb opt_cb, void *opt_data)
3183 {
3184         struct lws_spa *spa = lws_zalloc(sizeof(*spa));
3185
3186         if (!spa)
3187                 return NULL;
3188
3189         spa->param_names = param_names;
3190         spa->count_params = count_params;
3191         spa->max_storage = max_storage;
3192         spa->opt_cb = opt_cb;
3193         spa->opt_data = opt_data;
3194
3195         spa->storage = lws_malloc(max_storage);
3196         if (!spa->storage)
3197                 goto bail2;
3198         spa->end = spa->storage + max_storage - 1;
3199
3200         spa->params = lws_zalloc(sizeof(char *) * count_params);
3201         if (!spa->params)
3202                 goto bail3;
3203
3204         spa->s = lws_urldecode_s_create(wsi, spa->storage, max_storage, spa,
3205                                         lws_urldecode_spa_cb);
3206         if (!spa->s)
3207                 goto bail4;
3208
3209         spa->param_length = lws_zalloc(sizeof(int) * count_params);
3210         if (!spa->param_length)
3211                 goto bail5;
3212
3213         lwsl_info("%s: Created SPA %p\n", __func__, spa);
3214
3215         return spa;
3216
3217 bail5:
3218         lws_urldecode_s_destroy(spa->s);
3219 bail4:
3220         lws_free(spa->params);
3221 bail3:
3222         lws_free(spa->storage);
3223 bail2:
3224         lws_free(spa);
3225
3226         return NULL;
3227 }
3228
3229 LWS_VISIBLE LWS_EXTERN int
3230 lws_spa_process(struct lws_spa *ludspa, const char *in, int len)
3231 {
3232         if (!ludspa) {
3233                 lwsl_err("%s: NULL spa\n", __func__);
3234                 return -1;
3235         }
3236         /* we reject any junk after the last part arrived and we finalized */
3237         if (ludspa->finalized)
3238                 return 0;
3239
3240         return lws_urldecode_s_process(ludspa->s, in, len);
3241 }
3242
3243 LWS_VISIBLE LWS_EXTERN int
3244 lws_spa_get_length(struct lws_spa *ludspa, int n)
3245 {
3246         if (n >= ludspa->count_params)
3247                 return 0;
3248
3249         return ludspa->param_length[n];
3250 }
3251
3252 LWS_VISIBLE LWS_EXTERN const char *
3253 lws_spa_get_string(struct lws_spa *ludspa, int n)
3254 {
3255         if (n >= ludspa->count_params)
3256                 return NULL;
3257
3258         return ludspa->params[n];
3259 }
3260
3261 LWS_VISIBLE LWS_EXTERN int
3262 lws_spa_finalize(struct lws_spa *spa)
3263 {
3264         if (spa->s) {
3265                 lws_urldecode_s_destroy(spa->s);
3266                 spa->s = NULL;
3267         }
3268
3269         spa->finalized = 1;
3270
3271         return 0;
3272 }
3273
3274 LWS_VISIBLE LWS_EXTERN int
3275 lws_spa_destroy(struct lws_spa *spa)
3276 {
3277         int n = 0;
3278
3279         lwsl_notice("%s: destroy spa %p\n", __func__, spa);
3280
3281         if (spa->s)
3282                 lws_urldecode_s_destroy(spa->s);
3283
3284         lwsl_debug("%s %p %p %p %p\n", __func__,
3285                         spa->param_length,
3286                         spa->params,
3287                         spa->storage,
3288                         spa
3289                         );
3290
3291         lws_free(spa->param_length);
3292         lws_free(spa->params);
3293         lws_free(spa->storage);
3294         lws_free(spa);
3295
3296         return n;
3297 }
3298
3299 #if 0
3300 LWS_VISIBLE LWS_EXTERN int
3301 lws_spa_destroy(struct lws_spa *spa)
3302 {
3303         int n = 0;
3304
3305         lwsl_info("%s: destroy spa %p\n", __func__, spa);
3306
3307         if (spa->s)
3308                 lws_urldecode_s_destroy(spa->s);
3309
3310         lwsl_debug("%s\n", __func__);
3311
3312         lws_free(spa->param_length);
3313         lws_free(spa->params);
3314         lws_free(spa->storage);
3315         lws_free(spa);
3316
3317         return n;
3318 }
3319 #endif
3320 LWS_VISIBLE LWS_EXTERN int
3321 lws_chunked_html_process(struct lws_process_html_args *args,
3322                          struct lws_process_html_state *s)
3323 {
3324         char *sp, buffer[32];
3325         const char *pc;
3326         int old_len, n;
3327
3328         /* do replacements */
3329         sp = args->p;
3330         old_len = args->len;
3331         args->len = 0;
3332         s->start = sp;
3333         while (sp < args->p + old_len) {
3334
3335                 if (args->len + 7 >= args->max_len) {
3336                         lwsl_err("Used up interpret padding\n");
3337                         return -1;
3338                 }
3339
3340                 if ((!s->pos && *sp == '$') || s->pos) {
3341                         int hits = 0, hit = 0;
3342
3343                         if (!s->pos)
3344                                 s->start = sp;
3345                         s->swallow[s->pos++] = *sp;
3346                         if (s->pos == sizeof(s->swallow) - 1)
3347                                 goto skip;
3348                         for (n = 0; n < s->count_vars; n++)
3349                                 if (!strncmp(s->swallow, s->vars[n], s->pos)) {
3350                                         hits++;
3351                                         hit = n;
3352                                 }
3353                         if (!hits) {
3354 skip:
3355                                 s->swallow[s->pos] = '\0';
3356                                 memcpy(s->start, s->swallow, s->pos);
3357                                 args->len++;
3358                                 s->pos = 0;
3359                                 sp = s->start + 1;
3360                                 continue;
3361                         }
3362                         if (hits == 1 && s->pos == strlen(s->vars[hit])) {
3363                                 pc = s->replace(s->data, hit);
3364                                 if (!pc)
3365                                         pc = "NULL";
3366                                 n = strlen(pc);
3367                                 s->swallow[s->pos] = '\0';
3368                                 if (n != s->pos) {
3369                                         memmove(s->start + n,
3370                                                 s->start + s->pos,
3371                                                 old_len - (sp - args->p));
3372                                         old_len += (n - s->pos) + 1;
3373                                 }
3374                                 memcpy(s->start, pc, n);
3375                                 args->len++;
3376                                 sp = s->start + 1;
3377
3378                                 s->pos = 0;
3379                         }
3380                         sp++;
3381                         continue;
3382                 }
3383
3384                 args->len++;
3385                 sp++;
3386         }
3387
3388         /* no space left for final chunk trailer */
3389         if (args->final && args->len + 7 >= args->max_len)
3390                 return -1;
3391
3392         n = sprintf(buffer, "%X\x0d\x0a", args->len);
3393
3394         args->p -= n;
3395         memcpy(args->p, buffer, n);
3396         args->len += n;
3397
3398         if (args->final) {
3399                 sp = args->p + args->len;
3400                 *sp++ = '\x0d';
3401                 *sp++ = '\x0a';
3402                 *sp++ = '0';
3403                 *sp++ = '\x0d';
3404                 *sp++ = '\x0a';
3405                 *sp++ = '\x0d';
3406                 *sp++ = '\x0a';
3407                 args->len += 7;
3408         } else {
3409                 sp = args->p + args->len;
3410                 *sp++ = '\x0d';
3411                 *sp++ = '\x0a';
3412                 args->len += 2;
3413         }
3414
3415         return 0;
3416 }