• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 #include "private-lib-core.h"
26 
27 #if !defined(SOL_TCP) && defined(IPPROTO_TCP)
28 #define SOL_TCP IPPROTO_TCP
29 #endif
30 
31 const char * const method_names[] = {
32 	"GET", "POST",
33 #if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
34 	"OPTIONS", "PUT", "PATCH", "DELETE",
35 #endif
36 	"CONNECT", "HEAD",
37 #ifdef LWS_WITH_HTTP2
38 	":path",
39 #endif
40 	};
41 
42 #if defined(LWS_WITH_FILE_OPS)
43 static const char * const intermediates[] = { "private", "public" };
44 #endif
45 
46 /*
47  * return 0: all done
48  *        1: nonfatal error
49  *       <0: fatal error
50  *
51  *       REQUIRES CONTEXT LOCK HELD
52  */
53 
54 #if defined(LWS_WITH_SERVER)
55 
56 struct vh_sock_args {
57 	const struct lws_context_creation_info	*info;
58 	struct lws_vhost			*vhost;
59 	int					af;
60 };
61 
62 
63 static int
check_extant(struct lws_dll2 * d,void * user)64 check_extant(struct lws_dll2 *d, void *user)
65 {
66 	struct lws *wsi = lws_container_of(d, struct lws, listen_list);
67 	struct vh_sock_args *a = (struct vh_sock_args *)user;
68 
69 	if (!lws_vhost_compare_listen(wsi->a.vhost, a->vhost))
70 		return 0;
71 
72 	if (wsi->af != a ->af)
73 		return 0;
74 
75 	lwsl_notice(" using listen skt from vhost %s\n", wsi->a.vhost->name);
76 
77 	return 1;
78 }
79 
80 /*
81  * Creates a single listen socket of a specific AF
82  */
83 
84 int
_lws_vhost_init_server_af(struct vh_sock_args * a)85 _lws_vhost_init_server_af(struct vh_sock_args *a)
86 {
87 	struct lws_context *cx = a->vhost->context;
88 	struct lws_context_per_thread *pt;
89 	int n, opt = 1, limit = 1;
90 	lws_sockfd_type sockfd;
91 	struct lws *wsi;
92 	int m = 0, is;
93 #if defined(LWS_WITH_IPV6)
94 	int value = 1;
95 #endif
96 
97 	(void)method_names;
98 	(void)opt;
99 
100 	lwsl_info("%s: af %d\n", __func__, (int)a->af);
101 
102 	if (lws_vhost_foreach_listen_wsi(a->vhost->context, a, check_extant))
103 		return 0;
104 
105 deal:
106 
107 	if (a->vhost->iface) {
108 
109 		/*
110 		 * let's check before we do anything else about the disposition
111 		 * of the interface he wants to bind to...
112 		 */
113 		is = lws_socket_bind(a->vhost, NULL, LWS_SOCK_INVALID,
114 				     a->vhost->listen_port, a->vhost->iface,
115 				     a->af);
116 		lwsl_debug("initial if check says %d\n", is);
117 
118 		if (is == LWS_ITOSA_BUSY)
119 			/* treat as fatal */
120 			return -1;
121 
122 		lws_start_foreach_llp(struct lws_vhost **, pv,
123 				      cx->no_listener_vhost_list) {
124 			if (is >= LWS_ITOSA_USABLE && *pv == a->vhost) {
125 				/* on the list and shouldn't be: remove it */
126 				lwsl_debug("deferred iface: removing vh %s\n",
127 						(*pv)->name);
128 				*pv = a->vhost->no_listener_vhost_list;
129 				a->vhost->no_listener_vhost_list = NULL;
130 				goto done_list;
131 			}
132 			if (is < LWS_ITOSA_USABLE && *pv == a->vhost)
133 				goto done_list;
134 		} lws_end_foreach_llp(pv, no_listener_vhost_list);
135 
136 		/* not on the list... */
137 
138 		if (is < LWS_ITOSA_USABLE) {
139 
140 			/* ... but needs to be: so add it */
141 
142 			lwsl_debug("deferred iface: adding vh %s\n",
143 					a->vhost->name);
144 			a->vhost->no_listener_vhost_list =
145 					cx->no_listener_vhost_list;
146 			cx->no_listener_vhost_list = a->vhost;
147 		}
148 
149 done_list:
150 
151 		switch (is) {
152 		default:
153 			break;
154 		case LWS_ITOSA_NOT_EXIST:
155 			/* can't add it */
156 			if (!a->info)
157 				return -1;
158 
159 			/* first time */
160 			lwsl_err("%s: VH %s: iface %s port %d DOESN'T EXIST\n",
161 				 __func__, a->vhost->name, a->vhost->iface,
162 				 a->vhost->listen_port);
163 
164 			return (a->info->options &
165 				LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND) ==
166 				LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND ?
167 				-1 : 1;
168 
169 		case LWS_ITOSA_NOT_USABLE:
170 			/* can't add it */
171 			if (!a->info) /* first time */
172 				return -1;
173 
174 			lwsl_err("%s: VH %s: iface %s port %d NOT USABLE\n",
175 				 __func__, a->vhost->name, a->vhost->iface,
176 				 a->vhost->listen_port);
177 
178 			return (a->info->options &
179 				LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND) ==
180 				LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND ?
181 				-1 : 1;
182 		}
183 	}
184 
185 	(void)n;
186 #if defined(__linux__)
187 	/*
188 	 * A Unix domain sockets cannot be bound multiple times, even if we
189 	 * set the SO_REUSE* options on.
190 	 *
191 	 * However on recent linux, each thread is able to independently listen.
192 	 *
193 	 * So we can assume creating just one listening socket for a multi-
194 	 * threaded environment will typically work.
195 	 */
196 	if (a->af != AF_UNIX)
197 		limit = cx->count_threads;
198 #endif
199 
200 	for (m = 0; m < limit; m++) {
201 
202 		sockfd = lws_fi(&a->vhost->fic, "listenskt") ?
203 					LWS_SOCK_INVALID :
204 					socket(a->af, SOCK_STREAM, 0);
205 
206 		if (sockfd == LWS_SOCK_INVALID) {
207 			lwsl_err("ERROR opening socket\n");
208 			return 1;
209 		}
210 
211 #if !defined(LWS_PLAT_FREERTOS)
212 #if (defined(WIN32) || defined(_WIN32)) && defined(SO_EXCLUSIVEADDRUSE)
213 		/*
214 		 * only accept that we are the only listener on the port
215 		 * https://msdn.microsoft.com/zh-tw/library/
216 		 *    windows/desktop/ms740621(v=vs.85).aspx
217 		 *
218 		 * for lws, to match Linux, we default to exclusive listen
219 		 */
220 		if (!lws_check_opt(a->vhost->options,
221 				LWS_SERVER_OPTION_ALLOW_LISTEN_SHARE)) {
222 			if (setsockopt(sockfd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
223 				       (const void *)&opt, sizeof(opt)) < 0) {
224 				lwsl_err("reuseaddr failed\n");
225 				compatible_close(sockfd);
226 				return -1;
227 			}
228 		} else
229 #endif
230 
231 		/*
232 		 * allow us to restart even if old sockets in TIME_WAIT
233 		 */
234 		if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
235 			       (const void *)&opt, sizeof(opt)) < 0) {
236 			lwsl_err("reuseaddr failed\n");
237 			compatible_close(sockfd);
238 			return -1;
239 		}
240 
241 #if defined(LWS_WITH_IPV6) && defined(IPV6_V6ONLY)
242 		/*
243 		 * If we have an ipv6 listen socket, it only accepts ipv6.
244 		 *
245 		 * There will be a separate ipv4 listen socket if that's
246 		 * enabled.
247 		 */
248 		if (a->af == AF_INET6 &&
249 		    setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
250 			       (const void*)&value, sizeof(value)) < 0) {
251 			compatible_close(sockfd);
252 			return -1;
253 		}
254 #endif
255 
256 #if defined(__linux__) && defined(SO_REUSEPORT)
257 		/* keep coverity happy */
258 #if LWS_MAX_SMP > 1
259 		n = 1;
260 #else
261 		n = lws_check_opt(a->vhost->options,
262 				  LWS_SERVER_OPTION_ALLOW_LISTEN_SHARE);
263 #endif
264 		if (n || cx->count_threads > 1) /* ... also implied by threads > 1 */
265 			if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT,
266 					(const void *)&opt, sizeof(opt)) < 0) {
267 				compatible_close(sockfd);
268 				return -1;
269 			}
270 #endif
271 #endif
272 		lws_plat_set_socket_options(a->vhost, sockfd, 0);
273 
274 		is = lws_socket_bind(a->vhost, NULL, sockfd,
275 				     a->vhost->listen_port,
276 				     a->vhost->iface, a->af);
277 
278 		if (is == LWS_ITOSA_BUSY) {
279 			/* treat as fatal */
280 			compatible_close(sockfd);
281 
282 			return -1;
283 		}
284 
285 		/*
286 		 * There is a race where the network device may come up and then
287 		 * go away and fail here.  So correctly handle unexpected failure
288 		 * here despite we earlier confirmed it.
289 		 */
290 		if (is < 0) {
291 			lwsl_info("%s: lws_socket_bind says %d\n", __func__, is);
292 			compatible_close(sockfd);
293 			if (a->vhost->iface)
294 				goto deal;
295 			return -1;
296 		}
297 
298 		/*
299 		 * Create the listen wsi and customize it
300 		 */
301 
302 		lws_context_lock(cx, __func__);
303 		wsi = __lws_wsi_create_with_role(cx, m, &role_ops_listen, NULL);
304 		lws_context_unlock(cx);
305 		if (wsi == NULL) {
306 			lwsl_err("Out of mem\n");
307 			goto bail;
308 		}
309 
310 		wsi->af = (uint8_t)a->af;
311 
312 #ifdef LWS_WITH_UNIX_SOCK
313 		if (!LWS_UNIX_SOCK_ENABLED(a->vhost))
314 #endif
315 		{
316 			wsi->unix_skt = 1;
317 			a->vhost->listen_port = is;
318 
319 			lwsl_debug("%s: lws_socket_bind says %d\n", __func__, is);
320 		}
321 
322 		wsi->desc.sockfd = sockfd;
323 		wsi->a.protocol = a->vhost->protocols;
324 		lws_vhost_bind_wsi(a->vhost, wsi);
325 		wsi->listener = 1;
326 
327 		if (wsi->a.context->event_loop_ops->init_vhost_listen_wsi)
328 			wsi->a.context->event_loop_ops->init_vhost_listen_wsi(wsi);
329 
330 		pt = &cx->pt[m];
331 		lws_pt_lock(pt, __func__);
332 
333 		if (__insert_wsi_socket_into_fds(cx, wsi)) {
334 			lwsl_notice("inserting wsi socket into fds failed\n");
335 			lws_pt_unlock(pt);
336 			goto bail;
337 		}
338 
339 		lws_dll2_add_tail(&wsi->listen_list, &a->vhost->listen_wsi);
340 		lws_pt_unlock(pt);
341 
342 #if defined(WIN32) && defined(TCP_FASTOPEN)
343 		if (a->vhost->fo_listen_queue) {
344 			int optval = 1;
345 			if (setsockopt(wsi->desc.sockfd, IPPROTO_TCP,
346 				       TCP_FASTOPEN,
347 				       (const char*)&optval, sizeof(optval)) < 0) {
348 				int error = LWS_ERRNO;
349 				lwsl_warn("%s: TCP_NODELAY failed with error %d\n",
350 						__func__, error);
351 			}
352 		}
353 #else
354 #if defined(TCP_FASTOPEN)
355 		if (a->vhost->fo_listen_queue) {
356 			int qlen = a->vhost->fo_listen_queue;
357 
358 			if (setsockopt(wsi->desc.sockfd, SOL_TCP, TCP_FASTOPEN,
359 				       &qlen, sizeof(qlen)))
360 				lwsl_warn("%s: TCP_FASTOPEN failed\n", __func__);
361 		}
362 #endif
363 #endif
364 
365 		n = listen(wsi->desc.sockfd, LWS_SOMAXCONN);
366 		if (n < 0) {
367 			lwsl_err("listen failed with error %d\n", LWS_ERRNO);
368 			lws_dll2_remove(&wsi->listen_list);
369 			__remove_wsi_socket_from_fds(wsi);
370 			goto bail;
371 		}
372 
373 		if (wsi)
374 			__lws_lc_tag(a->vhost->context,
375 				     &a->vhost->context->lcg[LWSLCG_WSI],
376 				     &wsi->lc, "listen|%s|%s|%d",
377 				     a->vhost->name,
378 				     a->vhost->iface ? a->vhost->iface : "",
379 				     (int)a->vhost->listen_port);
380 
381 	} /* for each thread able to independently listen */
382 
383 	if (!lws_check_opt(cx->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) {
384 #ifdef LWS_WITH_UNIX_SOCK
385 		if (a->af == AF_UNIX)
386 			lwsl_info(" Listening on \"%s\"\n", a->vhost->iface);
387 		else
388 #endif
389 			lwsl_info(" Listening on %s:%d\n",
390 					a->vhost->iface,
391 					a->vhost->listen_port);
392         }
393 
394 	// info->port = vhost->listen_port;
395 
396 	return 0;
397 
398 bail:
399 	compatible_close(sockfd);
400 
401 	return -1;
402 }
403 
404 
405 int
_lws_vhost_init_server(const struct lws_context_creation_info * info,struct lws_vhost * vhost)406 _lws_vhost_init_server(const struct lws_context_creation_info *info,
407 		       struct lws_vhost *vhost)
408 {
409 	struct vh_sock_args a;
410 	int n;
411 
412 	a.info = info;
413 	a.vhost = vhost;
414 
415 	if (info) {
416 		vhost->iface = info->iface;
417 		vhost->listen_port = info->port;
418 	}
419 
420 	/* set up our external listening socket we serve on */
421 
422 	if (vhost->listen_port == CONTEXT_PORT_NO_LISTEN ||
423 	    vhost->listen_port == CONTEXT_PORT_NO_LISTEN_SERVER)
424 		return 0;
425 
426 	/*
427 	 * Let's figure out what AF(s) we want this vhost to listen on.
428 	 *
429 	 * We want AF_UNIX alone if that's what's told
430 	 */
431 
432 #if defined(LWS_WITH_UNIX_SOCK)
433 	/*
434 	 * If unix socket, ask for that and we are done
435 	 */
436 	if (LWS_UNIX_SOCK_ENABLED(vhost)) {
437 		a.af = AF_UNIX;
438 		goto single;
439 	}
440 #endif
441 
442 	/*
443 	 * We may support both ipv4 and ipv6, but get a numeric vhost listen
444 	 * iface that is unambiguously ipv4 or ipv6, meaning we can only listen
445 	 * for the related AF then.
446 	 */
447 
448 	if (vhost->iface) {
449 		uint8_t buf[16];
450 		int q;
451 
452 		q = lws_parse_numeric_address(vhost->iface, buf, sizeof(buf));
453 
454 		if (q == 4) {
455 			a.af = AF_INET;
456 			goto single;
457 		}
458 
459 		if (q == 16) {
460 #if defined(LWS_WITH_IPV6)
461 			if (LWS_IPV6_ENABLED(vhost)) {
462 				a.af = AF_INET6;
463 				goto single;
464 			}
465 #endif
466 			lwsl_err("%s: ipv6 not supported on %s\n", __func__,
467 					vhost->name);
468 			return 1;
469 		}
470 	}
471 
472 	/*
473 	 * ... if we make it here, we would want to listen on AF_INET and
474 	 * AF_INET6 unless one or the other is forbidden
475 	 */
476 
477 #if defined(LWS_WITH_IPV6)
478 	if (!(LWS_IPV6_ENABLED(vhost) &&
479 	      (vhost->options & LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY) &&
480 	      (vhost->options & LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE))) {
481 #endif
482 		a.af = AF_INET;
483 		n = _lws_vhost_init_server_af(&a);
484 		if (n)
485 			return n;
486 
487 #if defined(LWS_WITH_IPV6)
488 	}
489 	if (LWS_IPV6_ENABLED(vhost)) {
490 		a.af = AF_INET6;
491 		goto single;
492 	}
493 #endif
494 
495 	return 0;
496 
497 single:
498 	return _lws_vhost_init_server_af(&a);
499 }
500 
501 #endif
502 
503 struct lws_vhost *
lws_select_vhost(struct lws_context * context,int port,const char * servername)504 lws_select_vhost(struct lws_context *context, int port, const char *servername)
505 {
506 	struct lws_vhost *vhost = context->vhost_list;
507 	const char *p;
508 	int n, colon;
509 
510 	n = (int)strlen(servername);
511 	colon = n;
512 	p = strchr(servername, ':');
513 	if (p)
514 		colon = lws_ptr_diff(p, servername);
515 
516 	/* Priotity 1: first try exact matches */
517 
518 	while (vhost) {
519 		if (port == vhost->listen_port &&
520 		    !strncmp(vhost->name, servername, (unsigned int)colon)) {
521 			lwsl_info("SNI: Found: %s\n", servername);
522 			return vhost;
523 		}
524 		vhost = vhost->vhost_next;
525 	}
526 
527 	/*
528 	 * Priority 2: if no exact matches, try matching *.vhost-name
529 	 * unintentional matches are possible but resolve to x.com for *.x.com
530 	 * which is reasonable.  If exact match exists we already chose it and
531 	 * never reach here.  SSL will still fail it if the cert doesn't allow
532 	 * *.x.com.
533 	 */
534 	vhost = context->vhost_list;
535 	while (vhost) {
536 		int m = (int)strlen(vhost->name);
537 		if (port && port == vhost->listen_port &&
538 		    m <= (colon - 2) &&
539 		    servername[colon - m - 1] == '.' &&
540 		    !strncmp(vhost->name, servername + colon - m, (unsigned int)m)) {
541 			lwsl_info("SNI: Found %s on wildcard: %s\n",
542 				    servername, vhost->name);
543 			return vhost;
544 		}
545 		vhost = vhost->vhost_next;
546 	}
547 
548 	/* Priority 3: match the first vhost on our port */
549 
550 	vhost = context->vhost_list;
551 	while (vhost) {
552 		if (port && port == vhost->listen_port) {
553 			lwsl_info("%s: vhost match to %s based on port %d\n",
554 					__func__, vhost->name, port);
555 			return vhost;
556 		}
557 		vhost = vhost->vhost_next;
558 	}
559 
560 	/* no match */
561 
562 	return NULL;
563 }
564 
565 static const struct lws_mimetype {
566 	const char *extension;
567 	const char *mimetype;
568 } server_mimetypes[] = {
569 	{ ".html", "text/html" },
570 	{ ".htm", "text/html" },
571 	{ ".js", "text/javascript" },
572 	{ ".css", "text/css" },
573 	{ ".png", "image/png" },
574 	{ ".jpg", "image/jpeg" },
575 	{ ".jpeg", "image/jpeg" },
576 	{ ".ico", "image/x-icon" },
577 	{ ".gif", "image/gif" },
578 	{ ".svg", "image/svg+xml" },
579 	{ ".ttf", "application/x-font-ttf" },
580 	{ ".otf", "application/font-woff" },
581 	{ ".woff", "application/font-woff" },
582 	{ ".woff2", "application/font-woff2" },
583 	{ ".gz", "application/gzip" },
584 	{ ".txt", "text/plain" },
585 	{ ".xml", "application/xml" },
586 	{ ".json", "application/json" },
587 	{ ".mjs", "text/javascript" },
588 };
589 
590 const char *
lws_get_mimetype(const char * file,const struct lws_http_mount * m)591 lws_get_mimetype(const char *file, const struct lws_http_mount *m)
592 {
593 	const struct lws_protocol_vhost_options *pvo;
594 	size_t n = strlen(file), len, i;
595 	const char *fallback_mimetype = NULL;
596 	const struct lws_mimetype *mt;
597 
598 	/* prioritize user-defined mimetypes */
599 	for (pvo = m ? m->extra_mimetypes : NULL; pvo; pvo = pvo->next) {
600 		/* ie, match anything */
601 		if (!fallback_mimetype && pvo->name[0] == '*') {
602 			fallback_mimetype = pvo->value;
603 			continue;
604 		}
605 
606 		len = strlen(pvo->name);
607 		if (n > len && !strcasecmp(&file[n - len], pvo->name)) {
608 			lwsl_info("%s: match to user mimetype: %s\n", __func__,
609 				  pvo->value);
610 			return pvo->value;
611 		}
612 	}
613 
614 	/* fallback to server-defined mimetypes */
615 	for (i = 0; i < LWS_ARRAY_SIZE(server_mimetypes); ++i) {
616 		mt = &server_mimetypes[i];
617 
618 		len = strlen(mt->extension);
619 		if (n > len && !strcasecmp(&file[n - len], mt->extension)) {
620 			lwsl_info("%s: match to server mimetype: %s\n", __func__,
621 				  mt->mimetype);
622 			return mt->mimetype;
623 		}
624 	}
625 
626 	/* fallback to '*' if defined */
627 	if (fallback_mimetype) {
628 		lwsl_info("%s: match to any mimetype: %s\n", __func__,
629 			  fallback_mimetype);
630 		return fallback_mimetype;
631 	}
632 
633 	return NULL;
634 }
635 
636 #if defined(LWS_WITH_FILE_OPS)
637 static lws_fop_flags_t
lws_vfs_prepare_flags(struct lws * wsi)638 lws_vfs_prepare_flags(struct lws *wsi)
639 {
640 	lws_fop_flags_t f = 0;
641 
642 	if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING))
643 		return f;
644 
645 	if (strstr(lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING),
646 		   "gzip")) {
647 		lwsl_info("client indicates GZIP is acceptable\n");
648 		f |= LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP;
649 	}
650 
651 	return f;
652 }
653 
654 static int
lws_http_serve(struct lws * wsi,char * uri,const char * origin,const struct lws_http_mount * m)655 lws_http_serve(struct lws *wsi, char *uri, const char *origin,
656 	       const struct lws_http_mount *m)
657 {
658 	const struct lws_protocol_vhost_options *pvo = m->interpret;
659 	struct lws_process_html_args args;
660 	const char *mimetype;
661 #if !defined(_WIN32_WCE)
662 	const struct lws_plat_file_ops *fops;
663 	const char *vpath;
664 	lws_fop_flags_t fflags = LWS_O_RDONLY;
665 #if defined(WIN32) && defined(LWS_HAVE__STAT32I64)
666 	struct _stat32i64 st;
667 #else
668 	struct stat st;
669 #endif
670 	int spin = 0;
671 #endif
672 	char path[256], sym[2048];
673 	unsigned char *p = (unsigned char *)sym + 32 + LWS_PRE, *start = p;
674 	unsigned char *end = p + sizeof(sym) - 32 - LWS_PRE;
675 #if !defined(WIN32) && !defined(LWS_PLAT_FREERTOS)
676 	size_t len;
677 #endif
678 	int n;
679 
680 	wsi->handling_404 = 0;
681 	if (!wsi->a.vhost)
682 		return -1;
683 
684 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
685 	if (wsi->a.vhost->http.error_document_404 &&
686 	    !strcmp(uri, wsi->a.vhost->http.error_document_404))
687 		wsi->handling_404 = 1;
688 #endif
689 
690 	lws_snprintf(path, sizeof(path) - 1, "%s/%s", origin, uri);
691 
692 #if !defined(_WIN32_WCE)
693 
694 	fflags |= lws_vfs_prepare_flags(wsi);
695 
696 	do {
697 		spin++;
698 		fops = lws_vfs_select_fops(wsi->a.context->fops, path, &vpath);
699 
700 		if (wsi->http.fop_fd)
701 			lws_vfs_file_close(&wsi->http.fop_fd);
702 
703 		wsi->http.fop_fd = fops->LWS_FOP_OPEN(wsi->a.context->fops,
704 							path, vpath, &fflags);
705 		if (!wsi->http.fop_fd) {
706 			lwsl_info("%s: Unable to open '%s': errno %d\n",
707 				  __func__, path, errno);
708 
709 			return 1;
710 		}
711 
712 		/* if it can't be statted, don't try */
713 		if (fflags & LWS_FOP_FLAG_VIRTUAL)
714 			break;
715 #if defined(LWS_PLAT_FREERTOS)
716 		break;
717 #endif
718 #if !defined(WIN32)
719 		if (fstat(wsi->http.fop_fd->fd, &st)) {
720 			lwsl_info("unable to stat %s\n", path);
721 			goto notfound;
722 		}
723 #else
724 #if defined(LWS_HAVE__STAT32I64)
725 		{
726 			WCHAR buf[MAX_PATH];
727 			MultiByteToWideChar(CP_UTF8, 0, path, -1, buf, LWS_ARRAY_SIZE(buf));
728 			if (_wstat32i64(buf, &st)) {
729 				lwsl_info("unable to stat %s\n", path);
730 				goto notfound;
731 			}
732 		}
733 #else
734 		if (stat(path, &st)) {
735 			lwsl_info("unable to stat %s\n", path);
736 			goto notfound;
737 		}
738 #endif
739 #endif
740 
741 		wsi->http.fop_fd->mod_time = (uint32_t)st.st_mtime;
742 		fflags |= LWS_FOP_FLAG_MOD_TIME_VALID;
743 
744 #if !defined(WIN32) && !defined(LWS_PLAT_FREERTOS)
745 		if ((S_IFMT & st.st_mode) == S_IFLNK) {
746 			len = (size_t)readlink(path, sym, sizeof(sym) - 1);
747 			if (len) {
748 				lwsl_err("Failed to read link %s\n", path);
749 				goto notfound;
750 			}
751 			sym[len] = '\0';
752 			lwsl_debug("symlink %s -> %s\n", path, sym);
753 			lws_snprintf(path, sizeof(path) - 1, "%s", sym);
754 		}
755 #endif
756 		if ((S_IFMT & st.st_mode) == S_IFDIR) {
757 			lwsl_debug("default filename append to dir\n");
758 			lws_snprintf(path, sizeof(path) - 1, "%s/%s/%s",
759 				 origin, uri, m->def ? m->def : "index.html");
760 		}
761 
762 	} while ((S_IFMT & st.st_mode) != S_IFREG && spin < 5);
763 
764 	if (spin == 5)
765 		lwsl_err("symlink loop %s \n", path);
766 
767 	n = sprintf(sym, "%08llX%08lX",
768 		    (unsigned long long)lws_vfs_get_length(wsi->http.fop_fd),
769 		    (unsigned long)lws_vfs_get_mod_time(wsi->http.fop_fd));
770 
771 	/* disable ranges if IF_RANGE token invalid */
772 
773 	if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_IF_RANGE))
774 		if (strcmp(sym, lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_IF_RANGE)))
775 			/* differs - defeat Range: */
776 			wsi->http.ah->frag_index[WSI_TOKEN_HTTP_RANGE] = 0;
777 
778 	if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_IF_NONE_MATCH)) {
779 		/*
780 		 * he thinks he has some version of it already,
781 		 * check if the tag matches
782 		 */
783 		if (!strcmp(sym, lws_hdr_simple_ptr(wsi,
784 					WSI_TOKEN_HTTP_IF_NONE_MATCH))) {
785 
786 			char cache_control[50], *cc = "no-store";
787 			int cclen = 8;
788 
789 			lwsl_debug("%s: ETAG match %s %s\n", __func__,
790 				   uri, origin);
791 
792 			/* we don't need to send the payload */
793 			if (lws_add_http_header_status(wsi,
794 					HTTP_STATUS_NOT_MODIFIED, &p, end)) {
795 				lwsl_err("%s: failed adding not modified\n",
796 						__func__);
797 				return -1;
798 			}
799 
800 			if (lws_add_http_header_by_token(wsi,
801 					WSI_TOKEN_HTTP_ETAG,
802 					(unsigned char *)sym, n, &p, end))
803 				return -1;
804 
805 			/* but we still need to send cache control... */
806 
807 			if (m->cache_max_age && m->cache_reusable) {
808 				if (!m->cache_revalidate) {
809 					cc = cache_control;
810 					cclen = sprintf(cache_control,
811 						"%s, max-age=%u",
812 						intermediates[wsi->cache_intermediaries],
813 						m->cache_max_age);
814 				} else {
815 					cc = cache_control;
816                                         cclen = sprintf(cache_control,
817                                         	"must-revalidate, %s, max-age=%u",
818                                                 intermediates[wsi->cache_intermediaries],
819                                                 m->cache_max_age);
820 				}
821 			}
822 
823 			if (lws_add_http_header_by_token(wsi,
824 					WSI_TOKEN_HTTP_CACHE_CONTROL,
825 					(unsigned char *)cc, cclen, &p, end))
826 				return -1;
827 
828 			if (lws_finalize_http_header(wsi, &p, end))
829 				return -1;
830 
831 			n = lws_write(wsi, start, lws_ptr_diff_size_t(p, start),
832 				      LWS_WRITE_HTTP_HEADERS |
833 				      LWS_WRITE_H2_STREAM_END);
834 			if (n != lws_ptr_diff(p, start)) {
835 				lwsl_err("_write returned %d from %ld\n", n,
836 					 (long)(p - start));
837 				return -1;
838 			}
839 
840 			lws_vfs_file_close(&wsi->http.fop_fd);
841 
842 			if (lws_http_transaction_completed(wsi))
843 				return -1;
844 
845 			return 0;
846 		}
847 	}
848 
849 	if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ETAG,
850 			(unsigned char *)sym, n, &p, end))
851 		return -1;
852 #endif
853 
854 	mimetype = lws_get_mimetype(path, m);
855 	if (!mimetype) {
856 		lwsl_info("unknown mimetype for %s\n", path);
857 		if (lws_return_http_status(wsi,
858 				HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL) ||
859 		    lws_http_transaction_completed(wsi))
860 			return -1;
861 
862 		return 0;
863 	}
864 	if (!mimetype[0])
865 		lwsl_debug("sending no mimetype for %s\n", path);
866 
867 	wsi->sending_chunked = 0;
868 	wsi->interpreting = 0;
869 
870 	/*
871 	 * check if this is in the list of file suffixes to be interpreted by
872 	 * a protocol
873 	 */
874 	while (pvo) {
875 		n = (int)strlen(path);
876 		if (n > (int)strlen(pvo->name) &&
877 		    !strcmp(&path[(unsigned int)n - strlen(pvo->name)], pvo->name)) {
878 			wsi->interpreting = 1;
879 			if (!wsi->mux_substream)
880 				wsi->sending_chunked = 1;
881 
882 			wsi->protocol_interpret_idx = (char)(
883 				lws_vhost_name_to_protocol(wsi->a.vhost,
884 							   pvo->value) -
885 				&lws_get_vhost(wsi)->protocols[0]);
886 
887 			lwsl_debug("want %s interpreted by %s (pcol is %s)\n", path,
888 				    wsi->a.vhost->protocols[
889 				             (int)wsi->protocol_interpret_idx].name,
890 				             wsi->a.protocol->name);
891 			if (lws_bind_protocol(wsi, &wsi->a.vhost->protocols[
892 			          (int)wsi->protocol_interpret_idx], __func__))
893 				return -1;
894 
895 			if (lws_ensure_user_space(wsi))
896 				return -1;
897 			break;
898 		}
899 		pvo = pvo->next;
900 	}
901 
902 	if (wsi->sending_chunked) {
903 		if (lws_add_http_header_by_token(wsi,
904 				WSI_TOKEN_HTTP_TRANSFER_ENCODING,
905 				(unsigned char *)"chunked", 7,
906 				&p, end))
907 			return -1;
908 	}
909 
910 	if (m->protocol) {
911 		const struct lws_protocols *pp = lws_vhost_name_to_protocol(
912 						       wsi->a.vhost, m->protocol);
913 
914 		if (lws_bind_protocol(wsi, pp, __func__))
915 			return -1;
916 		args.p = (char *)p;
917 		args.max_len = lws_ptr_diff(end, p);
918 		if (pp->callback(wsi, LWS_CALLBACK_ADD_HEADERS,
919 					  wsi->user_space, &args, 0))
920 			return -1;
921 		p = (unsigned char *)args.p;
922 	}
923 
924 	*p = '\0';
925 	n = lws_serve_http_file(wsi, path, mimetype, (char *)start,
926 				lws_ptr_diff(p, start));
927 
928 	if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi)))
929 		return -1; /* error or can't reuse connection: close the socket */
930 
931 	return 0;
932 
933 notfound:
934 
935 	return 1;
936 }
937 #endif
938 
939 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
940 const struct lws_http_mount *
lws_find_mount(struct lws * wsi,const char * uri_ptr,int uri_len)941 lws_find_mount(struct lws *wsi, const char *uri_ptr, int uri_len)
942 {
943 	const struct lws_http_mount *hm, *hit = NULL;
944 	int best = 0;
945 
946 	hm = wsi->a.vhost->http.mount_list;
947 	while (hm) {
948 		if (uri_len >= hm->mountpoint_len &&
949 		    !strncmp(uri_ptr, hm->mountpoint, hm->mountpoint_len) &&
950 		    (uri_ptr[hm->mountpoint_len] == '\0' ||
951 		     uri_ptr[hm->mountpoint_len] == '/' ||
952 		     hm->mountpoint_len == 1)
953 		    ) {
954 #if defined(LWS_WITH_SYS_METRICS)
955 			lws_metrics_tag_wsi_add(wsi, "mnt", hm->mountpoint);
956 #endif
957 
958 			if (hm->origin_protocol == LWSMPRO_CALLBACK ||
959 			    ((hm->origin_protocol == LWSMPRO_CGI ||
960 			     lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) ||
961 			     lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) ||
962 #if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
963 			     lws_hdr_total_length(wsi, WSI_TOKEN_PUT_URI) ||
964 			     lws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI) ||
965 			     lws_hdr_total_length(wsi, WSI_TOKEN_DELETE_URI) ||
966 #endif
967 			     lws_hdr_total_length(wsi, WSI_TOKEN_HEAD_URI) ||
968 #if defined(LWS_ROLE_H2)
969 			     (wsi->mux_substream &&
970 				lws_hdr_total_length(wsi,
971 						WSI_TOKEN_HTTP_COLON_PATH)) ||
972 #endif
973 			     hm->protocol) &&
974 			    hm->mountpoint_len > best)) {
975 				best = hm->mountpoint_len;
976 				hit = hm;
977 			}
978 		}
979 		hm = hm->mount_next;
980 	}
981 
982 	return hit;
983 }
984 #endif
985 
986 #if defined(LWS_WITH_HTTP_BASIC_AUTH) && !defined(LWS_PLAT_FREERTOS) && defined(LWS_WITH_FILE_OPS)
987 static int
lws_find_string_in_file(const char * filename,const char * string,int stringlen)988 lws_find_string_in_file(const char *filename, const char *string, int stringlen)
989 {
990 	char buf[128];
991 	int fd, match = 0, pos = 0, n = 0, hit = 0;
992 
993 	fd = lws_open(filename, O_RDONLY);
994 	if (fd < 0) {
995 		lwsl_err("can't open auth file: %s\n", filename);
996 		return 0;
997 	}
998 
999 	while (1) {
1000 		if (pos == n) {
1001 			n = (int)read(fd, buf, sizeof(buf));
1002 			if (n <= 0) {
1003 				if (match == stringlen)
1004 					hit = 1;
1005 				break;
1006 			}
1007 			pos = 0;
1008 		}
1009 
1010 		if (match == stringlen) {
1011 			if (buf[pos] == '\r' || buf[pos] == '\n') {
1012 				hit = 1;
1013 				break;
1014 			}
1015 			match = 0;
1016 		}
1017 
1018 		if (buf[pos] == string[match])
1019 			match++;
1020 		else
1021 			match = 0;
1022 
1023 		pos++;
1024 	}
1025 
1026 	close(fd);
1027 
1028 	return hit;
1029 }
1030 #endif
1031 
1032 #if defined(LWS_WITH_HTTP_BASIC_AUTH)
1033 
1034 int
lws_unauthorised_basic_auth(struct lws * wsi)1035 lws_unauthorised_basic_auth(struct lws *wsi)
1036 {
1037 	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
1038 	unsigned char *start = pt->serv_buf + LWS_PRE,
1039 		      *p = start, *end = p + 2048;
1040 	char buf[64];
1041 	int n;
1042 
1043 	/* no auth... tell him it is required */
1044 
1045 	if (lws_add_http_header_status(wsi, HTTP_STATUS_UNAUTHORIZED, &p, end))
1046 		return -1;
1047 
1048 	n = lws_snprintf(buf, sizeof(buf), "Basic realm=\"lwsws\"");
1049 	if (lws_add_http_header_by_token(wsi,
1050 			WSI_TOKEN_HTTP_WWW_AUTHENTICATE,
1051 			(unsigned char *)buf, n, &p, end))
1052 		return -1;
1053 
1054 	if (lws_add_http_header_content_length(wsi, 0, &p, end))
1055 		return -1;
1056 
1057 	if (lws_finalize_http_header(wsi, &p, end))
1058 		return -1;
1059 
1060 	n = lws_write(wsi, start, lws_ptr_diff_size_t(p, start), LWS_WRITE_HTTP_HEADERS |
1061 					     LWS_WRITE_H2_STREAM_END);
1062 	if (n < 0)
1063 		return -1;
1064 
1065 	return lws_http_transaction_completed(wsi);
1066 
1067 }
1068 
1069 #endif
1070 
lws_clean_url(char * p)1071 int lws_clean_url(char *p)
1072 {
1073 	if (p[0] == 'h' && p[1] == 't' && p[2] == 't' && p[3] == 'p') {
1074 		p += 4;
1075 		if (*p == 's')
1076 		p++;
1077 		if (*p == ':') {
1078 			p++;
1079 			if (*p == '/')
1080 			p++;
1081 		}
1082 	}
1083 
1084 	while (*p) {
1085 		if (p[0] == '/' && p[1] == '/') {
1086 			char *p1 = p;
1087 			while (*p1) {
1088 				*p1 = p1[1];
1089 				p1++;
1090 			}
1091 			continue;
1092 		}
1093 		p++;
1094 	}
1095 
1096 	return 0;
1097 }
1098 
1099 static const unsigned char methods[] = {
1100 	WSI_TOKEN_GET_URI,
1101 	WSI_TOKEN_POST_URI,
1102 #if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
1103 	WSI_TOKEN_OPTIONS_URI,
1104 	WSI_TOKEN_PUT_URI,
1105 	WSI_TOKEN_PATCH_URI,
1106 	WSI_TOKEN_DELETE_URI,
1107 #endif
1108 	WSI_TOKEN_CONNECT,
1109 	WSI_TOKEN_HEAD_URI,
1110 #ifdef LWS_WITH_HTTP2
1111 	WSI_TOKEN_HTTP_COLON_PATH,
1112 #endif
1113 };
1114 
1115 int
lws_http_get_uri_and_method(struct lws * wsi,char ** puri_ptr,int * puri_len)1116 lws_http_get_uri_and_method(struct lws *wsi, char **puri_ptr, int *puri_len)
1117 {
1118 	int n, count = 0;
1119 
1120 	for (n = 0; n < (int)LWS_ARRAY_SIZE(methods); n++)
1121 		if (lws_hdr_total_length(wsi, methods[n]))
1122 			count++;
1123 	if (!count) {
1124 		lwsl_warn("Missing URI in HTTP request\n");
1125 		return -1;
1126 	}
1127 
1128 	if (count != 1 &&
1129 	    !((wsi->mux_substream || wsi->h2_stream_carries_ws)
1130 #if defined(LWS_ROLE_H2)
1131 			    &&
1132 	      lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH)
1133 #endif
1134 	      )) {
1135 		lwsl_warn("multiple methods?\n");
1136 		return -1;
1137 	}
1138 
1139 	for (n = 0; n < (int)LWS_ARRAY_SIZE(methods); n++)
1140 		if (lws_hdr_total_length(wsi, methods[n])) {
1141 			*puri_ptr = lws_hdr_simple_ptr(wsi, methods[n]);
1142 			*puri_len = lws_hdr_total_length(wsi, methods[n]);
1143 			return n;
1144 		}
1145 
1146 	return -1;
1147 }
1148 
1149 #if defined(LWS_WITH_HTTP_BASIC_AUTH)
1150 
1151 enum lws_check_basic_auth_results
lws_check_basic_auth(struct lws * wsi,const char * basic_auth_login_file,unsigned int auth_mode)1152 lws_check_basic_auth(struct lws *wsi, const char *basic_auth_login_file,
1153 		     unsigned int auth_mode)
1154 {
1155 #if defined(LWS_WITH_FILE_OPS)
1156 	char b64[160], plain[(sizeof(b64) * 3) / 4], *pcolon;
1157 	int m, ml, fi, bar;
1158 
1159 	if (!basic_auth_login_file && auth_mode == LWSAUTHM_DEFAULT)
1160 		return LCBA_CONTINUE;
1161 
1162 	/* Did he send auth? */
1163 	ml = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_AUTHORIZATION);
1164 	if (!ml)
1165 		return LCBA_FAILED_AUTH;
1166 
1167 	/* Disallow fragmentation monkey business */
1168 
1169 	fi = wsi->http.ah->frag_index[WSI_TOKEN_HTTP_AUTHORIZATION];
1170 	if (wsi->http.ah->frags[fi].nfrag) {
1171 		lwsl_err("fragmented basic auth header not allowed\n");
1172 		return LCBA_FAILED_AUTH;
1173 	}
1174 
1175 	m = lws_hdr_copy(wsi, b64, sizeof(b64),
1176 			 WSI_TOKEN_HTTP_AUTHORIZATION);
1177 	if (m < 7) {
1178 		lwsl_err("b64 auth too long\n");
1179 		return LCBA_END_TRANSACTION;
1180 	}
1181 
1182 	b64[5] = '\0';
1183 	if (strcasecmp(b64, "Basic")) {
1184 		lwsl_err("auth missing basic: %s\n", b64);
1185 		return LCBA_END_TRANSACTION;
1186 	}
1187 
1188 	/* It'll be like Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l */
1189 
1190 	m = lws_b64_decode_string(b64 + 6, plain, sizeof(plain) - 1);
1191 	if (m < 0) {
1192 		lwsl_err("plain auth too long\n");
1193 		return LCBA_END_TRANSACTION;
1194 	}
1195 
1196 	plain[m] = '\0';
1197 	pcolon = strchr(plain, ':');
1198 	if (!pcolon) {
1199 		lwsl_err("basic auth format broken\n");
1200 		return LCBA_END_TRANSACTION;
1201 	}
1202 
1203 	switch (auth_mode) {
1204 	case LWSAUTHM_DEFAULT:
1205 		if (lws_find_string_in_file(basic_auth_login_file, plain, m))
1206 			break;
1207 		lwsl_err("%s: basic auth lookup failed\n", __func__);
1208 		return LCBA_FAILED_AUTH;
1209 
1210 	case LWSAUTHM_BASIC_AUTH_CALLBACK:
1211 		bar = wsi->a.protocol->callback(wsi,
1212 				LWS_CALLBACK_VERIFY_BASIC_AUTHORIZATION,
1213 				wsi->user_space, plain, (unsigned int)m);
1214 		if (!bar)
1215 			return LCBA_FAILED_AUTH;
1216 		break;
1217 	default:
1218 		/* Invalid auth mode so lets fail all authentication attempts */
1219 		return LCBA_FAILED_AUTH;
1220 	}
1221 
1222 	/*
1223 	 * Rewrite WSI_TOKEN_HTTP_AUTHORIZATION so it is just the
1224 	 * authorized username
1225 	 */
1226 
1227 	*pcolon = '\0';
1228 	wsi->http.ah->frags[fi].len = (uint16_t)lws_ptr_diff_size_t(pcolon, &plain[0]);
1229 	pcolon = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_AUTHORIZATION);
1230 	strncpy(pcolon, plain, (unsigned int)(ml - 1));
1231 	pcolon[ml - 1] = '\0';
1232 	lwsl_info("%s: basic auth accepted for %s\n", __func__,
1233 		 lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_AUTHORIZATION));
1234 
1235 	return LCBA_CONTINUE;
1236 #else
1237 	if (!basic_auth_login_file && auth_mode == LWSAUTHM_DEFAULT)
1238 		return LCBA_CONTINUE;
1239 	return LCBA_FAILED_AUTH;
1240 #endif
1241 }
1242 
1243 #endif
1244 
1245 #if defined(LWS_WITH_HTTP_PROXY)
1246 /*
1247  * Set up an onward http proxy connection according to the mount this
1248  * uri falls under.  Notice this can also be starting the proxying of what was
1249  * originally an incoming h1 upgrade, or an h2 ws "upgrade".
1250  */
1251 int
lws_http_proxy_start(struct lws * wsi,const struct lws_http_mount * hit,char * uri_ptr,char ws)1252 lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit,
1253 		     char *uri_ptr, char ws)
1254 {
1255 	char ads[96], host[96], *pcolon, *pslash, unix_skt = 0;
1256 	struct lws_client_connect_info i;
1257 	struct lws *cwsi;
1258 	int n, na;
1259 	unsigned int max_http_header_data = wsi->a.context->max_http_header_data > 256 ?
1260 					    wsi->a.context->max_http_header_data : 256;
1261 	char *rpath = NULL;
1262 
1263 #if defined(LWS_ROLE_WS)
1264 	if (ws)
1265 		/*
1266 		 * Neither our inbound ws upgrade request side, nor our onward
1267 		 * ws client connection on our side can bind to the actual
1268 		 * protocol that only the remote inbound side and the remote
1269 		 * onward side understand.
1270 		 *
1271 		 * Instead these are both bound to our built-in "lws-ws-proxy"
1272 		 * protocol, which understands how to proxy between the two
1273 		 * sides.
1274 		 *
1275 		 * We bind the parent, inbound part here and our side of the
1276 		 * onward client connection is bound to the same handler using
1277 		 * the .local_protocol_name.
1278 		 */
1279 		lws_bind_protocol(wsi, &lws_ws_proxy, __func__);
1280 #endif
1281 	memset(&i, 0, sizeof(i));
1282 	i.context = lws_get_context(wsi);
1283 
1284 	if (hit->origin[0] == '+')
1285 		unix_skt = 1;
1286 
1287 	pcolon = strchr(hit->origin, ':');
1288 	pslash = strchr(hit->origin, '/');
1289 	if (!pslash) {
1290 		lwsl_err("Proxy mount origin '%s' must have /\n", hit->origin);
1291 		return -1;
1292 	}
1293 
1294 	if (unix_skt) {
1295 		if (!pcolon) {
1296 			lwsl_err("Proxy mount origin for unix skt must "
1297 				 "have address delimited by :\n");
1298 
1299 			return -1;
1300 		}
1301 		n = lws_ptr_diff(pcolon, hit->origin);
1302 		pslash = pcolon;
1303 	} else {
1304 		if (pcolon > pslash)
1305 			pcolon = NULL;
1306 
1307 		if (pcolon)
1308 			n = (int)(pcolon - hit->origin);
1309 		else
1310 			n = (int)(pslash - hit->origin);
1311 
1312 		if (n >= (int)sizeof(ads) - 2)
1313 			n = sizeof(ads) - 2;
1314 	}
1315 
1316 	memcpy(ads, hit->origin, (unsigned int)n);
1317 	ads[n] = '\0';
1318 
1319 	i.address = ads;
1320 	i.port = 80;
1321 	if (hit->origin_protocol == LWSMPRO_HTTPS) {
1322 		i.port = 443;
1323 		i.ssl_connection = 1;
1324 	}
1325 	if (pcolon)
1326 		i.port = atoi(pcolon + 1);
1327 
1328 	rpath = lws_malloc(max_http_header_data, __func__);
1329 	if (!rpath)
1330 		return -1;
1331 
1332 	/* rpath needs cleaning after this... ---> */
1333 
1334 	n = lws_snprintf(rpath, max_http_header_data - 1, "/%s/%s",
1335 			 pslash + 1, uri_ptr + hit->mountpoint_len) - 1;
1336 	lws_clean_url(rpath);
1337 	n = (int)strlen(rpath);
1338 	if (n && rpath[n - 1] == '/')
1339 		n--;
1340 
1341 	na = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_URI_ARGS);
1342 	if (na) {
1343 		char *p;
1344 		int budg;
1345 
1346 		if (!n) /* don't start with the ?... use the first / if so */
1347 			n++;
1348 
1349 		p = rpath + n;
1350 
1351 		if (na >= (int)max_http_header_data - n - 2) {
1352 			lwsl_info("%s: query string %d longer "
1353 				  "than we can handle\n", __func__,
1354 				  na);
1355 			lws_free(rpath);
1356 			return -1;
1357 		}
1358 
1359 		*p++ = '?';
1360 		budg = lws_hdr_copy(wsi, p,
1361 			     (int)(&rpath[max_http_header_data - 1] - p),
1362 			     WSI_TOKEN_HTTP_URI_ARGS);
1363 	       if (budg > 0)
1364 		       p += budg;
1365 
1366 		*p = '\0';
1367 	}
1368 
1369 	i.path = rpath;
1370 	lwsl_notice("%s: proxied path '%s'\n", __func__, i.path);
1371 
1372 	/* incoming may be h1 or h2... if he sends h1 HOST, use that
1373 	 * directly, otherwise we must convert h2 :authority to h1
1374 	 * host */
1375 
1376 	i.host = NULL;
1377 #if defined(LWS_ROLE_H2)
1378 	n = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_AUTHORITY);
1379 	if (n > 0)
1380 		i.host = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_AUTHORITY);
1381 	else
1382 #endif
1383 	{
1384 		n = lws_hdr_total_length(wsi, WSI_TOKEN_HOST);
1385 		if (n > 0)
1386 			i.host = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST);
1387 	}
1388 
1389 #if 0
1390 	if (i.address[0] != '+' ||
1391 	    !lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST))
1392 		i.host = i.address;
1393 	else
1394 		i.host = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST);
1395 #endif
1396 	i.origin = NULL;
1397 	if (!ws) {
1398 		if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_POST_URI)
1399 #if defined(LWS_WITH_HTTP2)
1400 								|| (
1401 			lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD) &&
1402 			!strcmp(lws_hdr_simple_ptr(wsi,
1403 					WSI_TOKEN_HTTP_COLON_METHOD), "post")
1404 			)
1405 #endif
1406 		)
1407 			i.method = "POST";
1408 		else if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PUT_URI)
1409 #if defined(LWS_WITH_HTTP2)
1410 								|| (
1411 			lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD) &&
1412 			!strcmp(lws_hdr_simple_ptr(wsi,
1413 					WSI_TOKEN_HTTP_COLON_METHOD), "put")
1414 			)
1415 #endif
1416 		)
1417 			i.method = "PUT";
1418 		else if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PATCH_URI)
1419 #if defined(LWS_WITH_HTTP2)
1420 								|| (
1421 			lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD) &&
1422 			!strcmp(lws_hdr_simple_ptr(wsi,
1423 					WSI_TOKEN_HTTP_COLON_METHOD), "patch")
1424 			)
1425 #endif
1426 		)
1427 			i.method = "PATCH";
1428 		else if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_DELETE_URI)
1429 #if defined(LWS_WITH_HTTP2)
1430 								|| (
1431 			lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD) &&
1432 			!strcmp(lws_hdr_simple_ptr(wsi,
1433 					WSI_TOKEN_HTTP_COLON_METHOD), "delete")
1434 			)
1435 #endif
1436 		)
1437 			i.method = "DELETE";
1438 		else
1439 			i.method = "GET";
1440 	}
1441 
1442 	if (i.host)
1443 		lws_snprintf(host, sizeof(host), "%s:%u", i.host,
1444 					wsi->a.vhost->listen_port);
1445 	else
1446 		lws_snprintf(host, sizeof(host), "%s:%d", i.address, i.port);
1447 
1448 	i.host = host;
1449 
1450 	i.alpn = "http/1.1";
1451 	i.parent_wsi = wsi;
1452 	i.pwsi = &cwsi;
1453 #if defined(LWS_ROLE_WS)
1454 	i.protocol = lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL);
1455 	if (ws)
1456 		i.local_protocol_name = "lws-ws-proxy";
1457 #endif
1458 
1459 //	i.uri_replace_from = hit->origin;
1460 //	i.uri_replace_to = hit->mountpoint;
1461 
1462 	lwsl_info("proxying to %s port %d url %s, ssl %d, from %s, to %s\n",
1463 		   i.address, i.port, i.path, i.ssl_connection,
1464 		   i.uri_replace_from, i.uri_replace_to);
1465 
1466 	if (!lws_client_connect_via_info(&i)) {
1467 		lwsl_err("proxy connect fail\n");
1468 
1469 		/*
1470 		 * ... we can't do the proxy action, but we can
1471 		 * cleanly return him a 503 and a description
1472 		 */
1473 
1474 		lws_return_http_status(wsi,
1475 			HTTP_STATUS_SERVICE_UNAVAILABLE,
1476 			"<h1>Service Temporarily Unavailable</h1>"
1477 			"The server is temporarily unable to service "
1478 			"your request due to maintenance downtime or "
1479 			"capacity problems. Please try again later.");
1480 		lws_free(rpath);
1481 		return 1;
1482 	}
1483 	lws_free(rpath);
1484 
1485 	lwsl_info("%s: setting proxy clientside on %s (parent %s)\n",
1486 		  __func__, lws_wsi_tag(cwsi), lws_wsi_tag(lws_get_parent(cwsi)));
1487 
1488 	cwsi->http.proxy_clientside = 1;
1489 	if (ws) {
1490 		wsi->proxied_ws_parent = 1;
1491 		cwsi->h1_ws_proxied = 1;
1492 		if (i.protocol) {
1493 			lwsl_debug("%s: (requesting '%s')\n",
1494 					__func__, i.protocol);
1495 		}
1496 	}
1497 
1498 	return 0;
1499 }
1500 #endif
1501 
1502 
1503 static const char * const oprot[] = {
1504 	"http://", "https://"
1505 };
1506 
1507 
1508 static int
lws_http_redirect_hit(struct lws_context_per_thread * pt,struct lws * wsi,const struct lws_http_mount * hit,char * uri_ptr,int uri_len,int * h)1509 lws_http_redirect_hit(struct lws_context_per_thread *pt, struct lws *wsi,
1510 		      const struct lws_http_mount *hit, char *uri_ptr,
1511 		      int uri_len, int *h)
1512 {
1513 	char *s;
1514 	int n;
1515 
1516 	*h = 0;
1517 	s = uri_ptr + hit->mountpoint_len;
1518 
1519 	/*
1520 	 * if we have a mountpoint like https://xxx.com/yyy
1521 	 * there is an implied / at the end for our purposes since
1522 	 * we can only mount on a "directory".
1523 	 *
1524 	 * But if we just go with that, the browser cannot understand
1525 	 * that he is actually looking down one "directory level", so
1526 	 * even though we give him /yyy/abc.html he acts like the
1527 	 * current directory level is /.  So relative urls like "x.png"
1528 	 * wrongly look outside the mountpoint.
1529 	 *
1530 	 * Therefore if we didn't come in on a url with an explicit
1531 	 * / at the end, we must redirect to add it so the browser
1532 	 * understands he is one "directory level" down.
1533 	 */
1534 	if ((hit->mountpoint_len > 1 ||
1535 	     (hit->origin_protocol == LWSMPRO_REDIR_HTTP ||
1536 	      hit->origin_protocol == LWSMPRO_REDIR_HTTPS)) &&
1537 	    (*s != '/' ||
1538 	     (hit->origin_protocol == LWSMPRO_REDIR_HTTP ||
1539 	      hit->origin_protocol == LWSMPRO_REDIR_HTTPS)) &&
1540 	    (hit->origin_protocol != LWSMPRO_CGI &&
1541 	     hit->origin_protocol != LWSMPRO_CALLBACK)) {
1542 		unsigned char *start = pt->serv_buf + LWS_PRE, *p = start,
1543 			      *end = p + wsi->a.context->pt_serv_buf_size -
1544 					LWS_PRE - 512;
1545 
1546 		*h = 1;
1547 
1548 		lwsl_info("Doing 301 '%s' org %s\n", s, hit->origin);
1549 
1550 		/* > at start indicates deal with by redirect */
1551 		if (hit->origin_protocol == LWSMPRO_REDIR_HTTP ||
1552 		    hit->origin_protocol == LWSMPRO_REDIR_HTTPS)
1553 			n = lws_snprintf((char *)end, 256, "%s%s",
1554 				    oprot[hit->origin_protocol & 1],
1555 				    hit->origin);
1556 		else {
1557 			if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {
1558 #if defined(LWS_ROLE_H2)
1559 				if (!lws_hdr_total_length(wsi,
1560 						WSI_TOKEN_HTTP_COLON_AUTHORITY))
1561 #endif
1562 					goto bail_nuke_ah;
1563 #if defined(LWS_ROLE_H2)
1564 				n = lws_snprintf((char *)end, 256,
1565 				    "%s%s%s/", oprot[!!lws_is_ssl(wsi)],
1566 				    lws_hdr_simple_ptr(wsi,
1567 						WSI_TOKEN_HTTP_COLON_AUTHORITY),
1568 				    uri_ptr);
1569 #else
1570 				;
1571 #endif
1572 			} else
1573 				n = lws_snprintf((char *)end, 256,
1574 				    "%s%s%s/", oprot[!!lws_is_ssl(wsi)],
1575 				    lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST),
1576 				    uri_ptr);
1577 		}
1578 
1579 		lws_clean_url((char *)end);
1580 		n = lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,
1581 				      end, n, &p, end);
1582 		if ((int)n < 0)
1583 			goto bail_nuke_ah;
1584 
1585 		return lws_http_transaction_completed(wsi);
1586 	}
1587 
1588 	return 0;
1589 
1590 bail_nuke_ah:
1591 	lws_header_table_detach(wsi, 1);
1592 
1593 	return 1;
1594 }
1595 
1596 int
lws_http_action(struct lws * wsi)1597 lws_http_action(struct lws *wsi)
1598 {
1599 	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
1600 	int uri_len = 0, meth, m, http_version_len, ha;
1601 	const struct lws_http_mount *hit = NULL;
1602 	enum http_version request_version;
1603 	struct lws_process_html_args args;
1604 	enum http_conn_type conn_type;
1605 	char content_length_str[32];
1606 	char http_version_str[12];
1607 	char http_conn_str[25];
1608 	char *uri_ptr = NULL;
1609 #if defined(LWS_WITH_FILE_OPS)
1610 	char *s;
1611 #endif
1612 	unsigned int n;
1613 
1614 	meth = lws_http_get_uri_and_method(wsi, &uri_ptr, &uri_len);
1615 	if (meth < 0 || meth >= (int)LWS_ARRAY_SIZE(method_names))
1616 		goto bail_nuke_ah;
1617 
1618 	lws_metrics_tag_wsi_add(wsi, "vh", wsi->a.vhost->name);
1619 	lws_metrics_tag_wsi_add(wsi, "meth", method_names[meth]);
1620 
1621 	/* we insist on absolute paths */
1622 
1623 	if (!uri_ptr || uri_ptr[0] != '/') {
1624 		lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
1625 
1626 		goto bail_nuke_ah;
1627 	}
1628 
1629 	lwsl_info("Method: '%s' (%d), request for '%s'\n", method_names[meth],
1630 		  meth, uri_ptr);
1631 
1632 	if (wsi->role_ops &&
1633 	    lws_rops_fidx(wsi->role_ops, LWS_ROPS_check_upgrades))
1634 		switch (lws_rops_func_fidx(wsi->role_ops,
1635 					   LWS_ROPS_check_upgrades).
1636 							check_upgrades(wsi)) {
1637 		case LWS_UPG_RET_DONE:
1638 			return 0;
1639 		case LWS_UPG_RET_CONTINUE:
1640 			break;
1641 		case LWS_UPG_RET_BAIL:
1642 			goto bail_nuke_ah;
1643 		}
1644 
1645 	if (lws_ensure_user_space(wsi))
1646 		goto bail_nuke_ah;
1647 
1648 	/* HTTP header had a content length? */
1649 
1650 	wsi->http.rx_content_length = 0;
1651 	wsi->http.content_length_explicitly_zero = 0;
1652 	if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)
1653 #if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
1654 			||
1655 	    lws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI) ||
1656 	    lws_hdr_total_length(wsi, WSI_TOKEN_PUT_URI)
1657 #endif
1658 	    )
1659 		wsi->http.rx_content_length = 100 * 1024 * 1024;
1660 
1661 	if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH) &&
1662 	    lws_hdr_copy(wsi, content_length_str,
1663 			 sizeof(content_length_str) - 1,
1664 			 WSI_TOKEN_HTTP_CONTENT_LENGTH) > 0) {
1665 		wsi->http.rx_content_remain = wsi->http.rx_content_length =
1666 				(lws_filepos_t)atoll(content_length_str);
1667 		if (!wsi->http.rx_content_length) {
1668 			wsi->http.content_length_explicitly_zero = 1;
1669 			lwsl_debug("%s: explicit 0 content-length\n", __func__);
1670 		}
1671 	}
1672 
1673 	if (wsi->mux_substream) {
1674 		wsi->http.request_version = HTTP_VERSION_2;
1675 	} else {
1676 		/* http_version? Default to 1.0, override with token: */
1677 		request_version = HTTP_VERSION_1_0;
1678 
1679 		/* Works for single digit HTTP versions. : */
1680 		http_version_len = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP);
1681 		if (http_version_len > 7 &&
1682 		    lws_hdr_copy(wsi, http_version_str,
1683 				 sizeof(http_version_str) - 1,
1684 				 WSI_TOKEN_HTTP) > 0 &&
1685 		    http_version_str[5] == '1' && http_version_str[7] == '1')
1686 			request_version = HTTP_VERSION_1_1;
1687 
1688 		wsi->http.request_version = request_version;
1689 
1690 		/* HTTP/1.1 defaults to "keep-alive", 1.0 to "close" */
1691 		if (request_version == HTTP_VERSION_1_1)
1692 			conn_type = HTTP_CONNECTION_KEEP_ALIVE;
1693 		else
1694 			conn_type = HTTP_CONNECTION_CLOSE;
1695 
1696 		/* Override default if http "Connection:" header: */
1697 		if (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION) &&
1698 		    lws_hdr_copy(wsi, http_conn_str, sizeof(http_conn_str) - 1,
1699 				 WSI_TOKEN_CONNECTION) > 0) {
1700 			http_conn_str[sizeof(http_conn_str) - 1] = '\0';
1701 			if (!strcasecmp(http_conn_str, "keep-alive"))
1702 				conn_type = HTTP_CONNECTION_KEEP_ALIVE;
1703 			else
1704 				if (!strcasecmp(http_conn_str, "close"))
1705 					conn_type = HTTP_CONNECTION_CLOSE;
1706 		}
1707 		wsi->http.conn_type = conn_type;
1708 	}
1709 
1710 	n = (unsigned int)wsi->a.protocol->callback(wsi, LWS_CALLBACK_FILTER_HTTP_CONNECTION,
1711 				    wsi->user_space, uri_ptr, (unsigned int)uri_len);
1712 	if (n) {
1713 		lwsl_info("LWS_CALLBACK_HTTP closing\n");
1714 
1715 		return 1;
1716 	}
1717 	/*
1718 	 * if there is content supposed to be coming,
1719 	 * put a timeout on it having arrived
1720 	 */
1721 	if (!wsi->mux_stream_immortal)
1722 		lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,
1723 				(int)wsi->a.context->timeout_secs);
1724 #if defined(LWS_WITH_TLS)
1725 	if (wsi->tls.redirect_to_https) {
1726 		/*
1727 		 * We accepted http:// only so we could redirect to
1728 		 * https://, so issue the redirect.  Create the redirection
1729 		 * URI from the host: header, and regenerate the path part from
1730 		 * the parsed pieces
1731 		 */
1732 		unsigned char *start = pt->serv_buf + LWS_PRE, *p = start,
1733 			      *end = p + wsi->a.context->pt_serv_buf_size -
1734 				     LWS_PRE;
1735 
1736 		n = (unsigned int)lws_hdr_total_length(wsi, WSI_TOKEN_HOST);
1737 		if (!n || n > 128)
1738 			goto bail_nuke_ah;
1739 
1740 		if (!lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST))
1741 			goto bail_nuke_ah;
1742 
1743 		p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "https://");
1744 		memcpy(p, lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST), n);
1745 		p += n;
1746 		*p++ = '/';
1747 		if (uri_len >= lws_ptr_diff(end, p))
1748 			goto bail_nuke_ah;
1749 
1750 		if (uri_ptr[0])
1751 			p--;
1752 		memcpy(p, uri_ptr, (unsigned int)uri_len);
1753 		p += uri_len;
1754 
1755 		n = 0;
1756 		while (lws_hdr_copy_fragment(wsi, (char *)p + 1,
1757 					     lws_ptr_diff(end, p) - 2,
1758 					     WSI_TOKEN_HTTP_URI_ARGS, (int)n) > 0) {
1759 			*p = n ? '&' : '?';
1760 			p += strlen((char *)p);
1761 			if (p >= end - 2)
1762 				goto bail_nuke_ah;
1763 			n++;
1764 		}
1765 
1766 		n = (unsigned int)lws_ptr_diff(p, start);
1767 
1768 		p += LWS_PRE;
1769 		n = (unsigned int)lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,
1770 				      start, (int)n, &p, end);
1771 		if ((int)n < 0)
1772 			goto bail_nuke_ah;
1773 
1774 		return lws_http_transaction_completed(wsi);
1775 	}
1776 #endif
1777 
1778 #ifdef LWS_WITH_ACCESS_LOG
1779 	lws_prepare_access_log_info(wsi, uri_ptr, uri_len, meth);
1780 #endif
1781 
1782 	/* can we serve it from the mount list? */
1783 
1784 	hit = lws_find_mount(wsi, uri_ptr, uri_len);
1785 	if (!hit) {
1786 		/* deferred cleanup and reset to protocols[0] */
1787 
1788 		lwsl_info("no hit\n");
1789 
1790 		if (lws_bind_protocol(wsi, &wsi->a.vhost->protocols[0],
1791 				      "no mount hit"))
1792 			return 1;
1793 
1794 		lwsi_set_state(wsi, LRS_DOING_TRANSACTION);
1795 
1796 		m = wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP,
1797 				    wsi->user_space, uri_ptr, (unsigned int)uri_len);
1798 
1799 		goto after;
1800 	}
1801 
1802 #if defined(LWS_WITH_FILE_OPS)
1803 	s = uri_ptr + hit->mountpoint_len;
1804 #endif
1805 	n = (unsigned int)lws_http_redirect_hit(pt, wsi, hit, uri_ptr, uri_len, &ha);
1806 	if (ha)
1807 		return (int)n;
1808 
1809 #if defined(LWS_WITH_HTTP_BASIC_AUTH)
1810 
1811 	/* basic auth? */
1812 
1813 	switch (lws_check_basic_auth(wsi, hit->basic_auth_login_file,
1814 				     hit->auth_mask & AUTH_MODE_MASK)) {
1815 	case LCBA_CONTINUE:
1816 		break;
1817 	case LCBA_FAILED_AUTH:
1818 		return lws_unauthorised_basic_auth(wsi);
1819 	case LCBA_END_TRANSACTION:
1820 		lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
1821 		return lws_http_transaction_completed(wsi);
1822 	}
1823 #endif
1824 
1825 #if defined(LWS_WITH_HTTP_PROXY)
1826 	/*
1827 	 * The mount is a reverse proxy?
1828 	 */
1829 
1830 	// if (hit)
1831 	// lwsl_notice("%s: origin_protocol: %d\n", __func__, hit->origin_protocol);
1832 	//else
1833 	//	lwsl_notice("%s: no hit\n", __func__);
1834 
1835 	if (hit->origin_protocol == LWSMPRO_HTTPS ||
1836 	    hit->origin_protocol == LWSMPRO_HTTP) {
1837 		n = (unsigned int)lws_http_proxy_start(wsi, hit, uri_ptr, 0);
1838 		// lwsl_notice("proxy start says %d\n", n);
1839 		if (n)
1840 			return (int)n;
1841 
1842 		goto deal_body;
1843 	}
1844 #endif
1845 
1846 	/*
1847 	 * A particular protocol callback is mounted here?
1848 	 *
1849 	 * For the duration of this http transaction, bind us to the
1850 	 * associated protocol
1851 	 */
1852 	if (hit->origin_protocol == LWSMPRO_CALLBACK || hit->protocol) {
1853 		const struct lws_protocols *pp;
1854 		const char *name = hit->origin;
1855 		if (hit->protocol)
1856 			name = hit->protocol;
1857 
1858 		pp = lws_vhost_name_to_protocol(wsi->a.vhost, name);
1859 		if (!pp) {
1860 			lwsl_err("Unable to find plugin '%s'\n",
1861 				 name);
1862 			return 1;
1863 		}
1864 
1865 		if (lws_bind_protocol(wsi, pp, "http action CALLBACK bind"))
1866 			return 1;
1867 
1868 		lwsl_debug("%s: %s, checking access rights for mask 0x%x\n",
1869 				__func__, hit->origin, hit->auth_mask);
1870 
1871 		args.p = uri_ptr;
1872 		args.len = uri_len;
1873 		args.max_len = hit->auth_mask & ~AUTH_MODE_MASK;
1874 		args.final = 0; /* used to signal callback dealt with it */
1875 		args.chunked = 0;
1876 
1877 		n = (unsigned int)wsi->a.protocol->callback(wsi,
1878 					    LWS_CALLBACK_CHECK_ACCESS_RIGHTS,
1879 					    wsi->user_space, &args, 0);
1880 		if (n) {
1881 			lws_return_http_status(wsi, HTTP_STATUS_UNAUTHORIZED,
1882 					       NULL);
1883 			goto bail_nuke_ah;
1884 		}
1885 		if (args.final) /* callback completely handled it well */
1886 			return 0;
1887 
1888 		if (hit->cgienv && wsi->a.protocol->callback(wsi,
1889 				LWS_CALLBACK_HTTP_PMO,
1890 				wsi->user_space, (void *)hit->cgienv, 0))
1891 			return 1;
1892 
1893 		if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
1894 			m = wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP,
1895 					    wsi->user_space,
1896 					    uri_ptr + hit->mountpoint_len,
1897 					    (unsigned int)uri_len - hit->mountpoint_len);
1898 			goto after;
1899 		}
1900 	}
1901 
1902 #ifdef LWS_WITH_CGI
1903 	/* did we hit something with a cgi:// origin? */
1904 	if (hit->origin_protocol == LWSMPRO_CGI) {
1905 		const char *cmd[] = {
1906 			NULL, /* replace with cgi path */
1907 			NULL
1908 		};
1909 
1910 		lwsl_debug("%s: cgi\n", __func__);
1911 		cmd[0] = hit->origin;
1912 
1913 		n = 5;
1914 		if (hit->cgi_timeout)
1915 			n = (unsigned int)hit->cgi_timeout;
1916 
1917 		n = (unsigned int)lws_cgi(wsi, cmd, hit->mountpoint_len, (int)n,
1918 			    hit->cgienv);
1919 		if (n) {
1920 			lwsl_err("%s: cgi failed\n", __func__);
1921 			return -1;
1922 		}
1923 
1924 		goto deal_body;
1925 	}
1926 #endif
1927 
1928 #if defined(LWS_WITH_FILE_OPS)
1929 	n = (unsigned int)(uri_len - lws_ptr_diff(s, uri_ptr));
1930 	if (s[0] == '\0' || (n == 1 && s[n - 1] == '/'))
1931 		s = (char *)hit->def;
1932 	if (!s)
1933 		s = "index.html";
1934 #endif
1935 
1936 	wsi->cache_secs = (unsigned int)hit->cache_max_age;
1937 	wsi->cache_reuse = hit->cache_reusable;
1938 	wsi->cache_revalidate = hit->cache_revalidate;
1939 	wsi->cache_intermediaries = hit->cache_intermediaries;
1940 
1941 #if defined(LWS_WITH_FILE_OPS)
1942 	m = 1;
1943 	if (hit->origin_protocol == LWSMPRO_FILE)
1944 		m = lws_http_serve(wsi, s, hit->origin, hit);
1945 
1946 	if (m > 0)
1947 #endif
1948 	{
1949 		/*
1950 		 * lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
1951 		 */
1952 		if (hit->protocol) {
1953 			const struct lws_protocols *pp =
1954 					lws_vhost_name_to_protocol(
1955 						wsi->a.vhost, hit->protocol);
1956 
1957 			/* coverity */
1958 			if (!pp)
1959 				return 1;
1960 
1961 			lwsi_set_state(wsi, LRS_DOING_TRANSACTION);
1962 
1963 			if (lws_bind_protocol(wsi, pp, "http_action HTTP"))
1964 				return 1;
1965 
1966 			m = pp->callback(wsi, LWS_CALLBACK_HTTP,
1967 					 wsi->user_space,
1968 					 uri_ptr + hit->mountpoint_len,
1969 					 (size_t)(uri_len - hit->mountpoint_len));
1970 		} else
1971 			m = wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP,
1972 				    wsi->user_space, uri_ptr, (size_t)uri_len);
1973 	}
1974 
1975 after:
1976 	if (m) {
1977 		lwsl_info("LWS_CALLBACK_HTTP closing\n");
1978 
1979 		return 1;
1980 	}
1981 
1982 #if defined(LWS_WITH_CGI) || defined(LWS_WITH_HTTP_PROXY)
1983 deal_body:
1984 #endif
1985 	/*
1986 	 * If we're not issuing a file, check for content_length or
1987 	 * HTTP keep-alive. No keep-alive header allocation for
1988 	 * ISSUING_FILE, as this uses HTTP/1.0.
1989 	 *
1990 	 * In any case, return 0 and let lws_read decide how to
1991 	 * proceed based on state
1992 	 */
1993 	if (lwsi_state(wsi) == LRS_ISSUING_FILE)
1994 		return 0;
1995 
1996 	/* Prepare to read body if we have a content length: */
1997 	lwsl_debug("wsi->http.rx_content_length %lld %d %d\n",
1998 		   (long long)wsi->http.rx_content_length,
1999 		   wsi->upgraded_to_http2, wsi->mux_substream);
2000 
2001 	if (wsi->http.content_length_explicitly_zero &&
2002 	    lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
2003 
2004 		/*
2005 		 * POST with an explicit content-length of zero
2006 		 *
2007 		 * If we don't give the user code the empty HTTP_BODY callback,
2008 		 * he may become confused to hear the HTTP_BODY_COMPLETION (due
2009 		 * to, eg, instantiation of lws_spa never happened).
2010 		 *
2011 		 * HTTP_BODY_COMPLETION is responsible for sending the result
2012 		 * status code and result body if any, and to do the transaction
2013 		 * complete processing.
2014 		 */
2015 		if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP_BODY,
2016 					    wsi->user_space, NULL, 0))
2017 			return 1;
2018 		if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP_BODY_COMPLETION,
2019 					    wsi->user_space, NULL, 0))
2020 			return 1;
2021 
2022 		return 0;
2023 	}
2024 
2025 	if (wsi->http.rx_content_length <= 0)
2026 		return 0;
2027 
2028 	if (lwsi_state(wsi) != LRS_DISCARD_BODY) {
2029 		lwsi_set_state(wsi, LRS_BODY);
2030 		lwsl_info("%s: %s: LRS_BODY state set (0x%x)\n", __func__,
2031 			  lws_wsi_tag(wsi), (int)wsi->wsistate);
2032 	}
2033 	wsi->http.rx_content_remain = wsi->http.rx_content_length;
2034 
2035 	/*
2036 	 * At this point we have transitioned from deferred
2037 	 * action to expecting BODY on the stream wsi, if it's
2038 	 * in a bundle like h2.  So if the stream wsi has its
2039 	 * own buflist, we need to deal with that first.
2040 	 */
2041 
2042 	while (1) {
2043 		struct lws_tokens ebuf;
2044 		int m;
2045 
2046 		ebuf.len = (int)lws_buflist_next_segment_len(&wsi->buflist,
2047 							     &ebuf.token);
2048 		if (!ebuf.len)
2049 			break;
2050 
2051 		lwsl_debug("%s: consuming %d\n", __func__, (int)ebuf.len);
2052 		m = lws_read_h1(wsi, ebuf.token, (lws_filepos_t)ebuf.len);
2053 		if (m < 0)
2054 			return -1;
2055 
2056 		if (lws_buflist_aware_finished_consuming(wsi, &ebuf, m, 1,
2057 							 __func__))
2058 			return -1;
2059 	}
2060 
2061 	return 0;
2062 
2063 bail_nuke_ah:
2064 	lws_header_table_detach(wsi, 1);
2065 
2066 	return 1;
2067 }
2068 
2069 int
lws_confirm_host_header(struct lws * wsi)2070 lws_confirm_host_header(struct lws *wsi)
2071 {
2072 	struct lws_tokenize ts;
2073 	lws_tokenize_elem e;
2074 	int port = 80, n;
2075 	char buf[128];
2076 
2077 	/*
2078 	 * this vhost wants us to validate what the
2079 	 * client sent against our vhost name
2080 	 */
2081 
2082 	if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {
2083 		lwsl_info("%s: missing host on upgrade\n", __func__);
2084 
2085 		return 1;
2086 	}
2087 
2088 #if defined(LWS_WITH_TLS)
2089 	if (wsi->tls.ssl)
2090 		port = 443;
2091 #endif
2092 
2093 	n = lws_hdr_copy(wsi, buf, sizeof(buf) - 1, WSI_TOKEN_HOST);
2094 	if (n <= 0) {
2095 		lwsl_info("%s: missing or oversize host header\n", __func__);
2096 		return 1;
2097 	}
2098 	ts.len = (size_t)n;
2099 	lws_tokenize_init(&ts, buf, LWS_TOKENIZE_F_DOT_NONTERM /* server.com */|
2100 				    LWS_TOKENIZE_F_NO_FLOATS /* 1.server.com */|
2101 				    LWS_TOKENIZE_F_MINUS_NONTERM /* a-b.com */);
2102 
2103 	if (lws_tokenize(&ts) != LWS_TOKZE_TOKEN)
2104 		goto bad_format;
2105 
2106 	if (strncmp(ts.token, wsi->a.vhost->name, ts.token_len)) {
2107 		buf[(size_t)(ts.token - buf) + ts.token_len] = '\0';
2108 		lwsl_info("%s: '%s' in host hdr but vhost name %s\n",
2109 			  __func__, ts.token, wsi->a.vhost->name);
2110 		return 1;
2111 	}
2112 
2113 	e = lws_tokenize(&ts);
2114 	if (e == LWS_TOKZE_DELIMITER && ts.token[0] == ':') {
2115 		if (lws_tokenize(&ts) != LWS_TOKZE_INTEGER)
2116 			goto bad_format;
2117 		else
2118 			port = atoi(ts.token);
2119 	} else
2120 		if (e != LWS_TOKZE_ENDED)
2121 			goto bad_format;
2122 
2123 	if (wsi->a.vhost->listen_port != port) {
2124 		lwsl_info("%s: host port %d mismatches vhost port %d\n",
2125 			  __func__, port, wsi->a.vhost->listen_port);
2126 		return 1;
2127 	}
2128 
2129 	lwsl_debug("%s: host header OK\n", __func__);
2130 
2131 	return 0;
2132 
2133 bad_format:
2134 	lwsl_info("%s: bad host header format\n", __func__);
2135 
2136 	return 1;
2137 }
2138 
2139 #if defined(LWS_WITH_SERVER)
2140 int
lws_http_to_fallback(struct lws * wsi,unsigned char * obuf,size_t olen)2141 lws_http_to_fallback(struct lws *wsi, unsigned char *obuf, size_t olen)
2142 {
2143 	const struct lws_role_ops *role = &role_ops_raw_skt;
2144 	const struct lws_protocols *p1, *protocol =
2145 			 &wsi->a.vhost->protocols[wsi->a.vhost->raw_protocol_index];
2146 	char ipbuf[64];
2147 	int n;
2148 
2149 	if (wsi->a.vhost->listen_accept_role &&
2150 	    lws_role_by_name(wsi->a.vhost->listen_accept_role))
2151 		role = lws_role_by_name(wsi->a.vhost->listen_accept_role);
2152 
2153 	if (wsi->a.vhost->listen_accept_protocol) {
2154 		p1 = lws_vhost_name_to_protocol(wsi->a.vhost,
2155 			    wsi->a.vhost->listen_accept_protocol);
2156 		if (p1)
2157 			protocol = p1;
2158 	}
2159 
2160 	lws_bind_protocol(wsi, protocol, __func__);
2161 
2162 	lws_role_transition(wsi, LWSIFR_SERVER, LRS_ESTABLISHED, role);
2163 
2164 	lws_header_table_detach(wsi, 0);
2165 	lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
2166 
2167 	n = LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED;
2168 	if (wsi->role_ops->adoption_cb[1])
2169 		n = wsi->role_ops->adoption_cb[1];
2170 
2171 	ipbuf[0] = '\0';
2172 #if !defined(LWS_PLAT_OPTEE)
2173 	lws_get_peer_simple(wsi, ipbuf, sizeof(ipbuf));
2174 #endif
2175 
2176 	lwsl_notice("%s: vh %s, peer: %s, role %s, "
2177 		    "protocol %s, cb %d, ah %p\n", __func__, wsi->a.vhost->name,
2178 		    ipbuf, role ? role->name : "null", protocol->name, n,
2179 		    wsi->http.ah);
2180 
2181 	if ((wsi->a.protocol->callback)(wsi, (enum lws_callback_reasons)n, wsi->user_space, NULL, 0))
2182 		return 1;
2183 
2184 	n = LWS_CALLBACK_RAW_RX;
2185 	if (wsi->role_ops->rx_cb[lwsi_role_server(wsi)])
2186 		n = wsi->role_ops->rx_cb[lwsi_role_server(wsi)];
2187 	if (wsi->a.protocol->callback(wsi, (enum lws_callback_reasons)n, wsi->user_space, obuf, olen))
2188 		return 1;
2189 
2190 	return 0;
2191 }
2192 
2193 int
lws_handshake_server(struct lws * wsi,unsigned char ** buf,size_t len)2194 lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
2195 {
2196 	struct lws_context *context = lws_get_context(wsi);
2197 	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
2198 #if defined(LWS_WITH_HTTP2)
2199 	struct allocated_headers *ah;
2200 #endif
2201 	unsigned char *obuf = *buf;
2202 #if defined(LWS_WITH_HTTP2)
2203 	char tbuf[128], *p;
2204 #endif
2205 	size_t olen = len;
2206 	int n = 0, m, i;
2207 
2208 	if (len >= 10000000) {
2209 		lwsl_err("%s: assert: len %ld\n", __func__, (long)len);
2210 		assert(0);
2211 	}
2212 
2213 	if (!wsi->http.ah) {
2214 		lwsl_err("%s: assert: NULL ah\n", __func__);
2215 		assert(0);
2216 	}
2217 
2218 	while (len) {
2219 		if (!lwsi_role_server(wsi) || !lwsi_role_http(wsi)) {
2220 			lwsl_err("%s: bad wsi role 0x%x\n", __func__,
2221 					(int)lwsi_role(wsi));
2222 			goto bail_nuke_ah;
2223 		}
2224 
2225 		i = (int)len;
2226 		m = lws_parse(wsi, *buf, &i);
2227 		lwsl_info("%s: parsed count %d\n", __func__, (int)len - i);
2228 		(*buf) += (int)len - i;
2229 		len = (unsigned int)i;
2230 
2231 		if (m == LPR_DO_FALLBACK) {
2232 
2233 			/*
2234 			 * http parser went off the rails and
2235 			 * LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_
2236 			 * ACCEPT_CONFIG is set on this vhost.
2237 			 *
2238 			 * We are transitioning from http with an AH, to
2239 			 * a backup role (raw-skt, by default).  Drop
2240 			 * the ah, bind to the role with mode as
2241 			 * ESTABLISHED.
2242 			 */
2243 raw_transition:
2244 
2245 			if (lws_http_to_fallback(wsi, obuf, olen)) {
2246 				lwsl_info("%s: fallback -> close\n", __func__);
2247 				goto bail_nuke_ah;
2248 			}
2249 
2250 			(*buf) = obuf + olen;
2251 
2252 			return 0;
2253 		}
2254 		if (m) {
2255 			lwsl_info("lws_parse failed\n");
2256 			goto bail_nuke_ah;
2257 		}
2258 
2259 		/* coverity... */
2260 		if (!wsi->http.ah)
2261 			goto bail_nuke_ah;
2262 
2263 		if (wsi->http.ah->parser_state != WSI_PARSING_COMPLETE)
2264 			continue;
2265 
2266 		lwsl_parser("%s: lws_parse sees parsing complete\n", __func__);
2267 
2268 		/* select vhost */
2269 
2270 		if (wsi->a.vhost->listen_port &&
2271 		    lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {
2272 			struct lws_vhost *vhost = lws_select_vhost(
2273 				context, wsi->a.vhost->listen_port,
2274 				lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));
2275 
2276 			if (vhost)
2277 				lws_vhost_bind_wsi(vhost, wsi);
2278 		} else
2279 			lwsl_info("no host\n");
2280 
2281 		if ((!lwsi_role_h2(wsi) || !lwsi_role_server(wsi)) &&
2282 		    (!wsi->conn_stat_done))
2283 			wsi->conn_stat_done = 1;
2284 
2285 		/* check for unwelcome guests */
2286 #if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
2287 		if (wsi->a.context->reject_service_keywords) {
2288 			const struct lws_protocol_vhost_options *rej =
2289 					wsi->a.context->reject_service_keywords;
2290 			char ua[384], *msg = NULL;
2291 
2292 			if (lws_hdr_copy(wsi, ua, sizeof(ua) - 1,
2293 					 WSI_TOKEN_HTTP_USER_AGENT) > 0) {
2294 #ifdef LWS_WITH_ACCESS_LOG
2295 				char *uri_ptr = NULL;
2296 				int meth, uri_len;
2297 #endif
2298 				ua[sizeof(ua) - 1] = '\0';
2299 				while (rej) {
2300 					if (!strstr(ua, rej->name)) {
2301 						rej = rej->next;
2302 						continue;
2303 					}
2304 
2305 					msg = strchr(rej->value, ' ');
2306 					if (msg)
2307 						msg++;
2308 					lws_return_http_status(wsi,
2309 						(unsigned int)atoi(rej->value), msg);
2310 #ifdef LWS_WITH_ACCESS_LOG
2311 					meth = lws_http_get_uri_and_method(wsi,
2312 							&uri_ptr, &uri_len);
2313 					if (meth >= 0)
2314 						lws_prepare_access_log_info(wsi,
2315 							uri_ptr, uri_len, meth);
2316 
2317 					/* wsi close will do the log */
2318 #endif
2319 					/*
2320 					 * We don't want anything from
2321 					 * this rejected guy.  Follow
2322 					 * the close flow, not the
2323 					 * transaction complete flow.
2324 					 */
2325 					goto bail_nuke_ah;
2326 				}
2327 			}
2328 		}
2329 #endif
2330 		/*
2331 		 * So he may have come to us requesting one or another kind
2332 		 * of upgrade from http... but we may want to redirect him at
2333 		 * http level.  In that case, we need to check the redirect
2334 		 * situation even though he's not actually wanting http and
2335 		 * prioritize returning that if there is one.
2336 		 */
2337 
2338 		{
2339 			const struct lws_http_mount *hit = NULL;
2340 			int uri_len = 0, ha, n;
2341 			char *uri_ptr = NULL;
2342 
2343 			n = lws_http_get_uri_and_method(wsi, &uri_ptr, &uri_len);
2344 			if (n >= 0) {
2345 				hit = lws_find_mount(wsi, uri_ptr, uri_len);
2346 				if (hit) {
2347 					n = lws_http_redirect_hit(pt, wsi, hit, uri_ptr,
2348 								  uri_len, &ha);
2349 					if (ha)
2350 						return n;
2351 				}
2352 			}
2353 		}
2354 
2355 
2356 
2357 		if (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECT)) {
2358 			lwsl_info("Changing to RAW mode\n");
2359 			goto raw_transition;
2360 		}
2361 
2362 		lwsi_set_state(wsi, LRS_PRE_WS_SERVING_ACCEPT);
2363 		lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
2364 
2365 		if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {
2366 
2367 			const char *up = lws_hdr_simple_ptr(wsi,
2368 							    WSI_TOKEN_UPGRADE);
2369 
2370 			if (strcasecmp(up, "websocket") &&
2371 			    strcasecmp(up, "h2c")) {
2372 				lwsl_info("Unknown upgrade '%s'\n", up);
2373 
2374 				if (lws_return_http_status(wsi,
2375 						HTTP_STATUS_FORBIDDEN, NULL) ||
2376 				    lws_http_transaction_completed(wsi))
2377 					goto bail_nuke_ah;
2378 			}
2379 
2380 			n = user_callback_handle_rxflow(wsi->a.protocol->callback,
2381 					wsi, LWS_CALLBACK_HTTP_CONFIRM_UPGRADE,
2382 					wsi->user_space, (char *)up, 0);
2383 
2384 			/* just hang up? */
2385 
2386 			if (n < 0)
2387 				goto bail_nuke_ah;
2388 
2389 			/* callback returned headers already, do t_c? */
2390 
2391 			if (n > 0) {
2392 				if (lws_http_transaction_completed(wsi))
2393 					goto bail_nuke_ah;
2394 
2395 				/* continue on */
2396 
2397 				return 0;
2398 			}
2399 
2400 			/* callback said 0, it was allowed */
2401 
2402 			if (wsi->a.vhost->options &
2403 			    LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK &&
2404 			    lws_confirm_host_header(wsi))
2405 				goto bail_nuke_ah;
2406 
2407 			if (!strcasecmp(up, "websocket")) {
2408 #if defined(LWS_ROLE_WS)
2409 				lws_metrics_tag_wsi_add(wsi, "upg", "ws");
2410 				lwsl_info("Upgrade to ws\n");
2411 				goto upgrade_ws;
2412 #endif
2413 			}
2414 #if defined(LWS_WITH_HTTP2)
2415 			if (!strcasecmp(up, "h2c")) {
2416 				lws_metrics_tag_wsi_add(wsi, "upg", "h2c");
2417 				lwsl_info("Upgrade to h2c\n");
2418 				goto upgrade_h2c;
2419 			}
2420 #endif
2421 		}
2422 
2423 		/* no upgrade ack... he remained as HTTP */
2424 
2425 		lwsl_info("%s: %s: No upgrade\n", __func__, lws_wsi_tag(wsi));
2426 
2427 		lwsi_set_state(wsi, LRS_ESTABLISHED);
2428 #if defined(LWS_WITH_FILE_OPS)
2429 		wsi->http.fop_fd = NULL;
2430 #endif
2431 
2432 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
2433 		lws_http_compression_validate(wsi);
2434 #endif
2435 
2436 		lwsl_debug("%s: %s: ah %p\n", __func__, lws_wsi_tag(wsi),
2437 			   (void *)wsi->http.ah);
2438 
2439 		n = lws_http_action(wsi);
2440 
2441 		return n;
2442 
2443 #if defined(LWS_WITH_HTTP2)
2444 upgrade_h2c:
2445 		if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP2_SETTINGS)) {
2446 			lwsl_info("missing http2_settings\n");
2447 			goto bail_nuke_ah;
2448 		}
2449 
2450 		lwsl_info("h2c upgrade...\n");
2451 
2452 		p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP2_SETTINGS);
2453 		/* convert the peer's HTTP-Settings */
2454 		n = lws_b64_decode_string(p, tbuf, sizeof(tbuf));
2455 		if (n < 0) {
2456 			lwsl_parser("HTTP2_SETTINGS too long\n");
2457 			return 1;
2458 		}
2459 
2460 		wsi->upgraded_to_http2 = 1;
2461 
2462 		/* adopt the header info */
2463 
2464 		ah = wsi->http.ah;
2465 		lws_role_transition(wsi, LWSIFR_SERVER, LRS_H2_AWAIT_PREFACE,
2466 				    &role_ops_h2);
2467 
2468 		/* http2 union member has http union struct at start */
2469 		wsi->http.ah = ah;
2470 
2471 		if (!wsi->h2.h2n) {
2472 			wsi->h2.h2n = lws_zalloc(sizeof(*wsi->h2.h2n), "h2n");
2473 			if (!wsi->h2.h2n)
2474 				return 1;
2475 		}
2476 
2477 		lws_h2_init(wsi);
2478 
2479 		/* HTTP2 union */
2480 
2481 		lws_h2_settings(wsi, &wsi->h2.h2n->peer_set, (uint8_t *)tbuf, n);
2482 
2483 		if (lws_hpack_dynamic_size(wsi, (int)wsi->h2.h2n->peer_set.s[
2484 		                                      H2SET_HEADER_TABLE_SIZE]))
2485 			return 1;
2486 
2487 		strcpy(tbuf, "HTTP/1.1 101 Switching Protocols\x0d\x0a"
2488 			      "Connection: Upgrade\x0d\x0a"
2489 			      "Upgrade: h2c\x0d\x0a\x0d\x0a");
2490 		m = (int)strlen(tbuf);
2491 		n = lws_issue_raw(wsi, (unsigned char *)tbuf, (unsigned int)m);
2492 		if (n != m) {
2493 			lwsl_debug("http2 switch: ERROR writing to socket\n");
2494 			return 1;
2495 		}
2496 
2497 		return 0;
2498 #endif
2499 #if defined(LWS_ROLE_WS)
2500 upgrade_ws:
2501 		if (lws_process_ws_upgrade(wsi))
2502 			goto bail_nuke_ah;
2503 
2504 		return 0;
2505 #endif
2506 	} /* while all chars are handled */
2507 
2508 	return 0;
2509 
2510 bail_nuke_ah:
2511 	/* drop the header info */
2512 	lws_header_table_detach(wsi, 1);
2513 
2514 	return 1;
2515 }
2516 #endif
2517 
2518 int LWS_WARN_UNUSED_RESULT
lws_http_transaction_completed(struct lws * wsi)2519 lws_http_transaction_completed(struct lws *wsi)
2520 {
2521 	int n;
2522 
2523 	if (wsi->http.cgi_transaction_complete)
2524 		return 0;
2525 
2526 	if (lws_has_buffered_out(wsi)
2527 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
2528 			|| wsi->http.comp_ctx.buflist_comp ||
2529 	    wsi->http.comp_ctx.may_have_more
2530 #endif
2531 	) {
2532 		/*
2533 		 * ...so he tried to send something large as the http reply,
2534 		 * it went as a partial, but he immediately said the
2535 		 * transaction was completed.
2536 		 *
2537 		 * Defer the transaction completed until the last part of the
2538 		 * partial is sent.
2539 		 */
2540 		lwsl_debug("%s: %s: deferring due to partial\n", __func__,
2541 				lws_wsi_tag(wsi));
2542 		wsi->http.deferred_transaction_completed = 1;
2543 		lws_callback_on_writable(wsi);
2544 
2545 		return 0;
2546 	}
2547 	/*
2548 	 * Are we finishing the transaction before we have consumed any body?
2549 	 *
2550 	 * For h1 this would kill keepalive pipelining, and for h2, considering
2551 	 * it can extend over multiple DATA frames, it would kill the network
2552 	 * connection.
2553 	 */
2554 	if (wsi->http.rx_content_length && wsi->http.rx_content_remain) {
2555 		/*
2556 		 * are we already in LRS_DISCARD_BODY and didn't clear the
2557 		 * remaining before trying to complete the transaction again?
2558 		 */
2559 		if (lwsi_state(wsi) == LRS_DISCARD_BODY)
2560 			return -1;
2561 		/*
2562 		 * let's defer transaction completed processing until we
2563 		 * discarded the remaining body
2564 		 */
2565 		lwsi_set_state(wsi, LRS_DISCARD_BODY);
2566 
2567 		return 0;
2568 	}
2569 
2570 #if defined(LWS_WITH_SYS_METRICS)
2571 	{
2572 		char tmp[10];
2573 
2574 		lws_snprintf(tmp, sizeof(tmp), "%u", wsi->http.response_code);
2575 		lws_metrics_tag_wsi_add(wsi, "status", tmp);
2576 	}
2577 #endif
2578 
2579 	lwsl_info("%s: %s\n", __func__, lws_wsi_tag(wsi));
2580 
2581 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
2582 	lws_http_compression_destroy(wsi);
2583 #endif
2584 	lws_access_log(wsi);
2585 
2586 	if (!wsi->hdr_parsing_completed
2587 #if defined(LWS_WITH_CGI)
2588 			&& !wsi->http.cgi
2589 #endif
2590 	) {
2591 		char peer[64];
2592 
2593 #if !defined(LWS_PLAT_OPTEE)
2594 		lws_get_peer_simple(wsi, peer, sizeof(peer) - 1);
2595 #else
2596 		peer[0] = '\0';
2597 #endif
2598 		peer[sizeof(peer) - 1] = '\0';
2599 		lwsl_info("%s: (from %s) ignoring, ah parsing incomplete\n",
2600 				__func__, peer);
2601 		return 0;
2602 	}
2603 
2604 #if defined(LWS_WITH_CGI)
2605 	if (wsi->http.cgi) {
2606 		lwsl_debug("%s: cleaning cgi\n", __func__);
2607 		wsi->http.cgi_transaction_complete = 1;
2608 		lws_cgi_remove_and_kill(wsi);
2609 		lws_spawn_piped_destroy(&wsi->http.cgi->lsp);
2610 		lws_sul_cancel(&wsi->http.cgi->sul_grace);
2611 
2612 		lws_free_set_NULL(wsi->http.cgi);
2613 		wsi->http.cgi_transaction_complete = 0;
2614 	}
2615 #endif
2616 
2617 	/* if we can't go back to accept new headers, drop the connection */
2618 	if (wsi->mux_substream)
2619 		return 1;
2620 
2621 	if (wsi->seen_zero_length_recv)
2622 		return 1;
2623 
2624 	if (wsi->http.conn_type != HTTP_CONNECTION_KEEP_ALIVE) {
2625 		lwsl_info("%s: %s: close connection\n", __func__, lws_wsi_tag(wsi));
2626 		return 1;
2627 	}
2628 
2629 	if (lws_bind_protocol(wsi, &wsi->a.vhost->protocols[0], __func__))
2630 		return 1;
2631 
2632 	/*
2633 	 * otherwise set ourselves up ready to go again, but because we have no
2634 	 * idea about the wsi writability, we make put it in a holding state
2635 	 * until we can verify POLLOUT.  The part of this that confirms POLLOUT
2636 	 * with no partials is in lws_server_socket_service() below.
2637 	 */
2638 	lwsl_debug("%s: %s: setting DEF_ACT from 0x%x: %p\n", __func__,
2639 		   lws_wsi_tag(wsi), (int)wsi->wsistate, wsi->buflist);
2640 	lwsi_set_state(wsi, LRS_DEFERRING_ACTION);
2641 	wsi->http.tx_content_length = 0;
2642 	wsi->http.tx_content_remain = 0;
2643 	wsi->hdr_parsing_completed = 0;
2644 	wsi->sending_chunked = 0;
2645 #ifdef LWS_WITH_ACCESS_LOG
2646 	wsi->http.access_log.sent = 0;
2647 #endif
2648 #if defined(LWS_WITH_FILE_OPS) && (defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2))
2649 	if (lwsi_role_http(wsi) && lwsi_role_server(wsi) &&
2650 	    wsi->http.fop_fd != NULL)
2651 		lws_vfs_file_close(&wsi->http.fop_fd);
2652 #endif
2653 
2654 	n = NO_PENDING_TIMEOUT;
2655 	if (wsi->a.vhost->keepalive_timeout)
2656 		n = PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE;
2657 	lws_set_timeout(wsi, (enum pending_timeout)n, wsi->a.vhost->keepalive_timeout);
2658 
2659 	/*
2660 	 * We already know we are on http1.1 / keepalive and the next thing
2661 	 * coming will be another header set.
2662 	 *
2663 	 * If there is no pending rx and we still have the ah, drop it and
2664 	 * reacquire a new ah when the new headers start to arrive.  (Otherwise
2665 	 * we needlessly hog an ah indefinitely.)
2666 	 *
2667 	 * However if there is pending rx and we know from the keepalive state
2668 	 * that is already at least the start of another header set, simply
2669 	 * reset the existing header table and keep it.
2670 	 */
2671 	if (wsi->http.ah) {
2672 		// lws_buflist_describe(&wsi->buflist, wsi, __func__);
2673 		if (!lws_buflist_next_segment_len(&wsi->buflist, NULL)) {
2674 			lwsl_debug("%s: %s: nothing in buflist, detaching ah\n",
2675 				  __func__, lws_wsi_tag(wsi));
2676 			lws_header_table_detach(wsi, 1);
2677 #ifdef LWS_WITH_TLS
2678 			/*
2679 			 * additionally... if we are hogging an SSL instance
2680 			 * with no pending pipelined headers (or ah now), and
2681 			 * SSL is scarce, drop this connection without waiting
2682 			 */
2683 
2684 			if (wsi->a.vhost->tls.use_ssl &&
2685 			    wsi->a.context->simultaneous_ssl_restriction &&
2686 			    wsi->a.context->simultaneous_ssl ==
2687 				   wsi->a.context->simultaneous_ssl_restriction) {
2688 				lwsl_info("%s: simultaneous_ssl_restriction\n",
2689 					  __func__);
2690 				return 1;
2691 			}
2692 #endif
2693 		} else {
2694 			lwsl_info("%s: %s: resetting/keeping ah as pipeline\n",
2695 				  __func__, lws_wsi_tag(wsi));
2696 			lws_header_table_reset(wsi, 0);
2697 			/*
2698 			 * If we kept the ah, we should restrict the amount
2699 			 * of time we are willing to keep it.  Otherwise it
2700 			 * will be bound the whole time the connection remains
2701 			 * open.
2702 			 */
2703 			lws_set_timeout(wsi, PENDING_TIMEOUT_HOLDING_AH,
2704 					wsi->a.vhost->keepalive_timeout);
2705 		}
2706 		/* If we're (re)starting on headers, need other implied init */
2707 		if (wsi->http.ah)
2708 			wsi->http.ah->ues = URIES_IDLE;
2709 
2710 		//lwsi_set_state(wsi, LRS_ESTABLISHED); // !!!
2711 	} else
2712 		if (lws_buflist_next_segment_len(&wsi->buflist, NULL))
2713 			if (lws_header_table_attach(wsi, 0))
2714 				lwsl_debug("acquired ah\n");
2715 
2716 	lwsl_debug("%s: %s: keep-alive await new transaction (state 0x%x)\n",
2717 		   __func__, lws_wsi_tag(wsi), (int)wsi->wsistate);
2718 	lws_callback_on_writable(wsi);
2719 
2720 	return 0;
2721 }
2722 
2723 #if defined(LWS_WITH_FILE_OPS)
2724 int
lws_serve_http_file(struct lws * wsi,const char * file,const char * content_type,const char * other_headers,int other_headers_len)2725 lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
2726 		    const char *other_headers, int other_headers_len)
2727 {
2728 	struct lws_context *context = lws_get_context(wsi);
2729 	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
2730 	unsigned char *response = pt->serv_buf + LWS_PRE;
2731 #if defined(LWS_WITH_RANGES)
2732 	struct lws_range_parsing *rp = &wsi->http.range;
2733 #endif
2734 	int ret = 0, cclen = 8, n = HTTP_STATUS_OK;
2735 	char cache_control[50], *cc = "no-store";
2736 	lws_fop_flags_t fflags = LWS_O_RDONLY;
2737 	const struct lws_plat_file_ops *fops;
2738 	lws_filepos_t total_content_length;
2739 	unsigned char *p = response;
2740 	unsigned char *end = p + context->pt_serv_buf_size - LWS_PRE;
2741 	const char *vpath;
2742 #if defined(LWS_WITH_RANGES)
2743 	int ranges;
2744 #endif
2745 
2746 	if (wsi->handling_404)
2747 		n = HTTP_STATUS_NOT_FOUND;
2748 
2749 	/*
2750 	 * We either call the platform fops .open with first arg platform fops,
2751 	 * or we call fops_zip .open with first arg platform fops, and fops_zip
2752 	 * open will decide whether to switch to fops_zip or stay with fops_def.
2753 	 *
2754 	 * If wsi->http.fop_fd is already set, the caller already opened it
2755 	 */
2756 	if (!wsi->http.fop_fd) {
2757 		fops = lws_vfs_select_fops(wsi->a.context->fops, file, &vpath);
2758 		fflags |= lws_vfs_prepare_flags(wsi);
2759 		wsi->http.fop_fd = fops->LWS_FOP_OPEN(wsi->a.context->fops,
2760 							file, vpath, &fflags);
2761 		if (!wsi->http.fop_fd) {
2762 			lwsl_info("%s: Unable to open: '%s': errno %d\n",
2763 				  __func__, file, errno);
2764 			if (lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND,
2765 						   NULL))
2766 						return -1;
2767 			return !wsi->mux_substream;
2768 		}
2769 	}
2770 
2771 	/*
2772 	 * Caution... wsi->http.fop_fd is live from here
2773 	 */
2774 
2775 	wsi->http.filelen = lws_vfs_get_length(wsi->http.fop_fd);
2776 	total_content_length = wsi->http.filelen;
2777 
2778 #if defined(LWS_WITH_RANGES)
2779 	ranges = lws_ranges_init(wsi, rp, wsi->http.filelen);
2780 
2781 	lwsl_debug("Range count %d\n", ranges);
2782 	/*
2783 	 * no ranges -> 200;
2784 	 *  1 range  -> 206 + Content-Type: normal; Content-Range;
2785 	 *  more     -> 206 + Content-Type: multipart/byteranges
2786 	 *  		Repeat the true Content-Type in each multipart header
2787 	 *  		along with Content-Range
2788 	 */
2789 	if (ranges < 0) {
2790 		/* it means he expressed a range in Range:, but it was illegal */
2791 		lws_return_http_status(wsi,
2792 				HTTP_STATUS_REQ_RANGE_NOT_SATISFIABLE, NULL);
2793 		if (lws_http_transaction_completed(wsi))
2794 			goto bail; /* <0 means just hang up */
2795 
2796 		lws_vfs_file_close(&wsi->http.fop_fd);
2797 
2798 		return 0; /* == 0 means we did the transaction complete */
2799 	}
2800 	if (ranges)
2801 		n = HTTP_STATUS_PARTIAL_CONTENT;
2802 #endif
2803 
2804 	if (lws_add_http_header_status(wsi, (unsigned int)n, &p, end))
2805 		goto bail;
2806 
2807 	if ((wsi->http.fop_fd->flags & (LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP |
2808 		       LWS_FOP_FLAG_COMPR_IS_GZIP)) ==
2809 	    (LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP | LWS_FOP_FLAG_COMPR_IS_GZIP)) {
2810 		if (lws_add_http_header_by_token(wsi,
2811 			WSI_TOKEN_HTTP_CONTENT_ENCODING,
2812 			(unsigned char *)"gzip", 4, &p, end))
2813 			goto bail;
2814 		lwsl_info("file is being provided in gzip\n");
2815 	}
2816 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
2817 	else {
2818 		/*
2819 		 * if we know its very compressible, and we can use
2820 		 * compression, then use the most preferred compression
2821 		 * method that the client said he will accept
2822 		 */
2823 
2824 		if (!wsi->interpreting && (
2825 		     !strncmp(content_type, "text/", 5) ||
2826 		     !strcmp(content_type, "application/javascript") ||
2827 		     !strcmp(content_type, "image/svg+xml")))
2828 			lws_http_compression_apply(wsi, NULL, &p, end, 0);
2829 	}
2830 #endif
2831 
2832 	if (
2833 #if defined(LWS_WITH_RANGES)
2834 	    ranges < 2 &&
2835 #endif
2836 	    content_type && content_type[0])
2837 		if (lws_add_http_header_by_token(wsi,
2838 						 WSI_TOKEN_HTTP_CONTENT_TYPE,
2839 						 (unsigned char *)content_type,
2840 						 (int)strlen(content_type),
2841 						 &p, end))
2842 			goto bail;
2843 
2844 #if defined(LWS_WITH_RANGES)
2845 	if (ranges >= 2) { /* multipart byteranges */
2846 		lws_strncpy(wsi->http.multipart_content_type, content_type,
2847 			sizeof(wsi->http.multipart_content_type));
2848 
2849 		if (lws_add_http_header_by_token(wsi,
2850 						 WSI_TOKEN_HTTP_CONTENT_TYPE,
2851 						 (unsigned char *)
2852 						 "multipart/byteranges; "
2853 						 "boundary=_lws",
2854 			 	 	 	 20, &p, end))
2855 			goto bail;
2856 
2857 		/*
2858 		 *  our overall content length has to include
2859 		 *
2860 		 *  - (n + 1) x "_lws\r\n"
2861 		 *  - n x Content-Type: xxx/xxx\r\n
2862 		 *  - n x Content-Range: bytes xxx-yyy/zzz\r\n
2863 		 *  - n x /r/n
2864 		 *  - the actual payloads (aggregated in rp->agg)
2865 		 *
2866 		 *  Precompute it for the main response header
2867 		 */
2868 
2869 		total_content_length = (lws_filepos_t)rp->agg +
2870 				       6 /* final _lws\r\n */;
2871 
2872 		lws_ranges_reset(rp);
2873 		while (lws_ranges_next(rp)) {
2874 			n = lws_snprintf(cache_control, sizeof(cache_control),
2875 					"bytes %llu-%llu/%llu",
2876 					rp->start, rp->end, rp->extent);
2877 
2878 			total_content_length = total_content_length +
2879 					(lws_filepos_t)(
2880 				6 /* header _lws\r\n */ +
2881 				/* Content-Type: xxx/xxx\r\n */
2882 				14 + (int)strlen(content_type) + 2 +
2883 				/* Content-Range: xxxx\r\n */
2884 				15 + n + 2 +
2885 				2); /* /r/n */
2886 		}
2887 
2888 		lws_ranges_reset(rp);
2889 		lws_ranges_next(rp);
2890 	}
2891 
2892 	if (ranges == 1) {
2893 		total_content_length = (lws_filepos_t)rp->agg;
2894 		n = lws_snprintf(cache_control, sizeof(cache_control),
2895 				 "bytes %llu-%llu/%llu",
2896 				 rp->start, rp->end, rp->extent);
2897 
2898 		if (lws_add_http_header_by_token(wsi,
2899 						 WSI_TOKEN_HTTP_CONTENT_RANGE,
2900 						 (unsigned char *)cache_control,
2901 						 n, &p, end))
2902 			goto bail;
2903 	}
2904 
2905 	wsi->http.range.inside = 0;
2906 
2907 	if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ACCEPT_RANGES,
2908 					 (unsigned char *)"bytes", 5, &p, end))
2909 		goto bail;
2910 #endif
2911 
2912 	if (!wsi->mux_substream) {
2913 		/* for http/1.1 ... */
2914 		if (!wsi->sending_chunked
2915 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
2916 				&& !wsi->http.lcs
2917 #endif
2918 		) {
2919 			/* ... if not already using chunked and not using an
2920 			 * http compression translation, then send the naive
2921 			 * content length
2922 			 */
2923 			if (lws_add_http_header_content_length(wsi,
2924 						total_content_length, &p, end))
2925 				goto bail;
2926 		} else {
2927 
2928 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
2929 			if (wsi->http.lcs) {
2930 
2931 				/* ...otherwise, for http 1 it must go chunked.
2932 				 * For the compression case, the reason is we
2933 				 * compress on the fly and do not know the
2934 				 * compressed content-length until it has all
2935 				 * been sent.  Http/1.1 pipelining must be able
2936 				 * to know where the transaction boundaries are
2937 				 * ... so chunking...
2938 				 */
2939 				if (lws_add_http_header_by_token(wsi,
2940 						WSI_TOKEN_HTTP_TRANSFER_ENCODING,
2941 						(unsigned char *)"chunked", 7,
2942 						&p, end))
2943 					goto bail;
2944 
2945 				/*
2946 				 * ...this is fun, isn't it :-)  For h1 that is
2947 				 * using an http compression translation, the
2948 				 * compressor must chunk its output privately.
2949 				 *
2950 				 * h2 doesn't need (or support) any of this
2951 				 * crap.
2952 				 */
2953 				lwsl_debug("setting chunking\n");
2954 				wsi->http.comp_ctx.chunking = 1;
2955 			}
2956 #endif
2957 		}
2958 	}
2959 
2960 	if (wsi->cache_secs && wsi->cache_reuse) {
2961 		if (!wsi->cache_revalidate) {
2962 			cc = cache_control;
2963 			cclen = sprintf(cache_control, "%s, max-age=%u",
2964 				    intermediates[wsi->cache_intermediaries],
2965 				    wsi->cache_secs);
2966 		} else {
2967 			cc = cache_control;
2968 			cclen = sprintf(cache_control,
2969 					"must-revalidate, %s, max-age=%u",
2970                                 intermediates[wsi->cache_intermediaries],
2971                                                     wsi->cache_secs);
2972 
2973 		}
2974 	}
2975 
2976 	/* Only add cache control if its not specified by any other_headers. */
2977 	if (!other_headers ||
2978 	    (!strstr(other_headers, "cache-control") &&
2979 	     !strstr(other_headers, "Cache-Control"))) {
2980 		if (lws_add_http_header_by_token(wsi,
2981 				WSI_TOKEN_HTTP_CACHE_CONTROL,
2982 				(unsigned char *)cc, cclen, &p, end))
2983 			goto bail;
2984 	}
2985 
2986 	if (other_headers) {
2987 		if ((end - p) < other_headers_len)
2988 			goto bail;
2989 		memcpy(p, other_headers, (unsigned int)other_headers_len);
2990 		p += other_headers_len;
2991 	}
2992 
2993 	if (lws_finalize_http_header(wsi, &p, end))
2994 		goto bail;
2995 
2996 	ret = lws_write(wsi, response, lws_ptr_diff_size_t(p, response), LWS_WRITE_HTTP_HEADERS);
2997 	if (ret != (p - response)) {
2998 		lwsl_err("_write returned %d from %ld\n", ret,
2999 			 (long)(p - response));
3000 		goto bail;
3001 	}
3002 
3003 	wsi->http.filepos = 0;
3004 	lwsi_set_state(wsi, LRS_ISSUING_FILE);
3005 
3006 	if (lws_hdr_total_length(wsi, WSI_TOKEN_HEAD_URI)) {
3007 		/* we do not emit the body */
3008 		lws_vfs_file_close(&wsi->http.fop_fd);
3009 		if (lws_http_transaction_completed(wsi))
3010 			goto bail;
3011 
3012 		return 0;
3013 	}
3014 
3015 	lws_callback_on_writable(wsi);
3016 
3017 	return 0;
3018 
3019 bail:
3020 	lws_vfs_file_close(&wsi->http.fop_fd);
3021 
3022 	return -1;
3023 }
3024 #endif
3025 
3026 #if defined(LWS_WITH_FILE_OPS)
3027 
lws_serve_http_file_fragment(struct lws * wsi)3028 int lws_serve_http_file_fragment(struct lws *wsi)
3029 {
3030 	struct lws_context *context = wsi->a.context;
3031 	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
3032 	struct lws_process_html_args args;
3033 	lws_filepos_t amount, poss;
3034 	unsigned char *p, *pstart;
3035 #if defined(LWS_WITH_RANGES)
3036 	unsigned char finished = 0;
3037 #endif
3038 #if defined(LWS_ROLE_H2)
3039 	struct lws *nwsi;
3040 #endif
3041 	int n, m;
3042 
3043 	lwsl_debug("wsi->mux_substream %d\n", wsi->mux_substream);
3044 
3045 	do {
3046 
3047 		/* priority 1: buffered output */
3048 
3049 		if (lws_has_buffered_out(wsi)) {
3050 			if (lws_issue_raw(wsi, NULL, 0) < 0) {
3051 				lwsl_info("%s: closing\n", __func__);
3052 				goto file_had_it;
3053 			}
3054 			break;
3055 		}
3056 
3057 		/* priority 2: buffered pre-compression-transform */
3058 
3059 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
3060 	if (wsi->http.comp_ctx.buflist_comp ||
3061 	    wsi->http.comp_ctx.may_have_more) {
3062 		enum lws_write_protocol wp = LWS_WRITE_HTTP;
3063 
3064 		lwsl_info("%s: completing comp partial (buflist %p, may %d)\n",
3065 			   __func__, wsi->http.comp_ctx.buflist_comp,
3066 			   wsi->http.comp_ctx.may_have_more);
3067 
3068 		if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol) &&
3069 		    lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol).
3070 					write_role_protocol(wsi, NULL, 0, &wp) < 0) {
3071 			lwsl_info("%s signalling to close\n", __func__);
3072 			goto file_had_it;
3073 		}
3074 		lws_callback_on_writable(wsi);
3075 
3076 		break;
3077 	}
3078 #endif
3079 
3080 		if (wsi->http.filepos == wsi->http.filelen)
3081 			goto all_sent;
3082 
3083 		n = 0;
3084 		p = pstart = pt->serv_buf + LWS_H2_FRAME_HEADER_LENGTH;
3085 
3086 #if defined(LWS_WITH_RANGES)
3087 		if (wsi->http.range.count_ranges && !wsi->http.range.inside) {
3088 
3089 			lwsl_notice("%s: doing range start %llu\n", __func__,
3090 				    wsi->http.range.start);
3091 
3092 			if ((long long)lws_vfs_file_seek_cur(wsi->http.fop_fd,
3093 						   (lws_fileofs_t)wsi->http.range.start -
3094 						   (lws_fileofs_t)wsi->http.filepos) < 0)
3095 				goto file_had_it;
3096 
3097 			wsi->http.filepos = wsi->http.range.start;
3098 
3099 			if (wsi->http.range.count_ranges > 1) {
3100 				n =  lws_snprintf((char *)p,
3101 						context->pt_serv_buf_size -
3102 						LWS_H2_FRAME_HEADER_LENGTH,
3103 					"_lws\x0d\x0a"
3104 					"Content-Type: %s\x0d\x0a"
3105 					"Content-Range: bytes "
3106 						"%llu-%llu/%llu\x0d\x0a"
3107 					"\x0d\x0a",
3108 					wsi->http.multipart_content_type,
3109 					wsi->http.range.start,
3110 					wsi->http.range.end,
3111 					wsi->http.range.extent);
3112 				p += n;
3113 			}
3114 
3115 			wsi->http.range.budget = wsi->http.range.end -
3116 						   wsi->http.range.start + 1;
3117 			wsi->http.range.inside = 1;
3118 		}
3119 #endif
3120 
3121 		poss = context->pt_serv_buf_size;
3122 
3123 #if defined(LWS_ROLE_H2)
3124 		/*
3125 		 * If it's h2, restrict any lump that we are sending to the
3126 		 * max h2 frame size the peer indicated he could handle in
3127 		 * his SETTINGS
3128 		 */
3129 		nwsi = lws_get_network_wsi(wsi);
3130 		if (nwsi->h2.h2n &&
3131 		    poss > (lws_filepos_t)nwsi->h2.h2n->peer_set.s[H2SET_MAX_FRAME_SIZE])
3132 			poss = (lws_filepos_t)nwsi->h2.h2n->peer_set.s[H2SET_MAX_FRAME_SIZE];
3133 #endif
3134 		poss = poss - (lws_filepos_t)(n + LWS_H2_FRAME_HEADER_LENGTH);
3135 
3136 		if (wsi->http.tx_content_length)
3137 			if (poss > wsi->http.tx_content_remain)
3138 				poss = wsi->http.tx_content_remain;
3139 
3140 		/*
3141 		 * If there is a hint about how much we will do well to send at
3142 		 * one time, restrict ourselves to only trying to send that.
3143 		 */
3144 		if (wsi->a.protocol->tx_packet_size &&
3145 		    poss > wsi->a.protocol->tx_packet_size)
3146 			poss = wsi->a.protocol->tx_packet_size;
3147 
3148 		if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_tx_credit)) {
3149 			lws_filepos_t txc = (unsigned int)lws_rops_func_fidx(wsi->role_ops,
3150 							       LWS_ROPS_tx_credit).
3151 					tx_credit(wsi, LWSTXCR_US_TO_PEER, 0);
3152 
3153 			if (!txc) {
3154 				/*
3155 				 * We shouldn't've been able to get the
3156 				 * WRITEABLE if we are skint
3157 				 */
3158 				lwsl_notice("%s: %s: no tx credit\n", __func__,
3159 						lws_wsi_tag(wsi));
3160 
3161 				return 0;
3162 			}
3163 			if (txc < poss)
3164 				poss = txc;
3165 
3166 			/*
3167 			 * Tracking consumption of the actual payload amount
3168 			 * will be handled when the role data frame is sent...
3169 			 */
3170 		}
3171 
3172 #if defined(LWS_WITH_RANGES)
3173 		if (wsi->http.range.count_ranges) {
3174 			if (wsi->http.range.count_ranges > 1)
3175 				poss -= 7; /* allow for final boundary */
3176 			if (poss > wsi->http.range.budget)
3177 				poss = wsi->http.range.budget;
3178 		}
3179 #endif
3180 		if (wsi->sending_chunked) {
3181 			/* we need to drop the chunk size in here */
3182 			p += 10;
3183 			/* allow for the chunk to grow by 128 in translation */
3184 			poss -= 10 + 128;
3185 		}
3186 
3187 		amount = 0;
3188 		if (lws_vfs_file_read(wsi->http.fop_fd, &amount, p, poss) < 0)
3189 			goto file_had_it; /* caller will close */
3190 
3191 		if (wsi->sending_chunked)
3192 			n = (int)amount;
3193 		else
3194 			n = lws_ptr_diff(p, pstart) + (int)amount;
3195 
3196 		lwsl_debug("%s: sending %d\n", __func__, n);
3197 
3198 		if (n) {
3199 			lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,
3200 					(int)context->timeout_secs);
3201 
3202 			if (wsi->interpreting) {
3203 				args.p = (char *)p;
3204 				args.len = n;
3205 				args.max_len = (int)(unsigned int)poss + 128;
3206 				args.final = wsi->http.filepos + (unsigned int)n ==
3207 							wsi->http.filelen;
3208 				args.chunked = wsi->sending_chunked;
3209 				if (user_callback_handle_rxflow(
3210 				     wsi->a.vhost->protocols[
3211 				     (int)wsi->protocol_interpret_idx].callback,
3212 				     wsi, LWS_CALLBACK_PROCESS_HTML,
3213 				     wsi->user_space, &args, 0) < 0)
3214 					goto file_had_it;
3215 				n = args.len;
3216 				p = (unsigned char *)args.p;
3217 			} else
3218 				p = pstart;
3219 
3220 #if defined(LWS_WITH_RANGES)
3221 			if (wsi->http.range.send_ctr + 1 ==
3222 				wsi->http.range.count_ranges && // last range
3223 			    wsi->http.range.count_ranges > 1 && // was 2+ ranges (ie, multipart)
3224 			    wsi->http.range.budget - amount == 0) {// final part
3225 				n += lws_snprintf((char *)pstart + n, 6,
3226 					"_lws\x0d\x0a"); // append trailing boundary
3227 				lwsl_debug("added trailing boundary\n");
3228 			}
3229 #endif
3230 			m = lws_write(wsi, p, (unsigned int)n, wsi->http.filepos + amount ==
3231 					wsi->http.filelen ?
3232 					 LWS_WRITE_HTTP_FINAL : LWS_WRITE_HTTP);
3233 			if (m < 0)
3234 				goto file_had_it;
3235 
3236 			wsi->http.filepos += amount;
3237 
3238 #if defined(LWS_WITH_RANGES)
3239 			if (wsi->http.range.count_ranges >= 1) {
3240 				wsi->http.range.budget -= amount;
3241 				if (wsi->http.range.budget == 0) {
3242 					lwsl_notice("range budget exhausted\n");
3243 					wsi->http.range.inside = 0;
3244 					wsi->http.range.send_ctr++;
3245 
3246 					if (lws_ranges_next(&wsi->http.range) < 1) {
3247 						finished = 1;
3248 						goto all_sent;
3249 					}
3250 				}
3251 			}
3252 #endif
3253 
3254 			if (m != n) {
3255 				/* adjust for what was not sent */
3256 				if (lws_vfs_file_seek_cur(wsi->http.fop_fd,
3257 							   m - n) ==
3258 							     (lws_fileofs_t)-1)
3259 					goto file_had_it;
3260 			}
3261 		}
3262 
3263 all_sent:
3264 		if ((!lws_has_buffered_out(wsi)
3265 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
3266 				&& !wsi->http.comp_ctx.buflist_comp &&
3267 		    !wsi->http.comp_ctx.may_have_more
3268 #endif
3269 		    ) && (wsi->http.filepos >= wsi->http.filelen
3270 #if defined(LWS_WITH_RANGES)
3271 		    || finished)
3272 #else
3273 		)
3274 #endif
3275 		) {
3276 			lwsi_set_state(wsi, LRS_ESTABLISHED);
3277 			/* we might be in keepalive, so close it off here */
3278 			lws_vfs_file_close(&wsi->http.fop_fd);
3279 
3280 			lwsl_debug("file completed\n");
3281 
3282 			if (wsi->a.protocol->callback &&
3283 			    user_callback_handle_rxflow(wsi->a.protocol->callback,
3284 					wsi, LWS_CALLBACK_HTTP_FILE_COMPLETION,
3285 					wsi->user_space, NULL, 0) < 0) {
3286 					/*
3287 					 * For http/1.x, the choices from
3288 					 * transaction_completed are either
3289 					 * 0 to use the connection for pipelined
3290 					 * or nonzero to hang it up.
3291 					 *
3292 					 * However for http/2. while we are
3293 					 * still interested in hanging up the
3294 					 * nwsi if there was a network-level
3295 					 * fatal error, simply completing the
3296 					 * transaction is a matter of the stream
3297 					 * state, not the root connection at the
3298 					 * network level
3299 					 */
3300 					if (wsi->mux_substream)
3301 						return 1;
3302 					else
3303 						return -1;
3304 				}
3305 
3306 			return 1;  /* >0 indicates completed */
3307 		}
3308 		/*
3309 		 * while(1) here causes us to spam the whole file contents into
3310 		 * a hugely bloated output buffer if it ever can't send the
3311 		 * whole chunk...
3312 		 */
3313 	} while (!lws_send_pipe_choked(wsi));
3314 
3315 	lws_callback_on_writable(wsi);
3316 
3317 	return 0; /* indicates further processing must be done */
3318 
3319 file_had_it:
3320 	lws_vfs_file_close(&wsi->http.fop_fd);
3321 
3322 	return -1;
3323 }
3324 
3325 #endif
3326 
3327 #if defined(LWS_WITH_SERVER)
3328 void
lws_server_get_canonical_hostname(struct lws_context * context,const struct lws_context_creation_info * info)3329 lws_server_get_canonical_hostname(struct lws_context *context,
3330 				  const struct lws_context_creation_info *info)
3331 {
3332 	if (lws_check_opt(info->options,
3333 			LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME))
3334 		return;
3335 #if !defined(LWS_PLAT_FREERTOS)
3336 	/* find canonical hostname */
3337 	if (gethostname((char *)context->canonical_hostname,
3338 		        sizeof(context->canonical_hostname) - 1))
3339 		lws_strncpy((char *)context->canonical_hostname, "unknown",
3340 			    sizeof(context->canonical_hostname));
3341 
3342 	lwsl_cx_info(context, " canonical_hostname = %s\n",
3343 					context->canonical_hostname);
3344 #else
3345 	(void)context;
3346 #endif
3347 }
3348 #endif
3349 
3350 int
lws_chunked_html_process(struct lws_process_html_args * args,struct lws_process_html_state * s)3351 lws_chunked_html_process(struct lws_process_html_args *args,
3352 			 struct lws_process_html_state *s)
3353 {
3354 	char *sp, buffer[32];
3355 	const char *pc;
3356 	int old_len, n;
3357 
3358 	/* do replacements */
3359 	sp = args->p;
3360 	old_len = args->len;
3361 	args->len = 0;
3362 	s->start = sp;
3363 	while (sp < args->p + old_len) {
3364 
3365 		if (args->len + 7 >= args->max_len) {
3366 			lwsl_err("Used up interpret padding\n");
3367 			return -1;
3368 		}
3369 
3370 		if ((!s->pos && *sp == '$') || s->pos) {
3371 			int hits = 0, hit = 0;
3372 
3373 			if (!s->pos)
3374 				s->start = sp;
3375 			s->swallow[s->pos++] = *sp;
3376 			if (s->pos == sizeof(s->swallow) - 1)
3377 				goto skip;
3378 			for (n = 0; n < s->count_vars; n++)
3379 				if (!strncmp(s->swallow, s->vars[n], (unsigned int)s->pos)) {
3380 					hits++;
3381 					hit = n;
3382 				}
3383 			if (!hits) {
3384 skip:
3385 				s->swallow[s->pos] = '\0';
3386 				memcpy(s->start, s->swallow, (unsigned int)s->pos);
3387 				args->len++;
3388 				s->pos = 0;
3389 				sp = s->start + 1;
3390 				continue;
3391 			}
3392 			if (hits == 1 && s->pos == (int)strlen(s->vars[hit])) {
3393 				pc = s->replace(s->data, hit);
3394 				if (!pc)
3395 					pc = "NULL";
3396 				n = (int)strlen(pc);
3397 				s->swallow[s->pos] = '\0';
3398 				if (n != s->pos) {
3399 					memmove(s->start + n, s->start + s->pos,
3400 						(unsigned int)(old_len - (sp - args->p) - 1));
3401 					old_len += (n - s->pos) + 1;
3402 				}
3403 				memcpy(s->start, pc, (unsigned int)n);
3404 				args->len++;
3405 				sp = s->start + 1;
3406 
3407 				s->pos = 0;
3408 			}
3409 			sp++;
3410 			continue;
3411 		}
3412 
3413 		args->len++;
3414 		sp++;
3415 	}
3416 
3417 	if (args->chunked) {
3418 		/* no space left for final chunk trailer */
3419 		if (args->final && args->len + 7 >= args->max_len)
3420 			return -1;
3421 
3422 		n = sprintf(buffer, "%X\x0d\x0a", args->len);
3423 
3424 		args->p -= n;
3425 		memcpy(args->p, buffer, (unsigned int)n);
3426 		args->len += n;
3427 
3428 		if (args->final) {
3429 			sp = args->p + args->len;
3430 			*sp++ = '\x0d';
3431 			*sp++ = '\x0a';
3432 			*sp++ = '0';
3433 			*sp++ = '\x0d';
3434 			*sp++ = '\x0a';
3435 			*sp++ = '\x0d';
3436 			*sp++ = '\x0a';
3437 			args->len += 7;
3438 		} else {
3439 			sp = args->p + args->len;
3440 			*sp++ = '\x0d';
3441 			*sp++ = '\x0a';
3442 			args->len += 2;
3443 		}
3444 	}
3445 
3446 	return 0;
3447 }
3448