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_cistatic const unsigned char lextable_h1[] = {
28d4afb5ceSopenharmony_ci	#include "lextable.h"
29d4afb5ceSopenharmony_ci};
30d4afb5ceSopenharmony_ci
31d4afb5ceSopenharmony_ci#define FAIL_CHAR 0x08
32d4afb5ceSopenharmony_ci
33d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CUSTOM_HEADERS)
34d4afb5ceSopenharmony_ci
35d4afb5ceSopenharmony_ci#define UHO_NLEN	0
36d4afb5ceSopenharmony_ci#define UHO_VLEN	2
37d4afb5ceSopenharmony_ci#define UHO_LL		4
38d4afb5ceSopenharmony_ci#define UHO_NAME	8
39d4afb5ceSopenharmony_ci
40d4afb5ceSopenharmony_ci#endif
41d4afb5ceSopenharmony_ci
42d4afb5ceSopenharmony_cistatic struct allocated_headers *
43d4afb5ceSopenharmony_ci_lws_create_ah(struct lws_context_per_thread *pt, ah_data_idx_t data_size)
44d4afb5ceSopenharmony_ci{
45d4afb5ceSopenharmony_ci	struct allocated_headers *ah = lws_zalloc(sizeof(*ah), "ah struct");
46d4afb5ceSopenharmony_ci
47d4afb5ceSopenharmony_ci	if (!ah)
48d4afb5ceSopenharmony_ci		return NULL;
49d4afb5ceSopenharmony_ci
50d4afb5ceSopenharmony_ci	ah->data = lws_malloc(data_size, "ah data");
51d4afb5ceSopenharmony_ci	if (!ah->data) {
52d4afb5ceSopenharmony_ci		lws_free(ah);
53d4afb5ceSopenharmony_ci
54d4afb5ceSopenharmony_ci		return NULL;
55d4afb5ceSopenharmony_ci	}
56d4afb5ceSopenharmony_ci	ah->next = pt->http.ah_list;
57d4afb5ceSopenharmony_ci	pt->http.ah_list = ah;
58d4afb5ceSopenharmony_ci	ah->data_length = data_size;
59d4afb5ceSopenharmony_ci	pt->http.ah_pool_length++;
60d4afb5ceSopenharmony_ci
61d4afb5ceSopenharmony_ci	lwsl_info("%s: created ah %p (size %d): pool length %u\n", __func__,
62d4afb5ceSopenharmony_ci		    ah, (int)data_size, (unsigned int)pt->http.ah_pool_length);
63d4afb5ceSopenharmony_ci
64d4afb5ceSopenharmony_ci	return ah;
65d4afb5ceSopenharmony_ci}
66d4afb5ceSopenharmony_ci
67d4afb5ceSopenharmony_ciint
68d4afb5ceSopenharmony_ci_lws_destroy_ah(struct lws_context_per_thread *pt, struct allocated_headers *ah)
69d4afb5ceSopenharmony_ci{
70d4afb5ceSopenharmony_ci	lws_start_foreach_llp(struct allocated_headers **, a, pt->http.ah_list) {
71d4afb5ceSopenharmony_ci		if ((*a) == ah) {
72d4afb5ceSopenharmony_ci			*a = ah->next;
73d4afb5ceSopenharmony_ci			pt->http.ah_pool_length--;
74d4afb5ceSopenharmony_ci			lwsl_info("%s: freed ah %p : pool length %u\n",
75d4afb5ceSopenharmony_ci				    __func__, ah,
76d4afb5ceSopenharmony_ci				    (unsigned int)pt->http.ah_pool_length);
77d4afb5ceSopenharmony_ci			if (ah->data)
78d4afb5ceSopenharmony_ci				lws_free(ah->data);
79d4afb5ceSopenharmony_ci			lws_free(ah);
80d4afb5ceSopenharmony_ci
81d4afb5ceSopenharmony_ci			return 0;
82d4afb5ceSopenharmony_ci		}
83d4afb5ceSopenharmony_ci	} lws_end_foreach_llp(a, next);
84d4afb5ceSopenharmony_ci
85d4afb5ceSopenharmony_ci	return 1;
86d4afb5ceSopenharmony_ci}
87d4afb5ceSopenharmony_ci
88d4afb5ceSopenharmony_civoid
89d4afb5ceSopenharmony_ci_lws_header_table_reset(struct allocated_headers *ah)
90d4afb5ceSopenharmony_ci{
91d4afb5ceSopenharmony_ci	/* init the ah to reflect no headers or data have appeared yet */
92d4afb5ceSopenharmony_ci	memset(ah->frag_index, 0, sizeof(ah->frag_index));
93d4afb5ceSopenharmony_ci	memset(ah->frags, 0, sizeof(ah->frags));
94d4afb5ceSopenharmony_ci	ah->nfrag = 0;
95d4afb5ceSopenharmony_ci	ah->pos = 0;
96d4afb5ceSopenharmony_ci	ah->http_response = 0;
97d4afb5ceSopenharmony_ci	ah->parser_state = WSI_TOKEN_NAME_PART;
98d4afb5ceSopenharmony_ci	ah->lextable_pos = 0;
99d4afb5ceSopenharmony_ci	ah->unk_pos = 0;
100d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CUSTOM_HEADERS)
101d4afb5ceSopenharmony_ci	ah->unk_ll_head = 0;
102d4afb5ceSopenharmony_ci	ah->unk_ll_tail = 0;
103d4afb5ceSopenharmony_ci#endif
104d4afb5ceSopenharmony_ci}
105d4afb5ceSopenharmony_ci
106d4afb5ceSopenharmony_ci// doesn't scrub the ah rxbuffer by default, parent must do if needed
107d4afb5ceSopenharmony_ci
108d4afb5ceSopenharmony_civoid
109d4afb5ceSopenharmony_ci__lws_header_table_reset(struct lws *wsi, int autoservice)
110d4afb5ceSopenharmony_ci{
111d4afb5ceSopenharmony_ci	struct allocated_headers *ah = wsi->http.ah;
112d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt;
113d4afb5ceSopenharmony_ci	struct lws_pollfd *pfd;
114d4afb5ceSopenharmony_ci
115d4afb5ceSopenharmony_ci	/* if we have the idea we're resetting 'our' ah, must be bound to one */
116d4afb5ceSopenharmony_ci	assert(ah);
117d4afb5ceSopenharmony_ci	/* ah also concurs with ownership */
118d4afb5ceSopenharmony_ci	assert(ah->wsi == wsi);
119d4afb5ceSopenharmony_ci
120d4afb5ceSopenharmony_ci	_lws_header_table_reset(ah);
121d4afb5ceSopenharmony_ci
122d4afb5ceSopenharmony_ci	/* since we will restart the ah, our new headers are not completed */
123d4afb5ceSopenharmony_ci	wsi->hdr_parsing_completed = 0;
124d4afb5ceSopenharmony_ci
125d4afb5ceSopenharmony_ci	/* while we hold the ah, keep a timeout on the wsi */
126d4afb5ceSopenharmony_ci	__lws_set_timeout(wsi, PENDING_TIMEOUT_HOLDING_AH,
127d4afb5ceSopenharmony_ci			  wsi->a.vhost->timeout_secs_ah_idle);
128d4afb5ceSopenharmony_ci
129d4afb5ceSopenharmony_ci	time(&ah->assigned);
130d4afb5ceSopenharmony_ci
131d4afb5ceSopenharmony_ci	if (wsi->position_in_fds_table != LWS_NO_FDS_POS &&
132d4afb5ceSopenharmony_ci	    lws_buflist_next_segment_len(&wsi->buflist, NULL) &&
133d4afb5ceSopenharmony_ci	    autoservice) {
134d4afb5ceSopenharmony_ci		lwsl_debug("%s: service on readbuf ah\n", __func__);
135d4afb5ceSopenharmony_ci
136d4afb5ceSopenharmony_ci		pt = &wsi->a.context->pt[(int)wsi->tsi];
137d4afb5ceSopenharmony_ci		/*
138d4afb5ceSopenharmony_ci		 * Unlike a normal connect, we have the headers already
139d4afb5ceSopenharmony_ci		 * (or the first part of them anyway)
140d4afb5ceSopenharmony_ci		 */
141d4afb5ceSopenharmony_ci		pfd = &pt->fds[wsi->position_in_fds_table];
142d4afb5ceSopenharmony_ci		pfd->revents |= LWS_POLLIN;
143d4afb5ceSopenharmony_ci		lwsl_err("%s: calling service\n", __func__);
144d4afb5ceSopenharmony_ci		lws_service_fd_tsi(wsi->a.context, pfd, wsi->tsi);
145d4afb5ceSopenharmony_ci	}
146d4afb5ceSopenharmony_ci}
147d4afb5ceSopenharmony_ci
148d4afb5ceSopenharmony_civoid
149d4afb5ceSopenharmony_cilws_header_table_reset(struct lws *wsi, int autoservice)
150d4afb5ceSopenharmony_ci{
151d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
152d4afb5ceSopenharmony_ci
153d4afb5ceSopenharmony_ci	lws_pt_lock(pt, __func__);
154d4afb5ceSopenharmony_ci
155d4afb5ceSopenharmony_ci	__lws_header_table_reset(wsi, autoservice);
156d4afb5ceSopenharmony_ci
157d4afb5ceSopenharmony_ci	lws_pt_unlock(pt);
158d4afb5ceSopenharmony_ci}
159d4afb5ceSopenharmony_ci
160d4afb5ceSopenharmony_cistatic void
161d4afb5ceSopenharmony_ci_lws_header_ensure_we_are_on_waiting_list(struct lws *wsi)
162d4afb5ceSopenharmony_ci{
163d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
164d4afb5ceSopenharmony_ci	struct lws_pollargs pa;
165d4afb5ceSopenharmony_ci	struct lws **pwsi = &pt->http.ah_wait_list;
166d4afb5ceSopenharmony_ci
167d4afb5ceSopenharmony_ci	while (*pwsi) {
168d4afb5ceSopenharmony_ci		if (*pwsi == wsi)
169d4afb5ceSopenharmony_ci			return;
170d4afb5ceSopenharmony_ci		pwsi = &(*pwsi)->http.ah_wait_list;
171d4afb5ceSopenharmony_ci	}
172d4afb5ceSopenharmony_ci
173d4afb5ceSopenharmony_ci	lwsl_info("%s: wsi: %s\n", __func__, lws_wsi_tag(wsi));
174d4afb5ceSopenharmony_ci	wsi->http.ah_wait_list = pt->http.ah_wait_list;
175d4afb5ceSopenharmony_ci	pt->http.ah_wait_list = wsi;
176d4afb5ceSopenharmony_ci	pt->http.ah_wait_list_length++;
177d4afb5ceSopenharmony_ci
178d4afb5ceSopenharmony_ci	/* we cannot accept input then */
179d4afb5ceSopenharmony_ci
180d4afb5ceSopenharmony_ci	_lws_change_pollfd(wsi, LWS_POLLIN, 0, &pa);
181d4afb5ceSopenharmony_ci}
182d4afb5ceSopenharmony_ci
183d4afb5ceSopenharmony_cistatic int
184d4afb5ceSopenharmony_ci__lws_remove_from_ah_waiting_list(struct lws *wsi)
185d4afb5ceSopenharmony_ci{
186d4afb5ceSopenharmony_ci        struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
187d4afb5ceSopenharmony_ci	struct lws **pwsi =&pt->http.ah_wait_list;
188d4afb5ceSopenharmony_ci
189d4afb5ceSopenharmony_ci	while (*pwsi) {
190d4afb5ceSopenharmony_ci		if (*pwsi == wsi) {
191d4afb5ceSopenharmony_ci			lwsl_info("%s: wsi %s\n", __func__, lws_wsi_tag(wsi));
192d4afb5ceSopenharmony_ci			/* point prev guy to our next */
193d4afb5ceSopenharmony_ci			*pwsi = wsi->http.ah_wait_list;
194d4afb5ceSopenharmony_ci			/* we shouldn't point anywhere now */
195d4afb5ceSopenharmony_ci			wsi->http.ah_wait_list = NULL;
196d4afb5ceSopenharmony_ci			pt->http.ah_wait_list_length--;
197d4afb5ceSopenharmony_ci
198d4afb5ceSopenharmony_ci			return 1;
199d4afb5ceSopenharmony_ci		}
200d4afb5ceSopenharmony_ci		pwsi = &(*pwsi)->http.ah_wait_list;
201d4afb5ceSopenharmony_ci	}
202d4afb5ceSopenharmony_ci
203d4afb5ceSopenharmony_ci	return 0;
204d4afb5ceSopenharmony_ci}
205d4afb5ceSopenharmony_ci
206d4afb5ceSopenharmony_ciint LWS_WARN_UNUSED_RESULT
207d4afb5ceSopenharmony_cilws_header_table_attach(struct lws *wsi, int autoservice)
208d4afb5ceSopenharmony_ci{
209d4afb5ceSopenharmony_ci	struct lws_context *context = wsi->a.context;
210d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
211d4afb5ceSopenharmony_ci	struct lws_pollargs pa;
212d4afb5ceSopenharmony_ci	int n;
213d4afb5ceSopenharmony_ci
214d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_MQTT) && defined(LWS_WITH_CLIENT)
215d4afb5ceSopenharmony_ci	if (lwsi_role_mqtt(wsi))
216d4afb5ceSopenharmony_ci		goto connect_via_info2;
217d4afb5ceSopenharmony_ci#endif
218d4afb5ceSopenharmony_ci
219d4afb5ceSopenharmony_ci	lwsl_info("%s: %s: ah %p (tsi %d, count = %d) in\n", __func__,
220d4afb5ceSopenharmony_ci		  lws_wsi_tag(wsi), (void *)wsi->http.ah, wsi->tsi,
221d4afb5ceSopenharmony_ci		  pt->http.ah_count_in_use);
222d4afb5ceSopenharmony_ci
223d4afb5ceSopenharmony_ci	if (!lwsi_role_http(wsi)) {
224d4afb5ceSopenharmony_ci		lwsl_err("%s: bad role %s\n", __func__, wsi->role_ops->name);
225d4afb5ceSopenharmony_ci		assert(0);
226d4afb5ceSopenharmony_ci		return -1;
227d4afb5ceSopenharmony_ci	}
228d4afb5ceSopenharmony_ci
229d4afb5ceSopenharmony_ci	lws_pt_lock(pt, __func__);
230d4afb5ceSopenharmony_ci
231d4afb5ceSopenharmony_ci	/* if we are already bound to one, just clear it down */
232d4afb5ceSopenharmony_ci	if (wsi->http.ah) {
233d4afb5ceSopenharmony_ci		lwsl_info("%s: cleardown\n", __func__);
234d4afb5ceSopenharmony_ci		goto reset;
235d4afb5ceSopenharmony_ci	}
236d4afb5ceSopenharmony_ci
237d4afb5ceSopenharmony_ci	n = pt->http.ah_count_in_use == (int)context->max_http_header_pool;
238d4afb5ceSopenharmony_ci#if defined(LWS_WITH_PEER_LIMITS)
239d4afb5ceSopenharmony_ci	if (!n)
240d4afb5ceSopenharmony_ci		n = lws_peer_confirm_ah_attach_ok(context, wsi->peer);
241d4afb5ceSopenharmony_ci#endif
242d4afb5ceSopenharmony_ci	if (n) {
243d4afb5ceSopenharmony_ci		/*
244d4afb5ceSopenharmony_ci		 * Pool is either all busy, or we don't want to give this
245d4afb5ceSopenharmony_ci		 * particular guy an ah right now...
246d4afb5ceSopenharmony_ci		 *
247d4afb5ceSopenharmony_ci		 * Make sure we are on the waiting list, and return that we
248d4afb5ceSopenharmony_ci		 * weren't able to provide the ah
249d4afb5ceSopenharmony_ci		 */
250d4afb5ceSopenharmony_ci		_lws_header_ensure_we_are_on_waiting_list(wsi);
251d4afb5ceSopenharmony_ci
252d4afb5ceSopenharmony_ci		goto bail;
253d4afb5ceSopenharmony_ci	}
254d4afb5ceSopenharmony_ci
255d4afb5ceSopenharmony_ci	__lws_remove_from_ah_waiting_list(wsi);
256d4afb5ceSopenharmony_ci
257d4afb5ceSopenharmony_ci	wsi->http.ah = _lws_create_ah(pt, context->max_http_header_data);
258d4afb5ceSopenharmony_ci	if (!wsi->http.ah) { /* we could not create an ah */
259d4afb5ceSopenharmony_ci		_lws_header_ensure_we_are_on_waiting_list(wsi);
260d4afb5ceSopenharmony_ci
261d4afb5ceSopenharmony_ci		goto bail;
262d4afb5ceSopenharmony_ci	}
263d4afb5ceSopenharmony_ci
264d4afb5ceSopenharmony_ci	wsi->http.ah->in_use = 1;
265d4afb5ceSopenharmony_ci	wsi->http.ah->wsi = wsi; /* mark our owner */
266d4afb5ceSopenharmony_ci	pt->http.ah_count_in_use++;
267d4afb5ceSopenharmony_ci
268d4afb5ceSopenharmony_ci#if defined(LWS_WITH_PEER_LIMITS) && (defined(LWS_ROLE_H1) || \
269d4afb5ceSopenharmony_ci    defined(LWS_ROLE_H2))
270d4afb5ceSopenharmony_ci	lws_context_lock(context, "ah attach"); /* <========================= */
271d4afb5ceSopenharmony_ci	if (wsi->peer)
272d4afb5ceSopenharmony_ci		wsi->peer->http.count_ah++;
273d4afb5ceSopenharmony_ci	lws_context_unlock(context); /* ====================================> */
274d4afb5ceSopenharmony_ci#endif
275d4afb5ceSopenharmony_ci
276d4afb5ceSopenharmony_ci	_lws_change_pollfd(wsi, 0, LWS_POLLIN, &pa);
277d4afb5ceSopenharmony_ci
278d4afb5ceSopenharmony_ci	lwsl_info("%s: did attach wsi %s: ah %p: count %d (on exit)\n", __func__,
279d4afb5ceSopenharmony_ci		  lws_wsi_tag(wsi), (void *)wsi->http.ah, pt->http.ah_count_in_use);
280d4afb5ceSopenharmony_ci
281d4afb5ceSopenharmony_cireset:
282d4afb5ceSopenharmony_ci	__lws_header_table_reset(wsi, autoservice);
283d4afb5ceSopenharmony_ci
284d4afb5ceSopenharmony_ci	lws_pt_unlock(pt);
285d4afb5ceSopenharmony_ci
286d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
287d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_MQTT)
288d4afb5ceSopenharmony_ciconnect_via_info2:
289d4afb5ceSopenharmony_ci#endif
290d4afb5ceSopenharmony_ci	if (lwsi_role_client(wsi) && lwsi_state(wsi) == LRS_UNCONNECTED)
291d4afb5ceSopenharmony_ci		if (!lws_http_client_connect_via_info2(wsi))
292d4afb5ceSopenharmony_ci			/* our client connect has failed, the wsi
293d4afb5ceSopenharmony_ci			 * has been closed
294d4afb5ceSopenharmony_ci			 */
295d4afb5ceSopenharmony_ci			return -1;
296d4afb5ceSopenharmony_ci#endif
297d4afb5ceSopenharmony_ci
298d4afb5ceSopenharmony_ci	return 0;
299d4afb5ceSopenharmony_ci
300d4afb5ceSopenharmony_cibail:
301d4afb5ceSopenharmony_ci	lws_pt_unlock(pt);
302d4afb5ceSopenharmony_ci
303d4afb5ceSopenharmony_ci	return 1;
304d4afb5ceSopenharmony_ci}
305d4afb5ceSopenharmony_ci
306d4afb5ceSopenharmony_ciint __lws_header_table_detach(struct lws *wsi, int autoservice)
307d4afb5ceSopenharmony_ci{
308d4afb5ceSopenharmony_ci	struct lws_context *context = wsi->a.context;
309d4afb5ceSopenharmony_ci	struct allocated_headers *ah = wsi->http.ah;
310d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
311d4afb5ceSopenharmony_ci	struct lws_pollargs pa;
312d4afb5ceSopenharmony_ci	struct lws **pwsi, **pwsi_eligible;
313d4afb5ceSopenharmony_ci	time_t now;
314d4afb5ceSopenharmony_ci
315d4afb5ceSopenharmony_ci	__lws_remove_from_ah_waiting_list(wsi);
316d4afb5ceSopenharmony_ci
317d4afb5ceSopenharmony_ci	if (!ah)
318d4afb5ceSopenharmony_ci		return 0;
319d4afb5ceSopenharmony_ci
320d4afb5ceSopenharmony_ci	lwsl_info("%s: %s: ah %p (tsi=%d, count = %d)\n", __func__,
321d4afb5ceSopenharmony_ci		  lws_wsi_tag(wsi), (void *)ah, wsi->tsi,
322d4afb5ceSopenharmony_ci		  pt->http.ah_count_in_use);
323d4afb5ceSopenharmony_ci
324d4afb5ceSopenharmony_ci	/* we did have an ah attached */
325d4afb5ceSopenharmony_ci	time(&now);
326d4afb5ceSopenharmony_ci	if (ah->assigned && now - ah->assigned > 3) {
327d4afb5ceSopenharmony_ci		/*
328d4afb5ceSopenharmony_ci		 * we're detaching the ah, but it was held an
329d4afb5ceSopenharmony_ci		 * unreasonably long time
330d4afb5ceSopenharmony_ci		 */
331d4afb5ceSopenharmony_ci		lwsl_debug("%s: %s: ah held %ds, role/state 0x%lx 0x%x,"
332d4afb5ceSopenharmony_ci			    "\n", __func__, lws_wsi_tag(wsi),
333d4afb5ceSopenharmony_ci			    (int)(now - ah->assigned),
334d4afb5ceSopenharmony_ci			    (unsigned long)lwsi_role(wsi), lwsi_state(wsi));
335d4afb5ceSopenharmony_ci	}
336d4afb5ceSopenharmony_ci
337d4afb5ceSopenharmony_ci	ah->assigned = 0;
338d4afb5ceSopenharmony_ci
339d4afb5ceSopenharmony_ci	/* if we think we're detaching one, there should be one in use */
340d4afb5ceSopenharmony_ci	assert(pt->http.ah_count_in_use > 0);
341d4afb5ceSopenharmony_ci	/* and this specific one should have been in use */
342d4afb5ceSopenharmony_ci	assert(ah->in_use);
343d4afb5ceSopenharmony_ci	memset(&wsi->http.ah, 0, sizeof(wsi->http.ah));
344d4afb5ceSopenharmony_ci
345d4afb5ceSopenharmony_ci#if defined(LWS_WITH_PEER_LIMITS)
346d4afb5ceSopenharmony_ci	if (ah->wsi)
347d4afb5ceSopenharmony_ci		lws_peer_track_ah_detach(context, wsi->peer);
348d4afb5ceSopenharmony_ci#endif
349d4afb5ceSopenharmony_ci	ah->wsi = NULL; /* no owner */
350d4afb5ceSopenharmony_ci	wsi->http.ah = NULL;
351d4afb5ceSopenharmony_ci
352d4afb5ceSopenharmony_ci	pwsi = &pt->http.ah_wait_list;
353d4afb5ceSopenharmony_ci
354d4afb5ceSopenharmony_ci	/* oh there is nobody on the waiting list... leave the ah unattached */
355d4afb5ceSopenharmony_ci	if (!*pwsi)
356d4afb5ceSopenharmony_ci		goto nobody_usable_waiting;
357d4afb5ceSopenharmony_ci
358d4afb5ceSopenharmony_ci	/*
359d4afb5ceSopenharmony_ci	 * at least one wsi on the same tsi is waiting, give it to oldest guy
360d4afb5ceSopenharmony_ci	 * who is allowed to take it (if any)
361d4afb5ceSopenharmony_ci	 */
362d4afb5ceSopenharmony_ci	lwsl_info("%s: pt wait list %s\n", __func__, lws_wsi_tag(*pwsi));
363d4afb5ceSopenharmony_ci	wsi = NULL;
364d4afb5ceSopenharmony_ci	pwsi_eligible = NULL;
365d4afb5ceSopenharmony_ci
366d4afb5ceSopenharmony_ci	while (*pwsi) {
367d4afb5ceSopenharmony_ci#if defined(LWS_WITH_PEER_LIMITS)
368d4afb5ceSopenharmony_ci		/* are we willing to give this guy an ah? */
369d4afb5ceSopenharmony_ci		if (!lws_peer_confirm_ah_attach_ok(context, (*pwsi)->peer))
370d4afb5ceSopenharmony_ci#endif
371d4afb5ceSopenharmony_ci		{
372d4afb5ceSopenharmony_ci			wsi = *pwsi;
373d4afb5ceSopenharmony_ci			pwsi_eligible = pwsi;
374d4afb5ceSopenharmony_ci		}
375d4afb5ceSopenharmony_ci
376d4afb5ceSopenharmony_ci		pwsi = &(*pwsi)->http.ah_wait_list;
377d4afb5ceSopenharmony_ci	}
378d4afb5ceSopenharmony_ci
379d4afb5ceSopenharmony_ci	if (!wsi) /* everybody waiting already has too many ah... */
380d4afb5ceSopenharmony_ci		goto nobody_usable_waiting;
381d4afb5ceSopenharmony_ci
382d4afb5ceSopenharmony_ci	lwsl_info("%s: transferring ah to last eligible wsi in wait list "
383d4afb5ceSopenharmony_ci		  "%s (wsistate 0x%lx)\n", __func__, lws_wsi_tag(wsi),
384d4afb5ceSopenharmony_ci		  (unsigned long)wsi->wsistate);
385d4afb5ceSopenharmony_ci
386d4afb5ceSopenharmony_ci	wsi->http.ah = ah;
387d4afb5ceSopenharmony_ci	ah->wsi = wsi; /* new owner */
388d4afb5ceSopenharmony_ci
389d4afb5ceSopenharmony_ci	__lws_header_table_reset(wsi, autoservice);
390d4afb5ceSopenharmony_ci#if defined(LWS_WITH_PEER_LIMITS) && (defined(LWS_ROLE_H1) || \
391d4afb5ceSopenharmony_ci    defined(LWS_ROLE_H2))
392d4afb5ceSopenharmony_ci	lws_context_lock(context, "ah detach"); /* <========================= */
393d4afb5ceSopenharmony_ci	if (wsi->peer)
394d4afb5ceSopenharmony_ci		wsi->peer->http.count_ah++;
395d4afb5ceSopenharmony_ci	lws_context_unlock(context); /* ====================================> */
396d4afb5ceSopenharmony_ci#endif
397d4afb5ceSopenharmony_ci
398d4afb5ceSopenharmony_ci	/* clients acquire the ah and then insert themselves in fds table... */
399d4afb5ceSopenharmony_ci	if (wsi->position_in_fds_table != LWS_NO_FDS_POS) {
400d4afb5ceSopenharmony_ci		lwsl_info("%s: Enabling %s POLLIN\n", __func__, lws_wsi_tag(wsi));
401d4afb5ceSopenharmony_ci
402d4afb5ceSopenharmony_ci		/* he has been stuck waiting for an ah, but now his wait is
403d4afb5ceSopenharmony_ci		 * over, let him progress */
404d4afb5ceSopenharmony_ci
405d4afb5ceSopenharmony_ci		_lws_change_pollfd(wsi, 0, LWS_POLLIN, &pa);
406d4afb5ceSopenharmony_ci	}
407d4afb5ceSopenharmony_ci
408d4afb5ceSopenharmony_ci	/* point prev guy to next guy in list instead */
409d4afb5ceSopenharmony_ci	*pwsi_eligible = wsi->http.ah_wait_list;
410d4afb5ceSopenharmony_ci	/* the guy who got one is out of the list */
411d4afb5ceSopenharmony_ci	wsi->http.ah_wait_list = NULL;
412d4afb5ceSopenharmony_ci	pt->http.ah_wait_list_length--;
413d4afb5ceSopenharmony_ci
414d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
415d4afb5ceSopenharmony_ci	if (lwsi_role_client(wsi) && lwsi_state(wsi) == LRS_UNCONNECTED) {
416d4afb5ceSopenharmony_ci		lws_pt_unlock(pt);
417d4afb5ceSopenharmony_ci
418d4afb5ceSopenharmony_ci		if (!lws_http_client_connect_via_info2(wsi)) {
419d4afb5ceSopenharmony_ci			/* our client connect has failed, the wsi
420d4afb5ceSopenharmony_ci			 * has been closed
421d4afb5ceSopenharmony_ci			 */
422d4afb5ceSopenharmony_ci
423d4afb5ceSopenharmony_ci			return -1;
424d4afb5ceSopenharmony_ci		}
425d4afb5ceSopenharmony_ci		return 0;
426d4afb5ceSopenharmony_ci	}
427d4afb5ceSopenharmony_ci#endif
428d4afb5ceSopenharmony_ci
429d4afb5ceSopenharmony_ci	assert(!!pt->http.ah_wait_list_length ==
430d4afb5ceSopenharmony_ci			!!(lws_intptr_t)pt->http.ah_wait_list);
431d4afb5ceSopenharmony_cibail:
432d4afb5ceSopenharmony_ci	lwsl_info("%s: %s: ah %p (tsi=%d, count = %d)\n", __func__,
433d4afb5ceSopenharmony_ci		  lws_wsi_tag(wsi), (void *)ah, pt->tid, pt->http.ah_count_in_use);
434d4afb5ceSopenharmony_ci
435d4afb5ceSopenharmony_ci	return 0;
436d4afb5ceSopenharmony_ci
437d4afb5ceSopenharmony_cinobody_usable_waiting:
438d4afb5ceSopenharmony_ci	lwsl_info("%s: nobody usable waiting\n", __func__);
439d4afb5ceSopenharmony_ci	_lws_destroy_ah(pt, ah);
440d4afb5ceSopenharmony_ci	pt->http.ah_count_in_use--;
441d4afb5ceSopenharmony_ci
442d4afb5ceSopenharmony_ci	goto bail;
443d4afb5ceSopenharmony_ci}
444d4afb5ceSopenharmony_ci
445d4afb5ceSopenharmony_ciint lws_header_table_detach(struct lws *wsi, int autoservice)
446d4afb5ceSopenharmony_ci{
447d4afb5ceSopenharmony_ci	struct lws_context *context = wsi->a.context;
448d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
449d4afb5ceSopenharmony_ci	int n;
450d4afb5ceSopenharmony_ci
451d4afb5ceSopenharmony_ci	lws_pt_lock(pt, __func__);
452d4afb5ceSopenharmony_ci	n = __lws_header_table_detach(wsi, autoservice);
453d4afb5ceSopenharmony_ci	lws_pt_unlock(pt);
454d4afb5ceSopenharmony_ci
455d4afb5ceSopenharmony_ci	return n;
456d4afb5ceSopenharmony_ci}
457d4afb5ceSopenharmony_ci
458d4afb5ceSopenharmony_ciint
459d4afb5ceSopenharmony_cilws_hdr_fragment_length(struct lws *wsi, enum lws_token_indexes h, int frag_idx)
460d4afb5ceSopenharmony_ci{
461d4afb5ceSopenharmony_ci	int n;
462d4afb5ceSopenharmony_ci
463d4afb5ceSopenharmony_ci	if (!wsi->http.ah)
464d4afb5ceSopenharmony_ci		return 0;
465d4afb5ceSopenharmony_ci
466d4afb5ceSopenharmony_ci	n = wsi->http.ah->frag_index[h];
467d4afb5ceSopenharmony_ci	if (!n)
468d4afb5ceSopenharmony_ci		return 0;
469d4afb5ceSopenharmony_ci	do {
470d4afb5ceSopenharmony_ci		if (!frag_idx)
471d4afb5ceSopenharmony_ci			return wsi->http.ah->frags[n].len;
472d4afb5ceSopenharmony_ci		n = wsi->http.ah->frags[n].nfrag;
473d4afb5ceSopenharmony_ci	} while (frag_idx-- && n);
474d4afb5ceSopenharmony_ci
475d4afb5ceSopenharmony_ci	return 0;
476d4afb5ceSopenharmony_ci}
477d4afb5ceSopenharmony_ci
478d4afb5ceSopenharmony_ciint lws_hdr_total_length(struct lws *wsi, enum lws_token_indexes h)
479d4afb5ceSopenharmony_ci{
480d4afb5ceSopenharmony_ci	int n;
481d4afb5ceSopenharmony_ci	int len = 0;
482d4afb5ceSopenharmony_ci
483d4afb5ceSopenharmony_ci	if (!wsi->http.ah)
484d4afb5ceSopenharmony_ci		return 0;
485d4afb5ceSopenharmony_ci
486d4afb5ceSopenharmony_ci	n = wsi->http.ah->frag_index[h];
487d4afb5ceSopenharmony_ci	if (!n)
488d4afb5ceSopenharmony_ci		return 0;
489d4afb5ceSopenharmony_ci	do {
490d4afb5ceSopenharmony_ci		len += wsi->http.ah->frags[n].len;
491d4afb5ceSopenharmony_ci		n = wsi->http.ah->frags[n].nfrag;
492d4afb5ceSopenharmony_ci
493d4afb5ceSopenharmony_ci		if (n)
494d4afb5ceSopenharmony_ci			len++;
495d4afb5ceSopenharmony_ci
496d4afb5ceSopenharmony_ci	} while (n);
497d4afb5ceSopenharmony_ci
498d4afb5ceSopenharmony_ci	return len;
499d4afb5ceSopenharmony_ci}
500d4afb5ceSopenharmony_ci
501d4afb5ceSopenharmony_ciint lws_hdr_copy_fragment(struct lws *wsi, char *dst, int len,
502d4afb5ceSopenharmony_ci				      enum lws_token_indexes h, int frag_idx)
503d4afb5ceSopenharmony_ci{
504d4afb5ceSopenharmony_ci	int n = 0;
505d4afb5ceSopenharmony_ci	int f;
506d4afb5ceSopenharmony_ci
507d4afb5ceSopenharmony_ci	if (!wsi->http.ah)
508d4afb5ceSopenharmony_ci		return -1;
509d4afb5ceSopenharmony_ci
510d4afb5ceSopenharmony_ci	f = wsi->http.ah->frag_index[h];
511d4afb5ceSopenharmony_ci
512d4afb5ceSopenharmony_ci	if (!f)
513d4afb5ceSopenharmony_ci		return -1;
514d4afb5ceSopenharmony_ci
515d4afb5ceSopenharmony_ci	while (n < frag_idx) {
516d4afb5ceSopenharmony_ci		f = wsi->http.ah->frags[f].nfrag;
517d4afb5ceSopenharmony_ci		if (!f)
518d4afb5ceSopenharmony_ci			return -1;
519d4afb5ceSopenharmony_ci		n++;
520d4afb5ceSopenharmony_ci	}
521d4afb5ceSopenharmony_ci
522d4afb5ceSopenharmony_ci	if (wsi->http.ah->frags[f].len >= len)
523d4afb5ceSopenharmony_ci		return -1;
524d4afb5ceSopenharmony_ci
525d4afb5ceSopenharmony_ci	memcpy(dst, wsi->http.ah->data + wsi->http.ah->frags[f].offset,
526d4afb5ceSopenharmony_ci	       wsi->http.ah->frags[f].len);
527d4afb5ceSopenharmony_ci	dst[wsi->http.ah->frags[f].len] = '\0';
528d4afb5ceSopenharmony_ci
529d4afb5ceSopenharmony_ci	return wsi->http.ah->frags[f].len;
530d4afb5ceSopenharmony_ci}
531d4afb5ceSopenharmony_ci
532d4afb5ceSopenharmony_ciint lws_hdr_copy(struct lws *wsi, char *dst, int len,
533d4afb5ceSopenharmony_ci			     enum lws_token_indexes h)
534d4afb5ceSopenharmony_ci{
535d4afb5ceSopenharmony_ci	int toklen = lws_hdr_total_length(wsi, h), n, comma;
536d4afb5ceSopenharmony_ci
537d4afb5ceSopenharmony_ci	*dst = '\0';
538d4afb5ceSopenharmony_ci	if (!toklen)
539d4afb5ceSopenharmony_ci		return 0;
540d4afb5ceSopenharmony_ci
541d4afb5ceSopenharmony_ci	if (toklen >= len)
542d4afb5ceSopenharmony_ci		return -1;
543d4afb5ceSopenharmony_ci
544d4afb5ceSopenharmony_ci	if (!wsi->http.ah)
545d4afb5ceSopenharmony_ci		return -1;
546d4afb5ceSopenharmony_ci
547d4afb5ceSopenharmony_ci	n = wsi->http.ah->frag_index[h];
548d4afb5ceSopenharmony_ci	if (!n)
549d4afb5ceSopenharmony_ci		return 0;
550d4afb5ceSopenharmony_ci	do {
551d4afb5ceSopenharmony_ci		comma = (wsi->http.ah->frags[n].nfrag) ? 1 : 0;
552d4afb5ceSopenharmony_ci
553d4afb5ceSopenharmony_ci		if (h == WSI_TOKEN_HTTP_URI_ARGS)
554d4afb5ceSopenharmony_ci			lwsl_notice("%s: WSI_TOKEN_HTTP_URI_ARGS '%.*s'\n",
555d4afb5ceSopenharmony_ci				    __func__, (int)wsi->http.ah->frags[n].len,
556d4afb5ceSopenharmony_ci				    &wsi->http.ah->data[
557d4afb5ceSopenharmony_ci				                wsi->http.ah->frags[n].offset]);
558d4afb5ceSopenharmony_ci
559d4afb5ceSopenharmony_ci		if (wsi->http.ah->frags[n].len + comma >= len) {
560d4afb5ceSopenharmony_ci			lwsl_notice("blowout len\n");
561d4afb5ceSopenharmony_ci			return -1;
562d4afb5ceSopenharmony_ci		}
563d4afb5ceSopenharmony_ci		strncpy(dst, &wsi->http.ah->data[wsi->http.ah->frags[n].offset],
564d4afb5ceSopenharmony_ci		        wsi->http.ah->frags[n].len);
565d4afb5ceSopenharmony_ci		dst += wsi->http.ah->frags[n].len;
566d4afb5ceSopenharmony_ci		len -= wsi->http.ah->frags[n].len;
567d4afb5ceSopenharmony_ci		n = wsi->http.ah->frags[n].nfrag;
568d4afb5ceSopenharmony_ci
569d4afb5ceSopenharmony_ci		/*
570d4afb5ceSopenharmony_ci		 * Note if you change this logic, take care about updating len
571d4afb5ceSopenharmony_ci		 * and make sure lws_hdr_total_length() gives the same resulting
572d4afb5ceSopenharmony_ci		 * length
573d4afb5ceSopenharmony_ci		 */
574d4afb5ceSopenharmony_ci
575d4afb5ceSopenharmony_ci		if (comma) {
576d4afb5ceSopenharmony_ci			if (h == WSI_TOKEN_HTTP_COOKIE ||
577d4afb5ceSopenharmony_ci			    h == WSI_TOKEN_HTTP_SET_COOKIE)
578d4afb5ceSopenharmony_ci				*dst++ = ';';
579d4afb5ceSopenharmony_ci			else
580d4afb5ceSopenharmony_ci				if (h == WSI_TOKEN_HTTP_URI_ARGS)
581d4afb5ceSopenharmony_ci					*dst++ = '&';
582d4afb5ceSopenharmony_ci				else
583d4afb5ceSopenharmony_ci					*dst++ = ',';
584d4afb5ceSopenharmony_ci			len--;
585d4afb5ceSopenharmony_ci		}
586d4afb5ceSopenharmony_ci
587d4afb5ceSopenharmony_ci	} while (n);
588d4afb5ceSopenharmony_ci	*dst = '\0';
589d4afb5ceSopenharmony_ci
590d4afb5ceSopenharmony_ci	if (h == WSI_TOKEN_HTTP_URI_ARGS)
591d4afb5ceSopenharmony_ci		lwsl_err("%s: WSI_TOKEN_HTTP_URI_ARGS toklen %d\n", __func__, (int)toklen);
592d4afb5ceSopenharmony_ci
593d4afb5ceSopenharmony_ci	return toklen;
594d4afb5ceSopenharmony_ci}
595d4afb5ceSopenharmony_ci
596d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CUSTOM_HEADERS)
597d4afb5ceSopenharmony_ciint
598d4afb5ceSopenharmony_cilws_hdr_custom_length(struct lws *wsi, const char *name, int nlen)
599d4afb5ceSopenharmony_ci{
600d4afb5ceSopenharmony_ci	ah_data_idx_t ll;
601d4afb5ceSopenharmony_ci
602d4afb5ceSopenharmony_ci	if (!wsi->http.ah || wsi->mux_substream)
603d4afb5ceSopenharmony_ci		return -1;
604d4afb5ceSopenharmony_ci
605d4afb5ceSopenharmony_ci	ll = wsi->http.ah->unk_ll_head;
606d4afb5ceSopenharmony_ci	while (ll) {
607d4afb5ceSopenharmony_ci		if (ll >= wsi->http.ah->data_length)
608d4afb5ceSopenharmony_ci			return -1;
609d4afb5ceSopenharmony_ci		if (nlen == lws_ser_ru16be(
610d4afb5ceSopenharmony_ci			(uint8_t *)&wsi->http.ah->data[ll + UHO_NLEN]) &&
611d4afb5ceSopenharmony_ci		    !strncmp(name, &wsi->http.ah->data[ll + UHO_NAME], (unsigned int)nlen))
612d4afb5ceSopenharmony_ci			return lws_ser_ru16be(
613d4afb5ceSopenharmony_ci				(uint8_t *)&wsi->http.ah->data[ll + UHO_VLEN]);
614d4afb5ceSopenharmony_ci
615d4afb5ceSopenharmony_ci		ll = lws_ser_ru32be((uint8_t *)&wsi->http.ah->data[ll + UHO_LL]);
616d4afb5ceSopenharmony_ci	}
617d4afb5ceSopenharmony_ci
618d4afb5ceSopenharmony_ci	return -1;
619d4afb5ceSopenharmony_ci}
620d4afb5ceSopenharmony_ci
621d4afb5ceSopenharmony_ciint
622d4afb5ceSopenharmony_cilws_hdr_custom_copy(struct lws *wsi, char *dst, int len, const char *name,
623d4afb5ceSopenharmony_ci		    int nlen)
624d4afb5ceSopenharmony_ci{
625d4afb5ceSopenharmony_ci	ah_data_idx_t ll;
626d4afb5ceSopenharmony_ci	int n;
627d4afb5ceSopenharmony_ci
628d4afb5ceSopenharmony_ci	if (!wsi->http.ah || wsi->mux_substream)
629d4afb5ceSopenharmony_ci		return -1;
630d4afb5ceSopenharmony_ci
631d4afb5ceSopenharmony_ci	*dst = '\0';
632d4afb5ceSopenharmony_ci
633d4afb5ceSopenharmony_ci	ll = wsi->http.ah->unk_ll_head;
634d4afb5ceSopenharmony_ci	while (ll) {
635d4afb5ceSopenharmony_ci		if (ll >= wsi->http.ah->data_length)
636d4afb5ceSopenharmony_ci			return -1;
637d4afb5ceSopenharmony_ci		if (nlen == lws_ser_ru16be(
638d4afb5ceSopenharmony_ci			(uint8_t *)&wsi->http.ah->data[ll + UHO_NLEN]) &&
639d4afb5ceSopenharmony_ci		    !strncmp(name, &wsi->http.ah->data[ll + UHO_NAME], (unsigned int)nlen)) {
640d4afb5ceSopenharmony_ci			n = lws_ser_ru16be(
641d4afb5ceSopenharmony_ci				(uint8_t *)&wsi->http.ah->data[ll + UHO_VLEN]);
642d4afb5ceSopenharmony_ci			if (n + 1 > len)
643d4afb5ceSopenharmony_ci				return -1;
644d4afb5ceSopenharmony_ci			strncpy(dst, &wsi->http.ah->data[ll + UHO_NAME + (unsigned int)nlen], (unsigned int)n);
645d4afb5ceSopenharmony_ci			dst[n] = '\0';
646d4afb5ceSopenharmony_ci
647d4afb5ceSopenharmony_ci			return n;
648d4afb5ceSopenharmony_ci		}
649d4afb5ceSopenharmony_ci		ll = lws_ser_ru32be((uint8_t *)&wsi->http.ah->data[ll + UHO_LL]);
650d4afb5ceSopenharmony_ci	}
651d4afb5ceSopenharmony_ci
652d4afb5ceSopenharmony_ci	return -1;
653d4afb5ceSopenharmony_ci}
654d4afb5ceSopenharmony_ci
655d4afb5ceSopenharmony_ciint
656d4afb5ceSopenharmony_cilws_hdr_custom_name_foreach(struct lws *wsi, lws_hdr_custom_fe_cb_t cb,
657d4afb5ceSopenharmony_ci			    void *custom)
658d4afb5ceSopenharmony_ci{
659d4afb5ceSopenharmony_ci	ah_data_idx_t ll;
660d4afb5ceSopenharmony_ci
661d4afb5ceSopenharmony_ci	if (!wsi->http.ah || wsi->mux_substream)
662d4afb5ceSopenharmony_ci		return -1;
663d4afb5ceSopenharmony_ci
664d4afb5ceSopenharmony_ci	ll = wsi->http.ah->unk_ll_head;
665d4afb5ceSopenharmony_ci
666d4afb5ceSopenharmony_ci	while (ll) {
667d4afb5ceSopenharmony_ci		if (ll >= wsi->http.ah->data_length)
668d4afb5ceSopenharmony_ci			return -1;
669d4afb5ceSopenharmony_ci
670d4afb5ceSopenharmony_ci		cb(&wsi->http.ah->data[ll + UHO_NAME],
671d4afb5ceSopenharmony_ci		   lws_ser_ru16be((uint8_t *)&wsi->http.ah->data[ll + UHO_NLEN]),
672d4afb5ceSopenharmony_ci		   custom);
673d4afb5ceSopenharmony_ci
674d4afb5ceSopenharmony_ci		ll = lws_ser_ru32be((uint8_t *)&wsi->http.ah->data[ll + UHO_LL]);
675d4afb5ceSopenharmony_ci	}
676d4afb5ceSopenharmony_ci
677d4afb5ceSopenharmony_ci	return 0;
678d4afb5ceSopenharmony_ci}
679d4afb5ceSopenharmony_ci#endif
680d4afb5ceSopenharmony_ci
681d4afb5ceSopenharmony_cichar *lws_hdr_simple_ptr(struct lws *wsi, enum lws_token_indexes h)
682d4afb5ceSopenharmony_ci{
683d4afb5ceSopenharmony_ci	int n;
684d4afb5ceSopenharmony_ci
685d4afb5ceSopenharmony_ci	if (!wsi->http.ah)
686d4afb5ceSopenharmony_ci		return NULL;
687d4afb5ceSopenharmony_ci
688d4afb5ceSopenharmony_ci	n = wsi->http.ah->frag_index[h];
689d4afb5ceSopenharmony_ci	if (!n)
690d4afb5ceSopenharmony_ci		return NULL;
691d4afb5ceSopenharmony_ci
692d4afb5ceSopenharmony_ci	return wsi->http.ah->data + wsi->http.ah->frags[n].offset;
693d4afb5ceSopenharmony_ci}
694d4afb5ceSopenharmony_ci
695d4afb5ceSopenharmony_cistatic int LWS_WARN_UNUSED_RESULT
696d4afb5ceSopenharmony_cilws_pos_in_bounds(struct lws *wsi)
697d4afb5ceSopenharmony_ci{
698d4afb5ceSopenharmony_ci	if (!wsi->http.ah)
699d4afb5ceSopenharmony_ci		return -1;
700d4afb5ceSopenharmony_ci
701d4afb5ceSopenharmony_ci	if (wsi->http.ah->pos <
702d4afb5ceSopenharmony_ci	    (unsigned int)wsi->a.context->max_http_header_data)
703d4afb5ceSopenharmony_ci		return 0;
704d4afb5ceSopenharmony_ci
705d4afb5ceSopenharmony_ci	if ((int)wsi->http.ah->pos >= (int)wsi->a.context->max_http_header_data - 1) {
706d4afb5ceSopenharmony_ci		lwsl_err("Ran out of header data space\n");
707d4afb5ceSopenharmony_ci		return 1;
708d4afb5ceSopenharmony_ci	}
709d4afb5ceSopenharmony_ci
710d4afb5ceSopenharmony_ci	/*
711d4afb5ceSopenharmony_ci	 * with these tests everywhere, it should never be able to exceed
712d4afb5ceSopenharmony_ci	 * the limit, only meet it
713d4afb5ceSopenharmony_ci	 */
714d4afb5ceSopenharmony_ci	lwsl_err("%s: pos %ld, limit %ld\n", __func__,
715d4afb5ceSopenharmony_ci		 (unsigned long)wsi->http.ah->pos,
716d4afb5ceSopenharmony_ci		 (unsigned long)wsi->a.context->max_http_header_data);
717d4afb5ceSopenharmony_ci	assert(0);
718d4afb5ceSopenharmony_ci
719d4afb5ceSopenharmony_ci	return 1;
720d4afb5ceSopenharmony_ci}
721d4afb5ceSopenharmony_ci
722d4afb5ceSopenharmony_ciint LWS_WARN_UNUSED_RESULT
723d4afb5ceSopenharmony_cilws_hdr_simple_create(struct lws *wsi, enum lws_token_indexes h, const char *s)
724d4afb5ceSopenharmony_ci{
725d4afb5ceSopenharmony_ci	if (!*s) {
726d4afb5ceSopenharmony_ci		/*
727d4afb5ceSopenharmony_ci		 * If we get an empty string, then remove any entry for the
728d4afb5ceSopenharmony_ci		 * header
729d4afb5ceSopenharmony_ci		 */
730d4afb5ceSopenharmony_ci		wsi->http.ah->frag_index[h] = 0;
731d4afb5ceSopenharmony_ci
732d4afb5ceSopenharmony_ci		return 0;
733d4afb5ceSopenharmony_ci	}
734d4afb5ceSopenharmony_ci
735d4afb5ceSopenharmony_ci	wsi->http.ah->nfrag++;
736d4afb5ceSopenharmony_ci	if (wsi->http.ah->nfrag == LWS_ARRAY_SIZE(wsi->http.ah->frags)) {
737d4afb5ceSopenharmony_ci		lwsl_warn("More hdr frags than we can deal with, dropping\n");
738d4afb5ceSopenharmony_ci		return -1;
739d4afb5ceSopenharmony_ci	}
740d4afb5ceSopenharmony_ci
741d4afb5ceSopenharmony_ci	wsi->http.ah->frag_index[h] = wsi->http.ah->nfrag;
742d4afb5ceSopenharmony_ci
743d4afb5ceSopenharmony_ci	wsi->http.ah->frags[wsi->http.ah->nfrag].offset = wsi->http.ah->pos;
744d4afb5ceSopenharmony_ci	wsi->http.ah->frags[wsi->http.ah->nfrag].len = 0;
745d4afb5ceSopenharmony_ci	wsi->http.ah->frags[wsi->http.ah->nfrag].nfrag = 0;
746d4afb5ceSopenharmony_ci
747d4afb5ceSopenharmony_ci	do {
748d4afb5ceSopenharmony_ci		if (lws_pos_in_bounds(wsi))
749d4afb5ceSopenharmony_ci			return -1;
750d4afb5ceSopenharmony_ci
751d4afb5ceSopenharmony_ci		wsi->http.ah->data[wsi->http.ah->pos++] = *s;
752d4afb5ceSopenharmony_ci		if (*s)
753d4afb5ceSopenharmony_ci			wsi->http.ah->frags[wsi->http.ah->nfrag].len++;
754d4afb5ceSopenharmony_ci	} while (*s++);
755d4afb5ceSopenharmony_ci
756d4afb5ceSopenharmony_ci	return 0;
757d4afb5ceSopenharmony_ci}
758d4afb5ceSopenharmony_ci
759d4afb5ceSopenharmony_cistatic int LWS_WARN_UNUSED_RESULT
760d4afb5ceSopenharmony_ciissue_char(struct lws *wsi, unsigned char c)
761d4afb5ceSopenharmony_ci{
762d4afb5ceSopenharmony_ci	unsigned short frag_len;
763d4afb5ceSopenharmony_ci
764d4afb5ceSopenharmony_ci	if (lws_pos_in_bounds(wsi))
765d4afb5ceSopenharmony_ci		return -1;
766d4afb5ceSopenharmony_ci
767d4afb5ceSopenharmony_ci	frag_len = wsi->http.ah->frags[wsi->http.ah->nfrag].len;
768d4afb5ceSopenharmony_ci	/*
769d4afb5ceSopenharmony_ci	 * If we haven't hit the token limit, just copy the character into
770d4afb5ceSopenharmony_ci	 * the header
771d4afb5ceSopenharmony_ci	 */
772d4afb5ceSopenharmony_ci	if (!wsi->http.ah->current_token_limit ||
773d4afb5ceSopenharmony_ci	    frag_len < wsi->http.ah->current_token_limit) {
774d4afb5ceSopenharmony_ci		wsi->http.ah->data[wsi->http.ah->pos++] = (char)c;
775d4afb5ceSopenharmony_ci		wsi->http.ah->frags[wsi->http.ah->nfrag].len++;
776d4afb5ceSopenharmony_ci		return 0;
777d4afb5ceSopenharmony_ci	}
778d4afb5ceSopenharmony_ci
779d4afb5ceSopenharmony_ci	/* Insert a null character when we *hit* the limit: */
780d4afb5ceSopenharmony_ci	if (frag_len == wsi->http.ah->current_token_limit) {
781d4afb5ceSopenharmony_ci		if (lws_pos_in_bounds(wsi))
782d4afb5ceSopenharmony_ci			return -1;
783d4afb5ceSopenharmony_ci
784d4afb5ceSopenharmony_ci		wsi->http.ah->data[wsi->http.ah->pos++] = '\0';
785d4afb5ceSopenharmony_ci		lwsl_warn("header %li exceeds limit %ld\n",
786d4afb5ceSopenharmony_ci			  (long)wsi->http.ah->parser_state,
787d4afb5ceSopenharmony_ci			  (long)wsi->http.ah->current_token_limit);
788d4afb5ceSopenharmony_ci	}
789d4afb5ceSopenharmony_ci
790d4afb5ceSopenharmony_ci	return 1;
791d4afb5ceSopenharmony_ci}
792d4afb5ceSopenharmony_ci
793d4afb5ceSopenharmony_ciint
794d4afb5ceSopenharmony_cilws_parse_urldecode(struct lws *wsi, uint8_t *_c)
795d4afb5ceSopenharmony_ci{
796d4afb5ceSopenharmony_ci	struct allocated_headers *ah = wsi->http.ah;
797d4afb5ceSopenharmony_ci	unsigned int enc = 0;
798d4afb5ceSopenharmony_ci	uint8_t c = *_c;
799d4afb5ceSopenharmony_ci
800d4afb5ceSopenharmony_ci	// lwsl_notice("ah->ups %d\n", ah->ups);
801d4afb5ceSopenharmony_ci
802d4afb5ceSopenharmony_ci	/*
803d4afb5ceSopenharmony_ci	 * PRIORITY 1
804d4afb5ceSopenharmony_ci	 * special URI processing... convert %xx
805d4afb5ceSopenharmony_ci	 */
806d4afb5ceSopenharmony_ci	switch (ah->ues) {
807d4afb5ceSopenharmony_ci	case URIES_IDLE:
808d4afb5ceSopenharmony_ci		if (c == '%') {
809d4afb5ceSopenharmony_ci			ah->ues = URIES_SEEN_PERCENT;
810d4afb5ceSopenharmony_ci			goto swallow;
811d4afb5ceSopenharmony_ci		}
812d4afb5ceSopenharmony_ci		break;
813d4afb5ceSopenharmony_ci	case URIES_SEEN_PERCENT:
814d4afb5ceSopenharmony_ci		if (char_to_hex((char)c) < 0)
815d4afb5ceSopenharmony_ci			/* illegal post-% char */
816d4afb5ceSopenharmony_ci			goto forbid;
817d4afb5ceSopenharmony_ci
818d4afb5ceSopenharmony_ci		ah->esc_stash = (char)c;
819d4afb5ceSopenharmony_ci		ah->ues = URIES_SEEN_PERCENT_H1;
820d4afb5ceSopenharmony_ci		goto swallow;
821d4afb5ceSopenharmony_ci
822d4afb5ceSopenharmony_ci	case URIES_SEEN_PERCENT_H1:
823d4afb5ceSopenharmony_ci		if (char_to_hex((char)c) < 0)
824d4afb5ceSopenharmony_ci			/* illegal post-% char */
825d4afb5ceSopenharmony_ci			goto forbid;
826d4afb5ceSopenharmony_ci
827d4afb5ceSopenharmony_ci		*_c = (uint8_t)(unsigned int)((char_to_hex(ah->esc_stash) << 4) |
828d4afb5ceSopenharmony_ci				char_to_hex((char)c));
829d4afb5ceSopenharmony_ci		c = *_c;
830d4afb5ceSopenharmony_ci		enc = 1;
831d4afb5ceSopenharmony_ci		ah->ues = URIES_IDLE;
832d4afb5ceSopenharmony_ci		break;
833d4afb5ceSopenharmony_ci	}
834d4afb5ceSopenharmony_ci
835d4afb5ceSopenharmony_ci	/*
836d4afb5ceSopenharmony_ci	 * PRIORITY 2
837d4afb5ceSopenharmony_ci	 * special URI processing...
838d4afb5ceSopenharmony_ci	 *  convert /.. or /... or /../ etc to /
839d4afb5ceSopenharmony_ci	 *  convert /./ to /
840d4afb5ceSopenharmony_ci	 *  convert // or /// etc to /
841d4afb5ceSopenharmony_ci	 *  leave /.dir or whatever alone
842d4afb5ceSopenharmony_ci	 */
843d4afb5ceSopenharmony_ci
844d4afb5ceSopenharmony_ci	if (!c && (!ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] ||
845d4afb5ceSopenharmony_ci		   !ah->post_literal_equal)) {
846d4afb5ceSopenharmony_ci		/*
847d4afb5ceSopenharmony_ci		 * Since user code is typically going to parse the path using
848d4afb5ceSopenharmony_ci		 * NUL-terminated apis, it's too dangerous to allow NUL
849d4afb5ceSopenharmony_ci		 * injection here.
850d4afb5ceSopenharmony_ci		 *
851d4afb5ceSopenharmony_ci		 * It's allowed in the urlargs, because the apis to access
852d4afb5ceSopenharmony_ci		 * those only allow retreival with explicit length.
853d4afb5ceSopenharmony_ci		 */
854d4afb5ceSopenharmony_ci		lwsl_warn("%s: saw NUL outside of uri args\n", __func__);
855d4afb5ceSopenharmony_ci		return -1;
856d4afb5ceSopenharmony_ci	}
857d4afb5ceSopenharmony_ci
858d4afb5ceSopenharmony_ci	switch (ah->ups) {
859d4afb5ceSopenharmony_ci	case URIPS_IDLE:
860d4afb5ceSopenharmony_ci
861d4afb5ceSopenharmony_ci		/* genuine delimiter */
862d4afb5ceSopenharmony_ci		if ((c == '&' || c == ';') && !enc) {
863d4afb5ceSopenharmony_ci			if (issue_char(wsi, '\0') < 0)
864d4afb5ceSopenharmony_ci				return -1;
865d4afb5ceSopenharmony_ci			/* don't account for it */
866d4afb5ceSopenharmony_ci			wsi->http.ah->frags[wsi->http.ah->nfrag].len--;
867d4afb5ceSopenharmony_ci			/* link to next fragment */
868d4afb5ceSopenharmony_ci			ah->frags[ah->nfrag].nfrag = (uint8_t)(ah->nfrag + 1);
869d4afb5ceSopenharmony_ci			ah->nfrag++;
870d4afb5ceSopenharmony_ci			if (ah->nfrag >= LWS_ARRAY_SIZE(ah->frags))
871d4afb5ceSopenharmony_ci				goto excessive;
872d4afb5ceSopenharmony_ci			/* start next fragment after the & */
873d4afb5ceSopenharmony_ci			ah->post_literal_equal = 0;
874d4afb5ceSopenharmony_ci			ah->frags[ah->nfrag].offset = ++ah->pos;
875d4afb5ceSopenharmony_ci			ah->frags[ah->nfrag].len = 0;
876d4afb5ceSopenharmony_ci			ah->frags[ah->nfrag].nfrag = 0;
877d4afb5ceSopenharmony_ci			goto swallow;
878d4afb5ceSopenharmony_ci		}
879d4afb5ceSopenharmony_ci		/* uriencoded = in the name part, disallow */
880d4afb5ceSopenharmony_ci		if (c == '=' && enc &&
881d4afb5ceSopenharmony_ci		    ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] &&
882d4afb5ceSopenharmony_ci		    !ah->post_literal_equal) {
883d4afb5ceSopenharmony_ci			c = '_';
884d4afb5ceSopenharmony_ci			*_c =c;
885d4afb5ceSopenharmony_ci		}
886d4afb5ceSopenharmony_ci
887d4afb5ceSopenharmony_ci		/* after the real =, we don't care how many = */
888d4afb5ceSopenharmony_ci		if (c == '=' && !enc)
889d4afb5ceSopenharmony_ci			ah->post_literal_equal = 1;
890d4afb5ceSopenharmony_ci
891d4afb5ceSopenharmony_ci		/* + to space */
892d4afb5ceSopenharmony_ci		if (c == '+' && !enc) {
893d4afb5ceSopenharmony_ci			c = ' ';
894d4afb5ceSopenharmony_ci			*_c = c;
895d4afb5ceSopenharmony_ci		}
896d4afb5ceSopenharmony_ci		/* issue the first / always */
897d4afb5ceSopenharmony_ci		if (c == '/' && !ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS])
898d4afb5ceSopenharmony_ci			ah->ups = URIPS_SEEN_SLASH;
899d4afb5ceSopenharmony_ci		break;
900d4afb5ceSopenharmony_ci	case URIPS_SEEN_SLASH:
901d4afb5ceSopenharmony_ci		/* swallow subsequent slashes */
902d4afb5ceSopenharmony_ci		if (c == '/')
903d4afb5ceSopenharmony_ci			goto swallow;
904d4afb5ceSopenharmony_ci		/* track and swallow the first . after / */
905d4afb5ceSopenharmony_ci		if (c == '.') {
906d4afb5ceSopenharmony_ci			ah->ups = URIPS_SEEN_SLASH_DOT;
907d4afb5ceSopenharmony_ci			goto swallow;
908d4afb5ceSopenharmony_ci		}
909d4afb5ceSopenharmony_ci		ah->ups = URIPS_IDLE;
910d4afb5ceSopenharmony_ci		break;
911d4afb5ceSopenharmony_ci	case URIPS_SEEN_SLASH_DOT:
912d4afb5ceSopenharmony_ci		/* swallow second . */
913d4afb5ceSopenharmony_ci		if (c == '.') {
914d4afb5ceSopenharmony_ci			ah->ups = URIPS_SEEN_SLASH_DOT_DOT;
915d4afb5ceSopenharmony_ci			goto swallow;
916d4afb5ceSopenharmony_ci		}
917d4afb5ceSopenharmony_ci		/* change /./ to / */
918d4afb5ceSopenharmony_ci		if (c == '/') {
919d4afb5ceSopenharmony_ci			ah->ups = URIPS_SEEN_SLASH;
920d4afb5ceSopenharmony_ci			goto swallow;
921d4afb5ceSopenharmony_ci		}
922d4afb5ceSopenharmony_ci		/* it was like /.dir ... regurgitate the . */
923d4afb5ceSopenharmony_ci		ah->ups = URIPS_IDLE;
924d4afb5ceSopenharmony_ci		if (issue_char(wsi, '.') < 0)
925d4afb5ceSopenharmony_ci			return -1;
926d4afb5ceSopenharmony_ci		break;
927d4afb5ceSopenharmony_ci
928d4afb5ceSopenharmony_ci	case URIPS_SEEN_SLASH_DOT_DOT:
929d4afb5ceSopenharmony_ci
930d4afb5ceSopenharmony_ci		/* /../ or /..[End of URI] --> backup to last / */
931d4afb5ceSopenharmony_ci		if (c == '/' || c == '?') {
932d4afb5ceSopenharmony_ci			/*
933d4afb5ceSopenharmony_ci			 * back up one dir level if possible
934d4afb5ceSopenharmony_ci			 * safe against header fragmentation because
935d4afb5ceSopenharmony_ci			 * the method URI can only be in 1 fragment
936d4afb5ceSopenharmony_ci			 */
937d4afb5ceSopenharmony_ci			if (ah->frags[ah->nfrag].len > 2) {
938d4afb5ceSopenharmony_ci				ah->pos--;
939d4afb5ceSopenharmony_ci				ah->frags[ah->nfrag].len--;
940d4afb5ceSopenharmony_ci				do {
941d4afb5ceSopenharmony_ci					ah->pos--;
942d4afb5ceSopenharmony_ci					ah->frags[ah->nfrag].len--;
943d4afb5ceSopenharmony_ci				} while (ah->frags[ah->nfrag].len > 1 &&
944d4afb5ceSopenharmony_ci					 ah->data[ah->pos] != '/');
945d4afb5ceSopenharmony_ci			}
946d4afb5ceSopenharmony_ci			ah->ups = URIPS_SEEN_SLASH;
947d4afb5ceSopenharmony_ci			if (ah->frags[ah->nfrag].len > 1)
948d4afb5ceSopenharmony_ci				break;
949d4afb5ceSopenharmony_ci			goto swallow;
950d4afb5ceSopenharmony_ci		}
951d4afb5ceSopenharmony_ci
952d4afb5ceSopenharmony_ci		/*  /..[^/] ... regurgitate and allow */
953d4afb5ceSopenharmony_ci
954d4afb5ceSopenharmony_ci		if (issue_char(wsi, '.') < 0)
955d4afb5ceSopenharmony_ci			return -1;
956d4afb5ceSopenharmony_ci		if (issue_char(wsi, '.') < 0)
957d4afb5ceSopenharmony_ci			return -1;
958d4afb5ceSopenharmony_ci		ah->ups = URIPS_IDLE;
959d4afb5ceSopenharmony_ci		break;
960d4afb5ceSopenharmony_ci	}
961d4afb5ceSopenharmony_ci
962d4afb5ceSopenharmony_ci	if (c == '?' && !enc &&
963d4afb5ceSopenharmony_ci	    !ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS]) { /* start of URI args */
964d4afb5ceSopenharmony_ci		if (ah->ues != URIES_IDLE)
965d4afb5ceSopenharmony_ci			goto forbid;
966d4afb5ceSopenharmony_ci
967d4afb5ceSopenharmony_ci		/* seal off uri header */
968d4afb5ceSopenharmony_ci		if (issue_char(wsi, '\0') < 0)
969d4afb5ceSopenharmony_ci			return -1;
970d4afb5ceSopenharmony_ci
971d4afb5ceSopenharmony_ci		/* don't account for it */
972d4afb5ceSopenharmony_ci		wsi->http.ah->frags[wsi->http.ah->nfrag].len--;
973d4afb5ceSopenharmony_ci
974d4afb5ceSopenharmony_ci		/* move to using WSI_TOKEN_HTTP_URI_ARGS */
975d4afb5ceSopenharmony_ci		ah->nfrag++;
976d4afb5ceSopenharmony_ci		if (ah->nfrag >= LWS_ARRAY_SIZE(ah->frags))
977d4afb5ceSopenharmony_ci			goto excessive;
978d4afb5ceSopenharmony_ci		ah->frags[ah->nfrag].offset = ++ah->pos;
979d4afb5ceSopenharmony_ci		ah->frags[ah->nfrag].len = 0;
980d4afb5ceSopenharmony_ci		ah->frags[ah->nfrag].nfrag = 0;
981d4afb5ceSopenharmony_ci
982d4afb5ceSopenharmony_ci		ah->post_literal_equal = 0;
983d4afb5ceSopenharmony_ci		ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] = ah->nfrag;
984d4afb5ceSopenharmony_ci		ah->ups = URIPS_IDLE;
985d4afb5ceSopenharmony_ci		goto swallow;
986d4afb5ceSopenharmony_ci	}
987d4afb5ceSopenharmony_ci
988d4afb5ceSopenharmony_ci	return LPUR_CONTINUE;
989d4afb5ceSopenharmony_ci
990d4afb5ceSopenharmony_ciswallow:
991d4afb5ceSopenharmony_ci	return LPUR_SWALLOW;
992d4afb5ceSopenharmony_ci
993d4afb5ceSopenharmony_ciforbid:
994d4afb5ceSopenharmony_ci	return LPUR_FORBID;
995d4afb5ceSopenharmony_ci
996d4afb5ceSopenharmony_ciexcessive:
997d4afb5ceSopenharmony_ci	return LPUR_EXCESSIVE;
998d4afb5ceSopenharmony_ci}
999d4afb5ceSopenharmony_ci
1000d4afb5ceSopenharmony_cistatic const unsigned char methods[] = {
1001d4afb5ceSopenharmony_ci	WSI_TOKEN_GET_URI,
1002d4afb5ceSopenharmony_ci	WSI_TOKEN_POST_URI,
1003d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
1004d4afb5ceSopenharmony_ci	WSI_TOKEN_OPTIONS_URI,
1005d4afb5ceSopenharmony_ci	WSI_TOKEN_PUT_URI,
1006d4afb5ceSopenharmony_ci	WSI_TOKEN_PATCH_URI,
1007d4afb5ceSopenharmony_ci	WSI_TOKEN_DELETE_URI,
1008d4afb5ceSopenharmony_ci#endif
1009d4afb5ceSopenharmony_ci	WSI_TOKEN_CONNECT,
1010d4afb5ceSopenharmony_ci	WSI_TOKEN_HEAD_URI,
1011d4afb5ceSopenharmony_ci};
1012d4afb5ceSopenharmony_ci
1013d4afb5ceSopenharmony_ci/*
1014d4afb5ceSopenharmony_ci * possible returns:, -1 fail, 0 ok or 2, transition to raw
1015d4afb5ceSopenharmony_ci */
1016d4afb5ceSopenharmony_ci
1017d4afb5ceSopenharmony_cilws_parser_return_t LWS_WARN_UNUSED_RESULT
1018d4afb5ceSopenharmony_cilws_parse(struct lws *wsi, unsigned char *buf, int *len)
1019d4afb5ceSopenharmony_ci{
1020d4afb5ceSopenharmony_ci	struct allocated_headers *ah = wsi->http.ah;
1021d4afb5ceSopenharmony_ci	struct lws_context *context = wsi->a.context;
1022d4afb5ceSopenharmony_ci	unsigned int n, m;
1023d4afb5ceSopenharmony_ci	unsigned char c;
1024d4afb5ceSopenharmony_ci	int r, pos;
1025d4afb5ceSopenharmony_ci
1026d4afb5ceSopenharmony_ci	assert(wsi->http.ah);
1027d4afb5ceSopenharmony_ci
1028d4afb5ceSopenharmony_ci	do {
1029d4afb5ceSopenharmony_ci		(*len)--;
1030d4afb5ceSopenharmony_ci		c = *buf++;
1031d4afb5ceSopenharmony_ci
1032d4afb5ceSopenharmony_ci		switch (ah->parser_state) {
1033d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CUSTOM_HEADERS)
1034d4afb5ceSopenharmony_ci		case WSI_TOKEN_UNKNOWN_VALUE_PART:
1035d4afb5ceSopenharmony_ci
1036d4afb5ceSopenharmony_ci			if (c == '\r')
1037d4afb5ceSopenharmony_ci				break;
1038d4afb5ceSopenharmony_ci			if (c == '\n') {
1039d4afb5ceSopenharmony_ci				lws_ser_wu16be((uint8_t *)&ah->data[ah->unk_pos + 2],
1040d4afb5ceSopenharmony_ci					       (uint16_t)(ah->pos - ah->unk_value_pos));
1041d4afb5ceSopenharmony_ci				ah->parser_state = WSI_TOKEN_NAME_PART;
1042d4afb5ceSopenharmony_ci				ah->unk_pos = 0;
1043d4afb5ceSopenharmony_ci				ah->lextable_pos = 0;
1044d4afb5ceSopenharmony_ci				break;
1045d4afb5ceSopenharmony_ci			}
1046d4afb5ceSopenharmony_ci
1047d4afb5ceSopenharmony_ci			/* trim leading whitespace */
1048d4afb5ceSopenharmony_ci			if (ah->pos != ah->unk_value_pos ||
1049d4afb5ceSopenharmony_ci			    (c != ' ' && c != '\t')) {
1050d4afb5ceSopenharmony_ci
1051d4afb5ceSopenharmony_ci				if (lws_pos_in_bounds(wsi))
1052d4afb5ceSopenharmony_ci					return LPR_FAIL;
1053d4afb5ceSopenharmony_ci
1054d4afb5ceSopenharmony_ci				ah->data[ah->pos++] = (char)c;
1055d4afb5ceSopenharmony_ci			}
1056d4afb5ceSopenharmony_ci			pos = ah->lextable_pos;
1057d4afb5ceSopenharmony_ci			break;
1058d4afb5ceSopenharmony_ci#endif
1059d4afb5ceSopenharmony_ci		default:
1060d4afb5ceSopenharmony_ci
1061d4afb5ceSopenharmony_ci			lwsl_parser("WSI_TOK_(%d) '%c'\n", ah->parser_state, c);
1062d4afb5ceSopenharmony_ci
1063d4afb5ceSopenharmony_ci			/* collect into malloc'd buffers */
1064d4afb5ceSopenharmony_ci			/* optional initial space swallow */
1065d4afb5ceSopenharmony_ci			if (!ah->frags[ah->frag_index[ah->parser_state]].len &&
1066d4afb5ceSopenharmony_ci			    c == ' ')
1067d4afb5ceSopenharmony_ci				break;
1068d4afb5ceSopenharmony_ci
1069d4afb5ceSopenharmony_ci			for (m = 0; m < LWS_ARRAY_SIZE(methods); m++)
1070d4afb5ceSopenharmony_ci				if (ah->parser_state == methods[m])
1071d4afb5ceSopenharmony_ci					break;
1072d4afb5ceSopenharmony_ci			if (m == LWS_ARRAY_SIZE(methods))
1073d4afb5ceSopenharmony_ci				/* it was not any of the methods */
1074d4afb5ceSopenharmony_ci				goto check_eol;
1075d4afb5ceSopenharmony_ci
1076d4afb5ceSopenharmony_ci			/* special URI processing... end at space */
1077d4afb5ceSopenharmony_ci
1078d4afb5ceSopenharmony_ci			if (c == ' ') {
1079d4afb5ceSopenharmony_ci				/* enforce starting with / */
1080d4afb5ceSopenharmony_ci				if (!ah->frags[ah->nfrag].len)
1081d4afb5ceSopenharmony_ci					if (issue_char(wsi, '/') < 0)
1082d4afb5ceSopenharmony_ci						return LPR_FAIL;
1083d4afb5ceSopenharmony_ci
1084d4afb5ceSopenharmony_ci				if (ah->ups == URIPS_SEEN_SLASH_DOT_DOT) {
1085d4afb5ceSopenharmony_ci					/*
1086d4afb5ceSopenharmony_ci					 * back up one dir level if possible
1087d4afb5ceSopenharmony_ci					 * safe against header fragmentation
1088d4afb5ceSopenharmony_ci					 * because the method URI can only be
1089d4afb5ceSopenharmony_ci					 * in 1 fragment
1090d4afb5ceSopenharmony_ci					 */
1091d4afb5ceSopenharmony_ci					if (ah->frags[ah->nfrag].len > 2) {
1092d4afb5ceSopenharmony_ci						ah->pos--;
1093d4afb5ceSopenharmony_ci						ah->frags[ah->nfrag].len--;
1094d4afb5ceSopenharmony_ci						do {
1095d4afb5ceSopenharmony_ci							ah->pos--;
1096d4afb5ceSopenharmony_ci							ah->frags[ah->nfrag].len--;
1097d4afb5ceSopenharmony_ci						} while (ah->frags[ah->nfrag].len > 1 &&
1098d4afb5ceSopenharmony_ci							 ah->data[ah->pos] != '/');
1099d4afb5ceSopenharmony_ci					}
1100d4afb5ceSopenharmony_ci				}
1101d4afb5ceSopenharmony_ci
1102d4afb5ceSopenharmony_ci				/* begin parsing HTTP version: */
1103d4afb5ceSopenharmony_ci				if (issue_char(wsi, '\0') < 0)
1104d4afb5ceSopenharmony_ci					return LPR_FAIL;
1105d4afb5ceSopenharmony_ci				/* don't account for it */
1106d4afb5ceSopenharmony_ci				wsi->http.ah->frags[wsi->http.ah->nfrag].len--;
1107d4afb5ceSopenharmony_ci				ah->parser_state = WSI_TOKEN_HTTP;
1108d4afb5ceSopenharmony_ci				goto start_fragment;
1109d4afb5ceSopenharmony_ci			}
1110d4afb5ceSopenharmony_ci
1111d4afb5ceSopenharmony_ci			r = lws_parse_urldecode(wsi, &c);
1112d4afb5ceSopenharmony_ci			switch (r) {
1113d4afb5ceSopenharmony_ci			case LPUR_CONTINUE:
1114d4afb5ceSopenharmony_ci				break;
1115d4afb5ceSopenharmony_ci			case LPUR_SWALLOW:
1116d4afb5ceSopenharmony_ci				goto swallow;
1117d4afb5ceSopenharmony_ci			case LPUR_FORBID:
1118d4afb5ceSopenharmony_ci				goto forbid;
1119d4afb5ceSopenharmony_ci			case LPUR_EXCESSIVE:
1120d4afb5ceSopenharmony_ci				goto excessive;
1121d4afb5ceSopenharmony_ci			default:
1122d4afb5ceSopenharmony_ci				return LPR_FAIL;
1123d4afb5ceSopenharmony_ci			}
1124d4afb5ceSopenharmony_cicheck_eol:
1125d4afb5ceSopenharmony_ci			/* bail at EOL */
1126d4afb5ceSopenharmony_ci			if (ah->parser_state != WSI_TOKEN_CHALLENGE &&
1127d4afb5ceSopenharmony_ci			    (c == '\x0d' || c == '\x0a')) {
1128d4afb5ceSopenharmony_ci				if (ah->ues != URIES_IDLE)
1129d4afb5ceSopenharmony_ci					goto forbid;
1130d4afb5ceSopenharmony_ci
1131d4afb5ceSopenharmony_ci				if (c == '\x0a') {
1132d4afb5ceSopenharmony_ci					/* broken peer */
1133d4afb5ceSopenharmony_ci					ah->parser_state = WSI_TOKEN_NAME_PART;
1134d4afb5ceSopenharmony_ci					ah->unk_pos = 0;
1135d4afb5ceSopenharmony_ci					ah->lextable_pos = 0;
1136d4afb5ceSopenharmony_ci				} else
1137d4afb5ceSopenharmony_ci					ah->parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
1138d4afb5ceSopenharmony_ci
1139d4afb5ceSopenharmony_ci				c = '\0';
1140d4afb5ceSopenharmony_ci				lwsl_parser("*\n");
1141d4afb5ceSopenharmony_ci			}
1142d4afb5ceSopenharmony_ci
1143d4afb5ceSopenharmony_ci			n = (unsigned int)issue_char(wsi, c);
1144d4afb5ceSopenharmony_ci			if ((int)n < 0)
1145d4afb5ceSopenharmony_ci				return LPR_FAIL;
1146d4afb5ceSopenharmony_ci			if (n > 0)
1147d4afb5ceSopenharmony_ci				ah->parser_state = WSI_TOKEN_SKIPPING;
1148d4afb5ceSopenharmony_ci			else {
1149d4afb5ceSopenharmony_ci				/*
1150d4afb5ceSopenharmony_ci				 * Explicit zeroes are legal in URI ARGS.
1151d4afb5ceSopenharmony_ci				 * They can only exist as a safety terminator
1152d4afb5ceSopenharmony_ci				 * after the valid part of the token contents
1153d4afb5ceSopenharmony_ci				 * for other types.
1154d4afb5ceSopenharmony_ci				 */
1155d4afb5ceSopenharmony_ci				if (!c && ah->parser_state != WSI_TOKEN_HTTP_URI_ARGS)
1156d4afb5ceSopenharmony_ci					/* don't account for safety terminator */
1157d4afb5ceSopenharmony_ci					wsi->http.ah->frags[wsi->http.ah->nfrag].len--;
1158d4afb5ceSopenharmony_ci			}
1159d4afb5ceSopenharmony_ci
1160d4afb5ceSopenharmony_ciswallow:
1161d4afb5ceSopenharmony_ci			/* per-protocol end of headers management */
1162d4afb5ceSopenharmony_ci
1163d4afb5ceSopenharmony_ci			if (ah->parser_state == WSI_TOKEN_CHALLENGE)
1164d4afb5ceSopenharmony_ci				goto set_parsing_complete;
1165d4afb5ceSopenharmony_ci			break;
1166d4afb5ceSopenharmony_ci
1167d4afb5ceSopenharmony_ci			/* collecting and checking a name part */
1168d4afb5ceSopenharmony_ci		case WSI_TOKEN_NAME_PART:
1169d4afb5ceSopenharmony_ci			lwsl_parser("WSI_TOKEN_NAME_PART '%c' 0x%02X "
1170d4afb5ceSopenharmony_ci				    "(role=0x%lx) "
1171d4afb5ceSopenharmony_ci				    "wsi->lextable_pos=%d\n", c, c,
1172d4afb5ceSopenharmony_ci				    (unsigned long)lwsi_role(wsi),
1173d4afb5ceSopenharmony_ci				    ah->lextable_pos);
1174d4afb5ceSopenharmony_ci
1175d4afb5ceSopenharmony_ci			if (!ah->unk_pos && c == '\x0a')
1176d4afb5ceSopenharmony_ci				/* broken peer */
1177d4afb5ceSopenharmony_ci				goto set_parsing_complete;
1178d4afb5ceSopenharmony_ci
1179d4afb5ceSopenharmony_ci			if (c >= 'A' && c <= 'Z')
1180d4afb5ceSopenharmony_ci				c = (unsigned char)(c + 'a' - 'A');
1181d4afb5ceSopenharmony_ci			/*
1182d4afb5ceSopenharmony_ci			 * ...in case it's an unknown header, speculatively
1183d4afb5ceSopenharmony_ci			 * store it as the name comes in.  If we recognize it as
1184d4afb5ceSopenharmony_ci			 * a known header, we'll snip this.
1185d4afb5ceSopenharmony_ci			 */
1186d4afb5ceSopenharmony_ci
1187d4afb5ceSopenharmony_ci			if (!wsi->mux_substream && !ah->unk_pos) {
1188d4afb5ceSopenharmony_ci				ah->unk_pos = ah->pos;
1189d4afb5ceSopenharmony_ci
1190d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CUSTOM_HEADERS)
1191d4afb5ceSopenharmony_ci				/*
1192d4afb5ceSopenharmony_ci				 * Prepare new unknown header linked-list entry
1193d4afb5ceSopenharmony_ci				 *
1194d4afb5ceSopenharmony_ci				 *  - 16-bit BE: name part length
1195d4afb5ceSopenharmony_ci				 *  - 16-bit BE: value part length
1196d4afb5ceSopenharmony_ci				 *  - 32-bit BE: data offset of next, or 0
1197d4afb5ceSopenharmony_ci				 */
1198d4afb5ceSopenharmony_ci				for (n = 0; n < 8; n++)
1199d4afb5ceSopenharmony_ci					if (!lws_pos_in_bounds(wsi))
1200d4afb5ceSopenharmony_ci						ah->data[ah->pos++] = 0;
1201d4afb5ceSopenharmony_ci#endif
1202d4afb5ceSopenharmony_ci			}
1203d4afb5ceSopenharmony_ci
1204d4afb5ceSopenharmony_ci			if (lws_pos_in_bounds(wsi))
1205d4afb5ceSopenharmony_ci				return LPR_FAIL;
1206d4afb5ceSopenharmony_ci
1207d4afb5ceSopenharmony_ci			ah->data[ah->pos++] = (char)c;
1208d4afb5ceSopenharmony_ci			pos = ah->lextable_pos;
1209d4afb5ceSopenharmony_ci
1210d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CUSTOM_HEADERS)
1211d4afb5ceSopenharmony_ci			if (!wsi->mux_substream && pos < 0 && c == ':') {
1212d4afb5ceSopenharmony_ci#if defined(_DEBUG)
1213d4afb5ceSopenharmony_ci				char dotstar[64];
1214d4afb5ceSopenharmony_ci				int uhlen;
1215d4afb5ceSopenharmony_ci#endif
1216d4afb5ceSopenharmony_ci
1217d4afb5ceSopenharmony_ci				/*
1218d4afb5ceSopenharmony_ci				 * process unknown headers
1219d4afb5ceSopenharmony_ci				 *
1220d4afb5ceSopenharmony_ci				 * register us in the unknown hdr ll
1221d4afb5ceSopenharmony_ci				 */
1222d4afb5ceSopenharmony_ci
1223d4afb5ceSopenharmony_ci				if (!ah->unk_ll_head)
1224d4afb5ceSopenharmony_ci					ah->unk_ll_head = ah->unk_pos;
1225d4afb5ceSopenharmony_ci
1226d4afb5ceSopenharmony_ci				if (ah->unk_ll_tail)
1227d4afb5ceSopenharmony_ci					lws_ser_wu32be(
1228d4afb5ceSopenharmony_ci				(uint8_t *)&ah->data[ah->unk_ll_tail + UHO_LL],
1229d4afb5ceSopenharmony_ci						       ah->unk_pos);
1230d4afb5ceSopenharmony_ci
1231d4afb5ceSopenharmony_ci				ah->unk_ll_tail = ah->unk_pos;
1232d4afb5ceSopenharmony_ci
1233d4afb5ceSopenharmony_ci#if defined(_DEBUG)
1234d4afb5ceSopenharmony_ci				uhlen = (int)(ah->pos - (ah->unk_pos + UHO_NAME));
1235d4afb5ceSopenharmony_ci				lws_strnncpy(dotstar,
1236d4afb5ceSopenharmony_ci					&ah->data[ah->unk_pos + UHO_NAME],
1237d4afb5ceSopenharmony_ci					uhlen, sizeof(dotstar));
1238d4afb5ceSopenharmony_ci				lwsl_debug("%s: unk header %d '%s'\n",
1239d4afb5ceSopenharmony_ci					    __func__,
1240d4afb5ceSopenharmony_ci					    ah->pos - (ah->unk_pos + UHO_NAME),
1241d4afb5ceSopenharmony_ci					    dotstar);
1242d4afb5ceSopenharmony_ci#endif
1243d4afb5ceSopenharmony_ci
1244d4afb5ceSopenharmony_ci				/* set the unknown header name part length */
1245d4afb5ceSopenharmony_ci
1246d4afb5ceSopenharmony_ci				lws_ser_wu16be((uint8_t *)&ah->data[ah->unk_pos],
1247d4afb5ceSopenharmony_ci					       (uint16_t)((ah->pos - ah->unk_pos) - UHO_NAME));
1248d4afb5ceSopenharmony_ci
1249d4afb5ceSopenharmony_ci				ah->unk_value_pos = ah->pos;
1250d4afb5ceSopenharmony_ci
1251d4afb5ceSopenharmony_ci				/*
1252d4afb5ceSopenharmony_ci				 * collect whatever's coming for the unknown header
1253d4afb5ceSopenharmony_ci				 * argument until the next CRLF
1254d4afb5ceSopenharmony_ci				 */
1255d4afb5ceSopenharmony_ci				ah->parser_state = WSI_TOKEN_UNKNOWN_VALUE_PART;
1256d4afb5ceSopenharmony_ci				break;
1257d4afb5ceSopenharmony_ci			}
1258d4afb5ceSopenharmony_ci#endif
1259d4afb5ceSopenharmony_ci			if (pos < 0)
1260d4afb5ceSopenharmony_ci				break;
1261d4afb5ceSopenharmony_ci
1262d4afb5ceSopenharmony_ci			while (1) {
1263d4afb5ceSopenharmony_ci				if (lextable_h1[pos] & (1 << 7)) {
1264d4afb5ceSopenharmony_ci					/* 1-byte, fail on mismatch */
1265d4afb5ceSopenharmony_ci					if ((lextable_h1[pos] & 0x7f) != c) {
1266d4afb5ceSopenharmony_cinope:
1267d4afb5ceSopenharmony_ci						ah->lextable_pos = -1;
1268d4afb5ceSopenharmony_ci						break;
1269d4afb5ceSopenharmony_ci					}
1270d4afb5ceSopenharmony_ci					/* fall thru */
1271d4afb5ceSopenharmony_ci					pos++;
1272d4afb5ceSopenharmony_ci					if (lextable_h1[pos] == FAIL_CHAR)
1273d4afb5ceSopenharmony_ci						goto nope;
1274d4afb5ceSopenharmony_ci
1275d4afb5ceSopenharmony_ci					ah->lextable_pos = (int16_t)pos;
1276d4afb5ceSopenharmony_ci					break;
1277d4afb5ceSopenharmony_ci				}
1278d4afb5ceSopenharmony_ci
1279d4afb5ceSopenharmony_ci				if (lextable_h1[pos] == FAIL_CHAR)
1280d4afb5ceSopenharmony_ci					goto nope;
1281d4afb5ceSopenharmony_ci
1282d4afb5ceSopenharmony_ci				/* b7 = 0, end or 3-byte */
1283d4afb5ceSopenharmony_ci				if (lextable_h1[pos] < FAIL_CHAR) {
1284d4afb5ceSopenharmony_ci					if (!wsi->mux_substream) {
1285d4afb5ceSopenharmony_ci						/*
1286d4afb5ceSopenharmony_ci						 * We hit a terminal marker, so
1287d4afb5ceSopenharmony_ci						 * we recognized this header...
1288d4afb5ceSopenharmony_ci						 * drop the speculative name
1289d4afb5ceSopenharmony_ci						 * part storage
1290d4afb5ceSopenharmony_ci						 */
1291d4afb5ceSopenharmony_ci						ah->pos = ah->unk_pos;
1292d4afb5ceSopenharmony_ci						ah->unk_pos = 0;
1293d4afb5ceSopenharmony_ci					}
1294d4afb5ceSopenharmony_ci
1295d4afb5ceSopenharmony_ci					ah->lextable_pos = (int16_t)pos;
1296d4afb5ceSopenharmony_ci					break;
1297d4afb5ceSopenharmony_ci				}
1298d4afb5ceSopenharmony_ci
1299d4afb5ceSopenharmony_ci				if (lextable_h1[pos] == c) { /* goto */
1300d4afb5ceSopenharmony_ci					ah->lextable_pos = (int16_t)(pos +
1301d4afb5ceSopenharmony_ci						(lextable_h1[pos + 1]) +
1302d4afb5ceSopenharmony_ci						(lextable_h1[pos + 2] << 8));
1303d4afb5ceSopenharmony_ci					break;
1304d4afb5ceSopenharmony_ci				}
1305d4afb5ceSopenharmony_ci
1306d4afb5ceSopenharmony_ci				/* fall thru goto */
1307d4afb5ceSopenharmony_ci				pos += 3;
1308d4afb5ceSopenharmony_ci				/* continue */
1309d4afb5ceSopenharmony_ci			}
1310d4afb5ceSopenharmony_ci
1311d4afb5ceSopenharmony_ci			/*
1312d4afb5ceSopenharmony_ci			 * If it's h1, server needs to be on the look out for
1313d4afb5ceSopenharmony_ci			 * unknown methods...
1314d4afb5ceSopenharmony_ci			 */
1315d4afb5ceSopenharmony_ci			if (ah->lextable_pos < 0 && lwsi_role_h1(wsi) &&
1316d4afb5ceSopenharmony_ci			    lwsi_role_server(wsi)) {
1317d4afb5ceSopenharmony_ci				/*
1318d4afb5ceSopenharmony_ci				 * this is not a header we know about... did
1319d4afb5ceSopenharmony_ci				 * we get a valid method (GET, POST etc)
1320d4afb5ceSopenharmony_ci				 * already, or is this the bogus method?
1321d4afb5ceSopenharmony_ci				 */
1322d4afb5ceSopenharmony_ci				for (m = 0; m < LWS_ARRAY_SIZE(methods); m++)
1323d4afb5ceSopenharmony_ci					if (ah->frag_index[methods[m]]) {
1324d4afb5ceSopenharmony_ci						/*
1325d4afb5ceSopenharmony_ci						 * already had the method
1326d4afb5ceSopenharmony_ci						 */
1327d4afb5ceSopenharmony_ci#if !defined(LWS_WITH_CUSTOM_HEADERS)
1328d4afb5ceSopenharmony_ci						ah->parser_state = WSI_TOKEN_SKIPPING;
1329d4afb5ceSopenharmony_ci#endif
1330d4afb5ceSopenharmony_ci						if (wsi->mux_substream)
1331d4afb5ceSopenharmony_ci							ah->parser_state = WSI_TOKEN_SKIPPING;
1332d4afb5ceSopenharmony_ci						break;
1333d4afb5ceSopenharmony_ci					}
1334d4afb5ceSopenharmony_ci
1335d4afb5ceSopenharmony_ci				if (m != LWS_ARRAY_SIZE(methods)) {
1336d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CUSTOM_HEADERS)
1337d4afb5ceSopenharmony_ci					/*
1338d4afb5ceSopenharmony_ci					 * We have the method, this is just an
1339d4afb5ceSopenharmony_ci					 * unknown header then
1340d4afb5ceSopenharmony_ci					 */
1341d4afb5ceSopenharmony_ci					if (!wsi->mux_substream)
1342d4afb5ceSopenharmony_ci						goto unknown_hdr;
1343d4afb5ceSopenharmony_ci					else
1344d4afb5ceSopenharmony_ci						break;
1345d4afb5ceSopenharmony_ci#else
1346d4afb5ceSopenharmony_ci					break;
1347d4afb5ceSopenharmony_ci#endif
1348d4afb5ceSopenharmony_ci				}
1349d4afb5ceSopenharmony_ci				/*
1350d4afb5ceSopenharmony_ci				 * ...it's an unknown http method from a client
1351d4afb5ceSopenharmony_ci				 * in fact, it cannot be valid http.
1352d4afb5ceSopenharmony_ci				 *
1353d4afb5ceSopenharmony_ci				 * Are we set up to transition to another role
1354d4afb5ceSopenharmony_ci				 * in these cases?
1355d4afb5ceSopenharmony_ci				 */
1356d4afb5ceSopenharmony_ci				if (lws_check_opt(wsi->a.vhost->options,
1357d4afb5ceSopenharmony_ci		    LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG)) {
1358d4afb5ceSopenharmony_ci					lwsl_notice("%s: http fail fallback\n",
1359d4afb5ceSopenharmony_ci						    __func__);
1360d4afb5ceSopenharmony_ci					 /* transition to other role */
1361d4afb5ceSopenharmony_ci					return LPR_DO_FALLBACK;
1362d4afb5ceSopenharmony_ci				}
1363d4afb5ceSopenharmony_ci
1364d4afb5ceSopenharmony_ci				lwsl_info("Unknown method - dropping\n");
1365d4afb5ceSopenharmony_ci				goto forbid;
1366d4afb5ceSopenharmony_ci			}
1367d4afb5ceSopenharmony_ci			if (ah->lextable_pos < 0) {
1368d4afb5ceSopenharmony_ci				/*
1369d4afb5ceSopenharmony_ci				 * It's not a header that lws knows about...
1370d4afb5ceSopenharmony_ci				 */
1371d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CUSTOM_HEADERS)
1372d4afb5ceSopenharmony_ci				if (!wsi->mux_substream)
1373d4afb5ceSopenharmony_ci					goto unknown_hdr;
1374d4afb5ceSopenharmony_ci#endif
1375d4afb5ceSopenharmony_ci				/*
1376d4afb5ceSopenharmony_ci				 * ...otherwise for a client, let him ignore
1377d4afb5ceSopenharmony_ci				 * unknown headers coming from the server
1378d4afb5ceSopenharmony_ci				 */
1379d4afb5ceSopenharmony_ci				ah->parser_state = WSI_TOKEN_SKIPPING;
1380d4afb5ceSopenharmony_ci				break;
1381d4afb5ceSopenharmony_ci			}
1382d4afb5ceSopenharmony_ci
1383d4afb5ceSopenharmony_ci			if (lextable_h1[ah->lextable_pos] < FAIL_CHAR) {
1384d4afb5ceSopenharmony_ci				/* terminal state */
1385d4afb5ceSopenharmony_ci
1386d4afb5ceSopenharmony_ci				n = ((unsigned int)lextable_h1[ah->lextable_pos] << 8) |
1387d4afb5ceSopenharmony_ci						lextable_h1[ah->lextable_pos + 1];
1388d4afb5ceSopenharmony_ci
1389d4afb5ceSopenharmony_ci				lwsl_parser("known hdr %d\n", n);
1390d4afb5ceSopenharmony_ci				for (m = 0; m < LWS_ARRAY_SIZE(methods); m++)
1391d4afb5ceSopenharmony_ci					if (n == methods[m] &&
1392d4afb5ceSopenharmony_ci					    ah->frag_index[methods[m]]) {
1393d4afb5ceSopenharmony_ci						lwsl_warn("Duplicated method\n");
1394d4afb5ceSopenharmony_ci						return LPR_FAIL;
1395d4afb5ceSopenharmony_ci					}
1396d4afb5ceSopenharmony_ci
1397d4afb5ceSopenharmony_ci				if (!wsi->mux_substream) {
1398d4afb5ceSopenharmony_ci					/*
1399d4afb5ceSopenharmony_ci					 * Whether we are collecting unknown names or not,
1400d4afb5ceSopenharmony_ci					 * if we matched an internal header we can dispense
1401d4afb5ceSopenharmony_ci					 * with the header name part we were keeping
1402d4afb5ceSopenharmony_ci					 */
1403d4afb5ceSopenharmony_ci					ah->pos = ah->unk_pos;
1404d4afb5ceSopenharmony_ci					ah->unk_pos = 0;
1405d4afb5ceSopenharmony_ci				}
1406d4afb5ceSopenharmony_ci
1407d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_WS)
1408d4afb5ceSopenharmony_ci				/*
1409d4afb5ceSopenharmony_ci				 * WSORIGIN is protocol equiv to ORIGIN,
1410d4afb5ceSopenharmony_ci				 * JWebSocket likes to send it, map to ORIGIN
1411d4afb5ceSopenharmony_ci				 */
1412d4afb5ceSopenharmony_ci				if (n == WSI_TOKEN_SWORIGIN)
1413d4afb5ceSopenharmony_ci					n = WSI_TOKEN_ORIGIN;
1414d4afb5ceSopenharmony_ci#endif
1415d4afb5ceSopenharmony_ci
1416d4afb5ceSopenharmony_ci				ah->parser_state = (uint8_t)
1417d4afb5ceSopenharmony_ci							(WSI_TOKEN_GET_URI + n);
1418d4afb5ceSopenharmony_ci				ah->ups = URIPS_IDLE;
1419d4afb5ceSopenharmony_ci
1420d4afb5ceSopenharmony_ci				if (context->token_limits)
1421d4afb5ceSopenharmony_ci					ah->current_token_limit = context->
1422d4afb5ceSopenharmony_ci						token_limits->token_limit[
1423d4afb5ceSopenharmony_ci							      ah->parser_state];
1424d4afb5ceSopenharmony_ci				else
1425d4afb5ceSopenharmony_ci					ah->current_token_limit =
1426d4afb5ceSopenharmony_ci						wsi->a.context->max_http_header_data;
1427d4afb5ceSopenharmony_ci
1428d4afb5ceSopenharmony_ci				if (ah->parser_state == WSI_TOKEN_CHALLENGE)
1429d4afb5ceSopenharmony_ci					goto set_parsing_complete;
1430d4afb5ceSopenharmony_ci
1431d4afb5ceSopenharmony_ci				goto start_fragment;
1432d4afb5ceSopenharmony_ci			}
1433d4afb5ceSopenharmony_ci			break;
1434d4afb5ceSopenharmony_ci
1435d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CUSTOM_HEADERS)
1436d4afb5ceSopenharmony_ciunknown_hdr:
1437d4afb5ceSopenharmony_ci			//ah->parser_state = WSI_TOKEN_SKIPPING;
1438d4afb5ceSopenharmony_ci			//break;
1439d4afb5ceSopenharmony_ci			if (!wsi->mux_substream)
1440d4afb5ceSopenharmony_ci				break;
1441d4afb5ceSopenharmony_ci#endif
1442d4afb5ceSopenharmony_ci
1443d4afb5ceSopenharmony_cistart_fragment:
1444d4afb5ceSopenharmony_ci			ah->nfrag++;
1445d4afb5ceSopenharmony_ciexcessive:
1446d4afb5ceSopenharmony_ci			if (ah->nfrag == LWS_ARRAY_SIZE(ah->frags)) {
1447d4afb5ceSopenharmony_ci				lwsl_warn("More hdr frags than we can deal with\n");
1448d4afb5ceSopenharmony_ci				return LPR_FAIL;
1449d4afb5ceSopenharmony_ci			}
1450d4afb5ceSopenharmony_ci
1451d4afb5ceSopenharmony_ci			ah->frags[ah->nfrag].offset = ah->pos;
1452d4afb5ceSopenharmony_ci			ah->frags[ah->nfrag].len = 0;
1453d4afb5ceSopenharmony_ci			ah->frags[ah->nfrag].nfrag = 0;
1454d4afb5ceSopenharmony_ci			ah->frags[ah->nfrag].flags = 2;
1455d4afb5ceSopenharmony_ci
1456d4afb5ceSopenharmony_ci			n = ah->frag_index[ah->parser_state];
1457d4afb5ceSopenharmony_ci			if (!n) { /* first fragment */
1458d4afb5ceSopenharmony_ci				ah->frag_index[ah->parser_state] = ah->nfrag;
1459d4afb5ceSopenharmony_ci				ah->hdr_token_idx = ah->parser_state;
1460d4afb5ceSopenharmony_ci				break;
1461d4afb5ceSopenharmony_ci			}
1462d4afb5ceSopenharmony_ci			/* continuation */
1463d4afb5ceSopenharmony_ci			while (ah->frags[n].nfrag)
1464d4afb5ceSopenharmony_ci				n = ah->frags[n].nfrag;
1465d4afb5ceSopenharmony_ci			ah->frags[n].nfrag = ah->nfrag;
1466d4afb5ceSopenharmony_ci
1467d4afb5ceSopenharmony_ci			if (issue_char(wsi, ' ') < 0)
1468d4afb5ceSopenharmony_ci				return LPR_FAIL;
1469d4afb5ceSopenharmony_ci			break;
1470d4afb5ceSopenharmony_ci
1471d4afb5ceSopenharmony_ci			/* skipping arg part of a name we didn't recognize */
1472d4afb5ceSopenharmony_ci		case WSI_TOKEN_SKIPPING:
1473d4afb5ceSopenharmony_ci			lwsl_parser("WSI_TOKEN_SKIPPING '%c'\n", c);
1474d4afb5ceSopenharmony_ci
1475d4afb5ceSopenharmony_ci			if (c == '\x0a') {
1476d4afb5ceSopenharmony_ci				/* broken peer */
1477d4afb5ceSopenharmony_ci				ah->parser_state = WSI_TOKEN_NAME_PART;
1478d4afb5ceSopenharmony_ci				ah->unk_pos = 0;
1479d4afb5ceSopenharmony_ci				ah->lextable_pos = 0;
1480d4afb5ceSopenharmony_ci			}
1481d4afb5ceSopenharmony_ci
1482d4afb5ceSopenharmony_ci			if (c == '\x0d')
1483d4afb5ceSopenharmony_ci				ah->parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
1484d4afb5ceSopenharmony_ci			break;
1485d4afb5ceSopenharmony_ci
1486d4afb5ceSopenharmony_ci		case WSI_TOKEN_SKIPPING_SAW_CR:
1487d4afb5ceSopenharmony_ci			lwsl_parser("WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c);
1488d4afb5ceSopenharmony_ci			if (ah->ues != URIES_IDLE)
1489d4afb5ceSopenharmony_ci				goto forbid;
1490d4afb5ceSopenharmony_ci			if (c == '\x0a') {
1491d4afb5ceSopenharmony_ci				ah->parser_state = WSI_TOKEN_NAME_PART;
1492d4afb5ceSopenharmony_ci				ah->unk_pos = 0;
1493d4afb5ceSopenharmony_ci				ah->lextable_pos = 0;
1494d4afb5ceSopenharmony_ci			} else
1495d4afb5ceSopenharmony_ci				ah->parser_state = WSI_TOKEN_SKIPPING;
1496d4afb5ceSopenharmony_ci			break;
1497d4afb5ceSopenharmony_ci			/* we're done, ignore anything else */
1498d4afb5ceSopenharmony_ci
1499d4afb5ceSopenharmony_ci		case WSI_PARSING_COMPLETE:
1500d4afb5ceSopenharmony_ci			lwsl_parser("WSI_PARSING_COMPLETE '%c'\n", c);
1501d4afb5ceSopenharmony_ci			break;
1502d4afb5ceSopenharmony_ci		}
1503d4afb5ceSopenharmony_ci
1504d4afb5ceSopenharmony_ci	} while (*len);
1505d4afb5ceSopenharmony_ci
1506d4afb5ceSopenharmony_ci	return LPR_OK;
1507d4afb5ceSopenharmony_ci
1508d4afb5ceSopenharmony_ciset_parsing_complete:
1509d4afb5ceSopenharmony_ci	if (ah->ues != URIES_IDLE)
1510d4afb5ceSopenharmony_ci		goto forbid;
1511d4afb5ceSopenharmony_ci
1512d4afb5ceSopenharmony_ci	if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {
1513d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_WS)
1514d4afb5ceSopenharmony_ci		const char *pv = lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION);
1515d4afb5ceSopenharmony_ci		if (pv)
1516d4afb5ceSopenharmony_ci			wsi->rx_frame_type = (char)atoi(pv);
1517d4afb5ceSopenharmony_ci
1518d4afb5ceSopenharmony_ci		lwsl_parser("v%02d hdrs done\n", wsi->rx_frame_type);
1519d4afb5ceSopenharmony_ci#endif
1520d4afb5ceSopenharmony_ci	}
1521d4afb5ceSopenharmony_ci	ah->parser_state = WSI_PARSING_COMPLETE;
1522d4afb5ceSopenharmony_ci	wsi->hdr_parsing_completed = 1;
1523d4afb5ceSopenharmony_ci
1524d4afb5ceSopenharmony_ci	return LPR_OK;
1525d4afb5ceSopenharmony_ci
1526d4afb5ceSopenharmony_ciforbid:
1527d4afb5ceSopenharmony_ci	lwsl_info(" forbidding on uri sanitation\n");
1528d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
1529d4afb5ceSopenharmony_ci	lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
1530d4afb5ceSopenharmony_ci#endif
1531d4afb5ceSopenharmony_ci
1532d4afb5ceSopenharmony_ci	return LPR_FORBIDDEN;
1533d4afb5ceSopenharmony_ci}
1534d4afb5ceSopenharmony_ci
1535d4afb5ceSopenharmony_ciint
1536d4afb5ceSopenharmony_cilws_http_cookie_get(struct lws *wsi, const char *name, char *buf,
1537d4afb5ceSopenharmony_ci		    size_t *max_len)
1538d4afb5ceSopenharmony_ci{
1539d4afb5ceSopenharmony_ci	size_t max = *max_len, bl = strlen(name);
1540d4afb5ceSopenharmony_ci	char *p, *bo = buf;
1541d4afb5ceSopenharmony_ci	int n;
1542d4afb5ceSopenharmony_ci
1543d4afb5ceSopenharmony_ci	n = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE);
1544d4afb5ceSopenharmony_ci	if ((unsigned int)n < bl + 1)
1545d4afb5ceSopenharmony_ci		return 1;
1546d4afb5ceSopenharmony_ci
1547d4afb5ceSopenharmony_ci	/*
1548d4afb5ceSopenharmony_ci	 * This can come to us two ways, in ah fragments (h2) or as a single
1549d4afb5ceSopenharmony_ci	 * semicolon-delimited string (h1)
1550d4afb5ceSopenharmony_ci	 */
1551d4afb5ceSopenharmony_ci
1552d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2)
1553d4afb5ceSopenharmony_ci	if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_METHOD)) {
1554d4afb5ceSopenharmony_ci
1555d4afb5ceSopenharmony_ci		/*
1556d4afb5ceSopenharmony_ci		 * The h2 way...
1557d4afb5ceSopenharmony_ci		 */
1558d4afb5ceSopenharmony_ci
1559d4afb5ceSopenharmony_ci		int f = wsi->http.ah->frag_index[WSI_TOKEN_HTTP_COOKIE];
1560d4afb5ceSopenharmony_ci		size_t fl;
1561d4afb5ceSopenharmony_ci
1562d4afb5ceSopenharmony_ci		while (f) {
1563d4afb5ceSopenharmony_ci			p = wsi->http.ah->data + wsi->http.ah->frags[f].offset;
1564d4afb5ceSopenharmony_ci			fl = (size_t)wsi->http.ah->frags[f].len;
1565d4afb5ceSopenharmony_ci			if (fl >= bl + 1 &&
1566d4afb5ceSopenharmony_ci			    p[bl] == '=' &&
1567d4afb5ceSopenharmony_ci			    !memcmp(p, name, bl)) {
1568d4afb5ceSopenharmony_ci				fl -= bl + 1;
1569d4afb5ceSopenharmony_ci				if (max - 1 < fl)
1570d4afb5ceSopenharmony_ci					fl = max - 1;
1571d4afb5ceSopenharmony_ci				if (fl)
1572d4afb5ceSopenharmony_ci					memcpy(buf, p + bl + 1, fl);
1573d4afb5ceSopenharmony_ci				*max_len = fl;
1574d4afb5ceSopenharmony_ci				buf[fl] = '\0';
1575d4afb5ceSopenharmony_ci
1576d4afb5ceSopenharmony_ci				return 0;
1577d4afb5ceSopenharmony_ci			}
1578d4afb5ceSopenharmony_ci			f = wsi->http.ah->frags[f].nfrag;
1579d4afb5ceSopenharmony_ci		}
1580d4afb5ceSopenharmony_ci
1581d4afb5ceSopenharmony_ci		return -1;
1582d4afb5ceSopenharmony_ci	}
1583d4afb5ceSopenharmony_ci#endif
1584d4afb5ceSopenharmony_ci
1585d4afb5ceSopenharmony_ci	/*
1586d4afb5ceSopenharmony_ci	 * The h1 way...
1587d4afb5ceSopenharmony_ci	 */
1588d4afb5ceSopenharmony_ci
1589d4afb5ceSopenharmony_ci	p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COOKIE);
1590d4afb5ceSopenharmony_ci	if (!p)
1591d4afb5ceSopenharmony_ci		return 1;
1592d4afb5ceSopenharmony_ci
1593d4afb5ceSopenharmony_ci	p += bl;
1594d4afb5ceSopenharmony_ci	n -= (int)bl;
1595d4afb5ceSopenharmony_ci	while (n-- > 0) {
1596d4afb5ceSopenharmony_ci		if (*p == '=' && !memcmp(p - bl, name, (unsigned int)bl)) {
1597d4afb5ceSopenharmony_ci			p++;
1598d4afb5ceSopenharmony_ci			while (*p != ';' && n-- && max) {
1599d4afb5ceSopenharmony_ci				*buf++ = *p++;
1600d4afb5ceSopenharmony_ci				max--;
1601d4afb5ceSopenharmony_ci			}
1602d4afb5ceSopenharmony_ci			if (!max)
1603d4afb5ceSopenharmony_ci				return 2;
1604d4afb5ceSopenharmony_ci
1605d4afb5ceSopenharmony_ci			*buf = '\0';
1606d4afb5ceSopenharmony_ci			*max_len = lws_ptr_diff_size_t(buf, bo);
1607d4afb5ceSopenharmony_ci
1608d4afb5ceSopenharmony_ci			return 0;
1609d4afb5ceSopenharmony_ci		}
1610d4afb5ceSopenharmony_ci		p++;
1611d4afb5ceSopenharmony_ci	}
1612d4afb5ceSopenharmony_ci
1613d4afb5ceSopenharmony_ci	return 1;
1614d4afb5ceSopenharmony_ci}
1615d4afb5ceSopenharmony_ci
1616d4afb5ceSopenharmony_ci#if defined(LWS_WITH_JOSE)
1617d4afb5ceSopenharmony_ci
1618d4afb5ceSopenharmony_ci#define MAX_JWT_SIZE 1024
1619d4afb5ceSopenharmony_ci
1620d4afb5ceSopenharmony_ciint
1621d4afb5ceSopenharmony_cilws_jwt_get_http_cookie_validate_jwt(struct lws *wsi,
1622d4afb5ceSopenharmony_ci				     struct lws_jwt_sign_set_cookie *i,
1623d4afb5ceSopenharmony_ci				     char *out, size_t *out_len)
1624d4afb5ceSopenharmony_ci{
1625d4afb5ceSopenharmony_ci	char temp[MAX_JWT_SIZE * 2];
1626d4afb5ceSopenharmony_ci	size_t cml = *out_len;
1627d4afb5ceSopenharmony_ci	const char *cp;
1628d4afb5ceSopenharmony_ci
1629d4afb5ceSopenharmony_ci	/* first use out to hold the encoded JWT */
1630d4afb5ceSopenharmony_ci
1631d4afb5ceSopenharmony_ci	if (lws_http_cookie_get(wsi, i->cookie_name, out, out_len)) {
1632d4afb5ceSopenharmony_ci		lwsl_debug("%s: cookie %s not provided\n", __func__,
1633d4afb5ceSopenharmony_ci				i->cookie_name);
1634d4afb5ceSopenharmony_ci		return 1;
1635d4afb5ceSopenharmony_ci	}
1636d4afb5ceSopenharmony_ci
1637d4afb5ceSopenharmony_ci	/* decode the JWT into temp */
1638d4afb5ceSopenharmony_ci
1639d4afb5ceSopenharmony_ci	if (lws_jwt_signed_validate(wsi->a.context, i->jwk, i->alg, out,
1640d4afb5ceSopenharmony_ci				    *out_len, temp, sizeof(temp), out, &cml)) {
1641d4afb5ceSopenharmony_ci		lwsl_info("%s: jwt validation failed\n", __func__);
1642d4afb5ceSopenharmony_ci		return 1;
1643d4afb5ceSopenharmony_ci	}
1644d4afb5ceSopenharmony_ci
1645d4afb5ceSopenharmony_ci	/*
1646d4afb5ceSopenharmony_ci	 * Copy out the decoded JWT payload into out, overwriting the
1647d4afb5ceSopenharmony_ci	 * original encoded JWT taken from the cookie (that has long ago been
1648d4afb5ceSopenharmony_ci	 * translated into allocated buffers in the JOSE object)
1649d4afb5ceSopenharmony_ci	 */
1650d4afb5ceSopenharmony_ci
1651d4afb5ceSopenharmony_ci	if (lws_jwt_token_sanity(out, cml, i->iss, i->aud, i->csrf_in,
1652d4afb5ceSopenharmony_ci				 i->sub, sizeof(i->sub),
1653d4afb5ceSopenharmony_ci				 &i->expiry_unix_time)) {
1654d4afb5ceSopenharmony_ci		lwsl_notice("%s: jwt sanity failed\n", __func__);
1655d4afb5ceSopenharmony_ci		return 1;
1656d4afb5ceSopenharmony_ci	}
1657d4afb5ceSopenharmony_ci
1658d4afb5ceSopenharmony_ci	/*
1659d4afb5ceSopenharmony_ci	 * If he's interested in his private JSON part, point him to that in
1660d4afb5ceSopenharmony_ci	 * the args struct (it's pointing to the data in out
1661d4afb5ceSopenharmony_ci	 */
1662d4afb5ceSopenharmony_ci
1663d4afb5ceSopenharmony_ci	cp = lws_json_simple_find(out, cml, "\"ext\":", &i->extra_json_len);
1664d4afb5ceSopenharmony_ci	if (cp)
1665d4afb5ceSopenharmony_ci		i->extra_json = cp;
1666d4afb5ceSopenharmony_ci
1667d4afb5ceSopenharmony_ci	if (!cp)
1668d4afb5ceSopenharmony_ci		lwsl_notice("%s: no ext JWT payload\n", __func__);
1669d4afb5ceSopenharmony_ci
1670d4afb5ceSopenharmony_ci	return 0;
1671d4afb5ceSopenharmony_ci}
1672d4afb5ceSopenharmony_ci
1673d4afb5ceSopenharmony_ciint
1674d4afb5ceSopenharmony_cilws_jwt_sign_token_set_http_cookie(struct lws *wsi,
1675d4afb5ceSopenharmony_ci				   const struct lws_jwt_sign_set_cookie *i,
1676d4afb5ceSopenharmony_ci				   uint8_t **p, uint8_t *end)
1677d4afb5ceSopenharmony_ci{
1678d4afb5ceSopenharmony_ci	char plain[MAX_JWT_SIZE + 1], temp[MAX_JWT_SIZE * 2], csrf[17];
1679d4afb5ceSopenharmony_ci	size_t pl = sizeof(plain);
1680d4afb5ceSopenharmony_ci	unsigned long long ull;
1681d4afb5ceSopenharmony_ci	int n;
1682d4afb5ceSopenharmony_ci
1683d4afb5ceSopenharmony_ci	/*
1684d4afb5ceSopenharmony_ci	 * Create a 16-char random csrf token with the same lifetime as the JWT
1685d4afb5ceSopenharmony_ci	 */
1686d4afb5ceSopenharmony_ci
1687d4afb5ceSopenharmony_ci	lws_hex_random(wsi->a.context, csrf, sizeof(csrf));
1688d4afb5ceSopenharmony_ci	ull = lws_now_secs();
1689d4afb5ceSopenharmony_ci	if (lws_jwt_sign_compact(wsi->a.context, i->jwk, i->alg, plain, &pl,
1690d4afb5ceSopenharmony_ci			         temp, sizeof(temp),
1691d4afb5ceSopenharmony_ci			         "{\"iss\":\"%s\",\"aud\":\"%s\","
1692d4afb5ceSopenharmony_ci			          "\"iat\":%llu,\"nbf\":%llu,\"exp\":%llu,"
1693d4afb5ceSopenharmony_ci			          "\"csrf\":\"%s\",\"sub\":\"%s\"%s%s%s}",
1694d4afb5ceSopenharmony_ci			         i->iss, i->aud, ull, ull - 60,
1695d4afb5ceSopenharmony_ci			         ull + i->expiry_unix_time,
1696d4afb5ceSopenharmony_ci			         csrf, i->sub,
1697d4afb5ceSopenharmony_ci			         i->extra_json ? ",\"ext\":{" : "",
1698d4afb5ceSopenharmony_ci			         i->extra_json ? i->extra_json : "",
1699d4afb5ceSopenharmony_ci			         i->extra_json ? "}" : "")) {
1700d4afb5ceSopenharmony_ci		lwsl_err("%s: failed to create JWT\n", __func__);
1701d4afb5ceSopenharmony_ci
1702d4afb5ceSopenharmony_ci		return 1;
1703d4afb5ceSopenharmony_ci	}
1704d4afb5ceSopenharmony_ci
1705d4afb5ceSopenharmony_ci	/*
1706d4afb5ceSopenharmony_ci	 * There's no point the browser holding on to a JWT beyond the JWT's
1707d4afb5ceSopenharmony_ci	 * expiry time, so set it to be the same.
1708d4afb5ceSopenharmony_ci	 */
1709d4afb5ceSopenharmony_ci
1710d4afb5ceSopenharmony_ci	n = lws_snprintf(temp, sizeof(temp), "__Host-%s=%s;"
1711d4afb5ceSopenharmony_ci			 "HttpOnly;"
1712d4afb5ceSopenharmony_ci			 "Secure;"
1713d4afb5ceSopenharmony_ci			 "SameSite=strict;"
1714d4afb5ceSopenharmony_ci			 "Path=/;"
1715d4afb5ceSopenharmony_ci			 "Max-Age=%lu",
1716d4afb5ceSopenharmony_ci			 i->cookie_name, plain, i->expiry_unix_time);
1717d4afb5ceSopenharmony_ci
1718d4afb5ceSopenharmony_ci	if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SET_COOKIE,
1719d4afb5ceSopenharmony_ci					 (uint8_t *)temp, n, p, end)) {
1720d4afb5ceSopenharmony_ci		lwsl_err("%s: failed to add JWT cookie header\n", __func__);
1721d4afb5ceSopenharmony_ci		return 1;
1722d4afb5ceSopenharmony_ci	}
1723d4afb5ceSopenharmony_ci
1724d4afb5ceSopenharmony_ci	return 0;
1725d4afb5ceSopenharmony_ci}
1726d4afb5ceSopenharmony_ci#endif
1727