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