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