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