1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2019 - 2020 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 * This is the glue that wires up h1 to Secure Streams.
25d4afb5ceSopenharmony_ci */
26d4afb5ceSopenharmony_ci
27d4afb5ceSopenharmony_ci#include <private-lib-core.h>
28d4afb5ceSopenharmony_ci
29d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_FREERTOS) || defined(LWS_ROLE_H2)
30d4afb5ceSopenharmony_ci#define LWS_WITH_SS_RIDESHARE
31d4afb5ceSopenharmony_ci#endif
32d4afb5ceSopenharmony_ci
33d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SS_RIDESHARE)
34d4afb5ceSopenharmony_cistatic int
35d4afb5ceSopenharmony_ciss_http_multipart_parser(lws_ss_handle_t *h, void *in, size_t len)
36d4afb5ceSopenharmony_ci{
37d4afb5ceSopenharmony_ci	uint8_t *q = (uint8_t *)in;
38d4afb5ceSopenharmony_ci	int pending_issue = 0, n = 0;
39d4afb5ceSopenharmony_ci
40d4afb5ceSopenharmony_ci
41d4afb5ceSopenharmony_ci	/* let's stick it in the boundary state machine first */
42d4afb5ceSopenharmony_ci	while (n < (int)len) {
43d4afb5ceSopenharmony_ci		if (h->u.http.boundary_seq != h->u.http.boundary_len) {
44d4afb5ceSopenharmony_ci			if (q[n] == h->u.http.boundary[h->u.http.boundary_seq])
45d4afb5ceSopenharmony_ci				h->u.http.boundary_seq++;
46d4afb5ceSopenharmony_ci			else {
47d4afb5ceSopenharmony_ci				h->u.http.boundary_seq = 0;
48d4afb5ceSopenharmony_ci				h->u.http.boundary_dashes = 0;
49d4afb5ceSopenharmony_ci				h->u.http.boundary_post = 0;
50d4afb5ceSopenharmony_ci			}
51d4afb5ceSopenharmony_ci			goto around;
52d4afb5ceSopenharmony_ci		}
53d4afb5ceSopenharmony_ci
54d4afb5ceSopenharmony_ci		/*
55d4afb5ceSopenharmony_ci		 * We already matched the boundary string, now we're
56d4afb5ceSopenharmony_ci		 * looking if there's a -- afterwards
57d4afb5ceSopenharmony_ci		 */
58d4afb5ceSopenharmony_ci		if (h->u.http.boundary_dashes < 2) {
59d4afb5ceSopenharmony_ci			if (q[n] == '-') {
60d4afb5ceSopenharmony_ci				h->u.http.boundary_dashes++;
61d4afb5ceSopenharmony_ci				goto around;
62d4afb5ceSopenharmony_ci			}
63d4afb5ceSopenharmony_ci			/* there was no final -- ... */
64d4afb5ceSopenharmony_ci		}
65d4afb5ceSopenharmony_ci
66d4afb5ceSopenharmony_ci		if (h->u.http.boundary_dashes == 2) {
67d4afb5ceSopenharmony_ci			/*
68d4afb5ceSopenharmony_ci			 * It's an EOM boundary: issue pending + multipart EOP
69d4afb5ceSopenharmony_ci			 */
70d4afb5ceSopenharmony_ci			lwsl_debug("%s: seen EOP, n %d pi %d\n",
71d4afb5ceSopenharmony_ci				    __func__, n, pending_issue);
72d4afb5ceSopenharmony_ci			/*
73d4afb5ceSopenharmony_ci			 * It's possible we already started the decode before
74d4afb5ceSopenharmony_ci			 * the end of the last packet.  Then there is no
75d4afb5ceSopenharmony_ci			 * remainder to send.
76d4afb5ceSopenharmony_ci			 */
77d4afb5ceSopenharmony_ci			if (n >= pending_issue + h->u.http.boundary_len +
78d4afb5ceSopenharmony_ci			    (h->u.http.any ? 2 : 0) + 1) {
79d4afb5ceSopenharmony_ci				h->info.rx(ss_to_userobj(h),
80d4afb5ceSopenharmony_ci					   &q[pending_issue],
81d4afb5ceSopenharmony_ci					   (unsigned int)(n - pending_issue -
82d4afb5ceSopenharmony_ci					   h->u.http.boundary_len - 1 -
83d4afb5ceSopenharmony_ci					   (h->u.http.any ? 2 : 0) /* crlf */),
84d4afb5ceSopenharmony_ci				   (!h->u.http.som ? LWSSS_FLAG_SOM : 0) |
85d4afb5ceSopenharmony_ci				   LWSSS_FLAG_EOM | LWSSS_FLAG_RELATED_END);
86d4afb5ceSopenharmony_ci				h->u.http.eom = 1;
87d4afb5ceSopenharmony_ci			}
88d4afb5ceSopenharmony_ci
89d4afb5ceSopenharmony_ci			/*
90d4afb5ceSopenharmony_ci			 * Peer may not END_STREAM us
91d4afb5ceSopenharmony_ci			 */
92d4afb5ceSopenharmony_ci			return 0;
93d4afb5ceSopenharmony_ci			//return -1;
94d4afb5ceSopenharmony_ci		}
95d4afb5ceSopenharmony_ci
96d4afb5ceSopenharmony_ci		/* how about --boundaryCRLF */
97d4afb5ceSopenharmony_ci
98d4afb5ceSopenharmony_ci		if (h->u.http.boundary_post < 2) {
99d4afb5ceSopenharmony_ci			if ((!h->u.http.boundary_post && q[n] == '\x0d') ||
100d4afb5ceSopenharmony_ci			    (h->u.http.boundary_post && q[n] == '\x0a')) {
101d4afb5ceSopenharmony_ci				h->u.http.boundary_post++;
102d4afb5ceSopenharmony_ci				goto around;
103d4afb5ceSopenharmony_ci			}
104d4afb5ceSopenharmony_ci			/* there was no final CRLF ... it's wrong */
105d4afb5ceSopenharmony_ci
106d4afb5ceSopenharmony_ci			return -1;
107d4afb5ceSopenharmony_ci		}
108d4afb5ceSopenharmony_ci		if (h->u.http.boundary_post != 2)
109d4afb5ceSopenharmony_ci			goto around;
110d4afb5ceSopenharmony_ci
111d4afb5ceSopenharmony_ci		/*
112d4afb5ceSopenharmony_ci		 * We have a starting "--boundaryCRLF" or intermediate
113d4afb5ceSopenharmony_ci		 * "CRLF--boundaryCRLF" boundary
114d4afb5ceSopenharmony_ci		 */
115d4afb5ceSopenharmony_ci		lwsl_debug("%s: b_post = 2 (pi %d)\n", __func__, pending_issue);
116d4afb5ceSopenharmony_ci		h->u.http.boundary_seq = 0;
117d4afb5ceSopenharmony_ci		h->u.http.boundary_post = 0;
118d4afb5ceSopenharmony_ci
119d4afb5ceSopenharmony_ci		if (n >= pending_issue && (h->u.http.any || !h->u.http.som)) {
120d4afb5ceSopenharmony_ci			/* Intermediate... do the EOM */
121d4afb5ceSopenharmony_ci			lwsl_debug("%s: seen interm EOP n %d pi %d\n", __func__,
122d4afb5ceSopenharmony_ci				   n, pending_issue);
123d4afb5ceSopenharmony_ci			/*
124d4afb5ceSopenharmony_ci			 * It's possible we already started the decode before
125d4afb5ceSopenharmony_ci			 * the end of the last packet.  Then there is no
126d4afb5ceSopenharmony_ci			 * remainder to send.
127d4afb5ceSopenharmony_ci			 */
128d4afb5ceSopenharmony_ci			if (n >= pending_issue + h->u.http.boundary_len +
129d4afb5ceSopenharmony_ci			    (h->u.http.any ? 2 : 0)) {
130d4afb5ceSopenharmony_ci				h->info.rx(ss_to_userobj(h), &q[pending_issue],
131d4afb5ceSopenharmony_ci					   (unsigned int)(n - pending_issue -
132d4afb5ceSopenharmony_ci					       h->u.http.boundary_len -
133d4afb5ceSopenharmony_ci					       (h->u.http.any ? 2 /* crlf */ : 0)),
134d4afb5ceSopenharmony_ci					   (!h->u.http.som ? LWSSS_FLAG_SOM : 0) |
135d4afb5ceSopenharmony_ci					   LWSSS_FLAG_EOM);
136d4afb5ceSopenharmony_ci				h->u.http.eom = 1;
137d4afb5ceSopenharmony_ci			}
138d4afb5ceSopenharmony_ci		}
139d4afb5ceSopenharmony_ci
140d4afb5ceSopenharmony_ci		/* Next message starts after this boundary */
141d4afb5ceSopenharmony_ci
142d4afb5ceSopenharmony_ci		pending_issue = n;
143d4afb5ceSopenharmony_ci		if (h->u.http.eom) {
144d4afb5ceSopenharmony_ci			/* reset only if we have sent eom */
145d4afb5ceSopenharmony_ci			h->u.http.som = 0;
146d4afb5ceSopenharmony_ci			h->u.http.eom = 0;
147d4afb5ceSopenharmony_ci		}
148d4afb5ceSopenharmony_ci
149d4afb5ceSopenharmony_ciaround:
150d4afb5ceSopenharmony_ci		n++;
151d4afb5ceSopenharmony_ci	}
152d4afb5ceSopenharmony_ci
153d4afb5ceSopenharmony_ci	if (pending_issue != n) {
154d4afb5ceSopenharmony_ci		uint8_t oh = 0;
155d4afb5ceSopenharmony_ci
156d4afb5ceSopenharmony_ci		/*
157d4afb5ceSopenharmony_ci		 * handle the first or last "--boundaryCRLF" case which is not captured in the
158d4afb5ceSopenharmony_ci		 * previous loop, on the Bob downchannel (/directive)
159d4afb5ceSopenharmony_ci		 *
160d4afb5ceSopenharmony_ci		 * probably does not cover the case that one boundary term is separated in multipile
161d4afb5ceSopenharmony_ci		 * one callbacks though never see such case
162d4afb5ceSopenharmony_ci		 */
163d4afb5ceSopenharmony_ci
164d4afb5ceSopenharmony_ci		if ((n >= h->u.http.boundary_len) &&
165d4afb5ceSopenharmony_ci			h->u.http.boundary_seq == h->u.http.boundary_len &&
166d4afb5ceSopenharmony_ci			h->u.http.boundary_post == 2) {
167d4afb5ceSopenharmony_ci
168d4afb5ceSopenharmony_ci			oh = 1;
169d4afb5ceSopenharmony_ci		}
170d4afb5ceSopenharmony_ci
171d4afb5ceSopenharmony_ci		h->info.rx(ss_to_userobj(h), &q[pending_issue],
172d4afb5ceSopenharmony_ci				(unsigned int)(oh ?
173d4afb5ceSopenharmony_ci				(n - pending_issue - h->u.http.boundary_len -
174d4afb5ceSopenharmony_ci					(h->u.http.any ? 2 : 0)) :
175d4afb5ceSopenharmony_ci				(n - pending_issue)),
176d4afb5ceSopenharmony_ci			   (!h->u.http.som ? LWSSS_FLAG_SOM : 0) |
177d4afb5ceSopenharmony_ci			     (oh && h->u.http.any ? LWSSS_FLAG_EOM : 0));
178d4afb5ceSopenharmony_ci
179d4afb5ceSopenharmony_ci		if (oh && h->u.http.any)
180d4afb5ceSopenharmony_ci			h->u.http.eom = 1;
181d4afb5ceSopenharmony_ci
182d4afb5ceSopenharmony_ci		h->u.http.any = 1;
183d4afb5ceSopenharmony_ci		h->u.http.som = 1;
184d4afb5ceSopenharmony_ci	}
185d4afb5ceSopenharmony_ci
186d4afb5ceSopenharmony_ci	return 0;
187d4afb5ceSopenharmony_ci}
188d4afb5ceSopenharmony_ci#endif
189d4afb5ceSopenharmony_ci
190d4afb5ceSopenharmony_ci/*
191d4afb5ceSopenharmony_ci * Returns 0, or the ss state resp maps on to
192d4afb5ceSopenharmony_ci */
193d4afb5ceSopenharmony_ci
194d4afb5ceSopenharmony_cistatic int
195d4afb5ceSopenharmony_cilws_ss_http_resp_to_state(lws_ss_handle_t *h, int resp)
196d4afb5ceSopenharmony_ci{
197d4afb5ceSopenharmony_ci	const lws_ss_http_respmap_t *r = h->policy->u.http.respmap;
198d4afb5ceSopenharmony_ci	int n = h->policy->u.http.count_respmap;
199d4afb5ceSopenharmony_ci
200d4afb5ceSopenharmony_ci	while (n--)
201d4afb5ceSopenharmony_ci		if (resp == r->resp)
202d4afb5ceSopenharmony_ci			return r->state;
203d4afb5ceSopenharmony_ci		else
204d4afb5ceSopenharmony_ci			r++;
205d4afb5ceSopenharmony_ci
206d4afb5ceSopenharmony_ci	return 0; /* no hit */
207d4afb5ceSopenharmony_ci}
208d4afb5ceSopenharmony_ci
209d4afb5ceSopenharmony_ci/*
210d4afb5ceSopenharmony_ci * This converts any set metadata items into outgoing http headers
211d4afb5ceSopenharmony_ci */
212d4afb5ceSopenharmony_ci
213d4afb5ceSopenharmony_cistatic int
214d4afb5ceSopenharmony_cilws_apply_metadata(lws_ss_handle_t *h, struct lws *wsi, uint8_t *buf,
215d4afb5ceSopenharmony_ci		   uint8_t **pp, uint8_t *end)
216d4afb5ceSopenharmony_ci{
217d4afb5ceSopenharmony_ci	lws_ss_metadata_t *polmd = h->policy->metadata;
218d4afb5ceSopenharmony_ci	int m = 0;
219d4afb5ceSopenharmony_ci
220d4afb5ceSopenharmony_ci	while (polmd) {
221d4afb5ceSopenharmony_ci
222d4afb5ceSopenharmony_ci		/* has to have a non-empty header string */
223d4afb5ceSopenharmony_ci
224d4afb5ceSopenharmony_ci		if (polmd->value__may_own_heap &&
225d4afb5ceSopenharmony_ci		    ((uint8_t *)polmd->value__may_own_heap)[0] &&
226d4afb5ceSopenharmony_ci		    h->metadata[m].value__may_own_heap) {
227d4afb5ceSopenharmony_ci			if (lws_add_http_header_by_name(wsi,
228d4afb5ceSopenharmony_ci					polmd->value__may_own_heap,
229d4afb5ceSopenharmony_ci					h->metadata[m].value__may_own_heap,
230d4afb5ceSopenharmony_ci					(int)h->metadata[m].length, pp, end))
231d4afb5ceSopenharmony_ci			return -1;
232d4afb5ceSopenharmony_ci
233d4afb5ceSopenharmony_ci			/*
234d4afb5ceSopenharmony_ci			 * Check for the case he's setting a non-zero
235d4afb5ceSopenharmony_ci			 * content-length "via the backdoor" metadata-
236d4afb5ceSopenharmony_ci			 * driven headers, and set the body_pending()
237d4afb5ceSopenharmony_ci			 * state if so...
238d4afb5ceSopenharmony_ci			 */
239d4afb5ceSopenharmony_ci
240d4afb5ceSopenharmony_ci			if (!strncmp(polmd->value__may_own_heap,
241d4afb5ceSopenharmony_ci				     "content-length", 14) &&
242d4afb5ceSopenharmony_ci			    atoi(h->metadata[m].value__may_own_heap))
243d4afb5ceSopenharmony_ci				lws_client_http_body_pending(wsi, 1);
244d4afb5ceSopenharmony_ci		}
245d4afb5ceSopenharmony_ci
246d4afb5ceSopenharmony_ci		m++;
247d4afb5ceSopenharmony_ci		polmd = polmd->next;
248d4afb5ceSopenharmony_ci	}
249d4afb5ceSopenharmony_ci
250d4afb5ceSopenharmony_ci	/*
251d4afb5ceSopenharmony_ci	 * Content-length on POST / PUT / PATCH if we have the length information
252d4afb5ceSopenharmony_ci	 */
253d4afb5ceSopenharmony_ci
254d4afb5ceSopenharmony_ci	if (h->policy->u.http.method && (
255d4afb5ceSopenharmony_ci		(!strcmp(h->policy->u.http.method, "POST") ||
256d4afb5ceSopenharmony_ci		 !strcmp(h->policy->u.http.method, "PATCH") ||
257d4afb5ceSopenharmony_ci		 !strcmp(h->policy->u.http.method, "PUT"))) &&
258d4afb5ceSopenharmony_ci	    wsi->http.writeable_len) {
259d4afb5ceSopenharmony_ci		if (!(h->policy->flags &
260d4afb5ceSopenharmony_ci			LWSSSPOLF_HTTP_NO_CONTENT_LENGTH)) {
261d4afb5ceSopenharmony_ci			int n = lws_snprintf((char *)buf, 20, "%u",
262d4afb5ceSopenharmony_ci				(unsigned int)wsi->http.writeable_len);
263d4afb5ceSopenharmony_ci			if (lws_add_http_header_by_token(wsi,
264d4afb5ceSopenharmony_ci					WSI_TOKEN_HTTP_CONTENT_LENGTH,
265d4afb5ceSopenharmony_ci					buf, n, pp, end))
266d4afb5ceSopenharmony_ci				return -1;
267d4afb5ceSopenharmony_ci		}
268d4afb5ceSopenharmony_ci		lws_client_http_body_pending(wsi, 1);
269d4afb5ceSopenharmony_ci	}
270d4afb5ceSopenharmony_ci
271d4afb5ceSopenharmony_ci	return 0;
272d4afb5ceSopenharmony_ci}
273d4afb5ceSopenharmony_ci
274d4afb5ceSopenharmony_ci
275d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
276d4afb5ceSopenharmony_cistatic int
277d4afb5ceSopenharmony_cilws_apply_instant_metadata(lws_ss_handle_t *h, struct lws *wsi, uint8_t *buf,
278d4afb5ceSopenharmony_ci		   uint8_t **pp, uint8_t *end)
279d4afb5ceSopenharmony_ci{
280d4afb5ceSopenharmony_ci	lws_ss_metadata_t *imd = h->instant_metadata;
281d4afb5ceSopenharmony_ci
282d4afb5ceSopenharmony_ci	while (imd) {
283d4afb5ceSopenharmony_ci		if (imd->name && imd->value__may_own_heap) {
284d4afb5ceSopenharmony_ci			lwsl_debug("%s add header %s %s %d\n", __func__,
285d4afb5ceSopenharmony_ci					           imd->name,
286d4afb5ceSopenharmony_ci			                           (char *)imd->value__may_own_heap,
287d4afb5ceSopenharmony_ci						   (int)imd->length);
288d4afb5ceSopenharmony_ci			if (lws_add_http_header_by_name(wsi,
289d4afb5ceSopenharmony_ci					(const unsigned char *)imd->name,
290d4afb5ceSopenharmony_ci					(const unsigned char *)imd->value__may_own_heap,
291d4afb5ceSopenharmony_ci					(int)imd->length, pp, end))
292d4afb5ceSopenharmony_ci			return -1;
293d4afb5ceSopenharmony_ci
294d4afb5ceSopenharmony_ci			/* it's possible user set content-length directly */
295d4afb5ceSopenharmony_ci			if (!strncmp(imd->name,
296d4afb5ceSopenharmony_ci				     "content-length", 14) &&
297d4afb5ceSopenharmony_ci			    atoi(imd->value__may_own_heap))
298d4afb5ceSopenharmony_ci				lws_client_http_body_pending(wsi, 1);
299d4afb5ceSopenharmony_ci
300d4afb5ceSopenharmony_ci		}
301d4afb5ceSopenharmony_ci
302d4afb5ceSopenharmony_ci		imd = imd->next;
303d4afb5ceSopenharmony_ci	}
304d4afb5ceSopenharmony_ci
305d4afb5ceSopenharmony_ci	return 0;
306d4afb5ceSopenharmony_ci}
307d4afb5ceSopenharmony_ci#endif
308d4afb5ceSopenharmony_ci/*
309d4afb5ceSopenharmony_ci * Check if any metadata headers present in the server headers, and record
310d4afb5ceSopenharmony_ci * them into the associated metadata item if so.
311d4afb5ceSopenharmony_ci */
312d4afb5ceSopenharmony_ci
313d4afb5ceSopenharmony_cistatic int
314d4afb5ceSopenharmony_cilws_extract_metadata(lws_ss_handle_t *h, struct lws *wsi)
315d4afb5ceSopenharmony_ci{
316d4afb5ceSopenharmony_ci	lws_ss_metadata_t *polmd = h->policy->metadata, *omd;
317d4afb5ceSopenharmony_ci	int n;
318d4afb5ceSopenharmony_ci
319d4afb5ceSopenharmony_ci	while (polmd) {
320d4afb5ceSopenharmony_ci
321d4afb5ceSopenharmony_ci		if (polmd->value_is_http_token != LWS_HTTP_NO_KNOWN_HEADER) {
322d4afb5ceSopenharmony_ci
323d4afb5ceSopenharmony_ci			/* it's a well-known header token */
324d4afb5ceSopenharmony_ci
325d4afb5ceSopenharmony_ci			n = lws_hdr_total_length(wsi, polmd->value_is_http_token);
326d4afb5ceSopenharmony_ci			if (n) {
327d4afb5ceSopenharmony_ci				const char *cp = lws_hdr_simple_ptr(wsi,
328d4afb5ceSopenharmony_ci						polmd->value_is_http_token);
329d4afb5ceSopenharmony_ci				omd = lws_ss_get_handle_metadata(h, polmd->name);
330d4afb5ceSopenharmony_ci				if (!omd || !cp)
331d4afb5ceSopenharmony_ci					return 1;
332d4afb5ceSopenharmony_ci
333d4afb5ceSopenharmony_ci				assert(!strcmp(omd->name, polmd->name));
334d4afb5ceSopenharmony_ci
335d4afb5ceSopenharmony_ci				/*
336d4afb5ceSopenharmony_ci				 * it's present on the wsi, we want to
337d4afb5ceSopenharmony_ci				 * set the related metadata name to it then
338d4afb5ceSopenharmony_ci				 */
339d4afb5ceSopenharmony_ci
340d4afb5ceSopenharmony_ci				_lws_ss_alloc_set_metadata(omd, polmd->name, cp,
341d4afb5ceSopenharmony_ci							   (unsigned int)n);
342d4afb5ceSopenharmony_ci
343d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
344d4afb5ceSopenharmony_ci				/*
345d4afb5ceSopenharmony_ci				 * ...and because we are doing it from parsing
346d4afb5ceSopenharmony_ci				 * onward rx, we want to mark the metadata as
347d4afb5ceSopenharmony_ci				 * needing passing to the client
348d4afb5ceSopenharmony_ci				 */
349d4afb5ceSopenharmony_ci				omd->pending_onward = 1;
350d4afb5ceSopenharmony_ci#endif
351d4afb5ceSopenharmony_ci			}
352d4afb5ceSopenharmony_ci		}
353d4afb5ceSopenharmony_ci
354d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CUSTOM_HEADERS)
355d4afb5ceSopenharmony_ci		else
356d4afb5ceSopenharmony_ci
357d4afb5ceSopenharmony_ci			/* has to have a non-empty header string */
358d4afb5ceSopenharmony_ci
359d4afb5ceSopenharmony_ci			if (polmd->value__may_own_heap &&
360d4afb5ceSopenharmony_ci			    ((uint8_t *)polmd->value__may_own_heap)[0]) {
361d4afb5ceSopenharmony_ci				char *p;
362d4afb5ceSopenharmony_ci
363d4afb5ceSopenharmony_ci				/*
364d4afb5ceSopenharmony_ci				 * Can it be a custom header?
365d4afb5ceSopenharmony_ci				 */
366d4afb5ceSopenharmony_ci
367d4afb5ceSopenharmony_ci				n = lws_hdr_custom_length(wsi, (const char *)
368d4afb5ceSopenharmony_ci						    polmd->value__may_own_heap,
369d4afb5ceSopenharmony_ci						    polmd->value_length);
370d4afb5ceSopenharmony_ci				if (n > 0) {
371d4afb5ceSopenharmony_ci
372d4afb5ceSopenharmony_ci					p = lws_malloc((unsigned int)n + 1, __func__);
373d4afb5ceSopenharmony_ci					if (!p)
374d4afb5ceSopenharmony_ci						return 1;
375d4afb5ceSopenharmony_ci
376d4afb5ceSopenharmony_ci					/* if needed, free any previous value */
377d4afb5ceSopenharmony_ci
378d4afb5ceSopenharmony_ci					if (polmd->value_on_lws_heap) {
379d4afb5ceSopenharmony_ci						lws_free(
380d4afb5ceSopenharmony_ci						    polmd->value__may_own_heap);
381d4afb5ceSopenharmony_ci						polmd->value_on_lws_heap = 0;
382d4afb5ceSopenharmony_ci					}
383d4afb5ceSopenharmony_ci
384d4afb5ceSopenharmony_ci					/*
385d4afb5ceSopenharmony_ci					 * copy the named custom header value
386d4afb5ceSopenharmony_ci					 * into the malloc'd buffer
387d4afb5ceSopenharmony_ci					 */
388d4afb5ceSopenharmony_ci
389d4afb5ceSopenharmony_ci					if (lws_hdr_custom_copy(wsi, p, n + 1,
390d4afb5ceSopenharmony_ci						     (const char *)
391d4afb5ceSopenharmony_ci						     polmd->value__may_own_heap,
392d4afb5ceSopenharmony_ci						     polmd->value_length) < 0) {
393d4afb5ceSopenharmony_ci						lws_free(p);
394d4afb5ceSopenharmony_ci
395d4afb5ceSopenharmony_ci						return 1;
396d4afb5ceSopenharmony_ci					}
397d4afb5ceSopenharmony_ci
398d4afb5ceSopenharmony_ci					omd = lws_ss_get_handle_metadata(h,
399d4afb5ceSopenharmony_ci								   polmd->name);
400d4afb5ceSopenharmony_ci					if (omd) {
401d4afb5ceSopenharmony_ci
402d4afb5ceSopenharmony_ci						_lws_ss_set_metadata(omd,
403d4afb5ceSopenharmony_ci							polmd->name, p, (size_t)n);
404d4afb5ceSopenharmony_ci						omd->value_on_lws_heap = 1;
405d4afb5ceSopenharmony_ci
406d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
407d4afb5ceSopenharmony_ci						omd->pending_onward = 1;
408d4afb5ceSopenharmony_ci#endif
409d4afb5ceSopenharmony_ci					}
410d4afb5ceSopenharmony_ci				}
411d4afb5ceSopenharmony_ci			}
412d4afb5ceSopenharmony_ci#endif
413d4afb5ceSopenharmony_ci
414d4afb5ceSopenharmony_ci		polmd = polmd->next;
415d4afb5ceSopenharmony_ci	}
416d4afb5ceSopenharmony_ci
417d4afb5ceSopenharmony_ci	return 0;
418d4afb5ceSopenharmony_ci}
419d4afb5ceSopenharmony_ci
420d4afb5ceSopenharmony_cistatic const uint8_t blob_idx[] = {
421d4afb5ceSopenharmony_ci	LWS_SYSBLOB_TYPE_AUTH,
422d4afb5ceSopenharmony_ci	LWS_SYSBLOB_TYPE_DEVICE_SERIAL,
423d4afb5ceSopenharmony_ci	LWS_SYSBLOB_TYPE_DEVICE_FW_VERSION,
424d4afb5ceSopenharmony_ci	LWS_SYSBLOB_TYPE_DEVICE_TYPE,
425d4afb5ceSopenharmony_ci};
426d4afb5ceSopenharmony_ci
427d4afb5ceSopenharmony_ciint
428d4afb5ceSopenharmony_cisecstream_h1(struct lws *wsi, enum lws_callback_reasons reason, void *user,
429d4afb5ceSopenharmony_ci	     void *in, size_t len)
430d4afb5ceSopenharmony_ci{
431d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
432d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
433d4afb5ceSopenharmony_ci#endif
434d4afb5ceSopenharmony_ci	lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi);
435d4afb5ceSopenharmony_ci	uint8_t buf[LWS_PRE + 1520], *p = &buf[LWS_PRE],
436d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
437d4afb5ceSopenharmony_ci			*start = p,
438d4afb5ceSopenharmony_ci#endif
439d4afb5ceSopenharmony_ci		*end = &buf[sizeof(buf) - 1];
440d4afb5ceSopenharmony_ci	lws_ss_state_return_t r;
441d4afb5ceSopenharmony_ci	int f = 0, m, status;
442d4afb5ceSopenharmony_ci	char conceal_eom = 0;
443d4afb5ceSopenharmony_ci	lws_usec_t inter;
444d4afb5ceSopenharmony_ci	size_t buflen;
445d4afb5ceSopenharmony_ci
446d4afb5ceSopenharmony_ci	switch (reason) {
447d4afb5ceSopenharmony_ci
448d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
449d4afb5ceSopenharmony_ci		if (!h) {
450d4afb5ceSopenharmony_ci			lwsl_err("%s: CCE with no ss handle %s\n", __func__, lws_wsi_tag(wsi));
451d4afb5ceSopenharmony_ci			break;
452d4afb5ceSopenharmony_ci		}
453d4afb5ceSopenharmony_ci
454d4afb5ceSopenharmony_ci		lws_ss_assert_extant(wsi->a.context, wsi->tsi, h);
455d4afb5ceSopenharmony_ci
456d4afb5ceSopenharmony_ci		assert(h->policy);
457d4afb5ceSopenharmony_ci
458d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CONMON)
459d4afb5ceSopenharmony_ci		lws_conmon_ss_json(h);
460d4afb5ceSopenharmony_ci#endif
461d4afb5ceSopenharmony_ci
462d4afb5ceSopenharmony_ci		lws_metrics_caliper_report_hist(h->cal_txn, wsi);
463d4afb5ceSopenharmony_ci		lwsl_info("%s: %s CLIENT_CONNECTION_ERROR: %s\n", __func__,
464d4afb5ceSopenharmony_ci			  h->lc.gutag, in ? (const char *)in : "none");
465d4afb5ceSopenharmony_ci		if (h->ss_dangling_connected) {
466d4afb5ceSopenharmony_ci			/* already disconnected, no action for DISCONNECT_ME */
467d4afb5ceSopenharmony_ci			r = lws_ss_event_helper(h, LWSSSCS_DISCONNECTED);
468d4afb5ceSopenharmony_ci			if (r != LWSSSSRET_OK)
469d4afb5ceSopenharmony_ci				return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
470d4afb5ceSopenharmony_ci		} else {
471d4afb5ceSopenharmony_ci			/* already disconnected, no action for DISCONNECT_ME */
472d4afb5ceSopenharmony_ci			r = lws_ss_event_helper(h, LWSSSCS_UNREACHABLE);
473d4afb5ceSopenharmony_ci			if (r) {
474d4afb5ceSopenharmony_ci				if (h->inside_connect) {
475d4afb5ceSopenharmony_ci					h->pending_ret = r;
476d4afb5ceSopenharmony_ci					break;
477d4afb5ceSopenharmony_ci				}
478d4afb5ceSopenharmony_ci
479d4afb5ceSopenharmony_ci				return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
480d4afb5ceSopenharmony_ci			}
481d4afb5ceSopenharmony_ci		}
482d4afb5ceSopenharmony_ci
483d4afb5ceSopenharmony_ci		h->wsi = NULL;
484d4afb5ceSopenharmony_ci		r = lws_ss_backoff(h);
485d4afb5ceSopenharmony_ci		if (r != LWSSSSRET_OK) {
486d4afb5ceSopenharmony_ci			if (h->inside_connect) {
487d4afb5ceSopenharmony_ci				h->pending_ret = r;
488d4afb5ceSopenharmony_ci				break;
489d4afb5ceSopenharmony_ci			}
490d4afb5ceSopenharmony_ci			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
491d4afb5ceSopenharmony_ci		}
492d4afb5ceSopenharmony_ci		break;
493d4afb5ceSopenharmony_ci
494d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLIENT_HTTP_REDIRECT:
495d4afb5ceSopenharmony_ci
496d4afb5ceSopenharmony_ci		if (!h)
497d4afb5ceSopenharmony_ci			return -1;
498d4afb5ceSopenharmony_ci
499d4afb5ceSopenharmony_ci		if (h->policy->u.http.fail_redirect)
500d4afb5ceSopenharmony_ci			lws_system_cpd_set(lws_get_context(wsi),
501d4afb5ceSopenharmony_ci					   LWS_CPD_CAPTIVE_PORTAL);
502d4afb5ceSopenharmony_ci		/* unless it's explicitly allowed, reject to follow it */
503d4afb5ceSopenharmony_ci		return !(h->policy->flags & LWSSSPOLF_ALLOW_REDIRECTS);
504d4afb5ceSopenharmony_ci
505d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLOSED_HTTP: /* server */
506d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
507d4afb5ceSopenharmony_ci		if (!h)
508d4afb5ceSopenharmony_ci			break;
509d4afb5ceSopenharmony_ci
510d4afb5ceSopenharmony_ci		lws_sul_cancel(&h->sul_timeout);
511d4afb5ceSopenharmony_ci
512d4afb5ceSopenharmony_ci		lws_ss_assert_extant(wsi->a.context, wsi->tsi, h);
513d4afb5ceSopenharmony_ci
514d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CONMON)
515d4afb5ceSopenharmony_ci		if (wsi->conmon.pcol == LWSCONMON_PCOL_NONE) {
516d4afb5ceSopenharmony_ci			wsi->conmon.pcol = LWSCONMON_PCOL_HTTP;
517d4afb5ceSopenharmony_ci			wsi->conmon.protocol_specific.http.response =
518d4afb5ceSopenharmony_ci					(int)lws_http_client_http_response(wsi);
519d4afb5ceSopenharmony_ci		}
520d4afb5ceSopenharmony_ci
521d4afb5ceSopenharmony_ci		lws_conmon_ss_json(h);
522d4afb5ceSopenharmony_ci#endif
523d4afb5ceSopenharmony_ci
524d4afb5ceSopenharmony_ci		lws_metrics_caliper_report_hist(h->cal_txn, wsi);
525d4afb5ceSopenharmony_ci		//lwsl_notice("%s: %s LWS_CALLBACK_CLOSED_CLIENT_HTTP\n",
526d4afb5ceSopenharmony_ci		//		__func__, wsi->lc.gutag);
527d4afb5ceSopenharmony_ci
528d4afb5ceSopenharmony_ci		h->wsi = NULL;
529d4afb5ceSopenharmony_ci		h->hanging_som = 0;
530d4afb5ceSopenharmony_ci		h->subseq = 0;
531d4afb5ceSopenharmony_ci
532d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
533d4afb5ceSopenharmony_ci		lws_pt_lock(pt, __func__);
534d4afb5ceSopenharmony_ci		lws_dll2_remove(&h->cli_list);
535d4afb5ceSopenharmony_ci		lws_pt_unlock(pt);
536d4afb5ceSopenharmony_ci#endif
537d4afb5ceSopenharmony_ci
538d4afb5ceSopenharmony_ci		if (h->policy && !(h->policy->flags & LWSSSPOLF_OPPORTUNISTIC) &&
539d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
540d4afb5ceSopenharmony_ci		    !(h->info.flags & LWSSSINFLAGS_ACCEPTED) && /* not server */
541d4afb5ceSopenharmony_ci#endif
542d4afb5ceSopenharmony_ci		    !h->txn_ok && !wsi->a.context->being_destroyed) {
543d4afb5ceSopenharmony_ci			r = lws_ss_backoff(h);
544d4afb5ceSopenharmony_ci			if (r != LWSSSSRET_OK)
545d4afb5ceSopenharmony_ci				return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
546d4afb5ceSopenharmony_ci			break;
547d4afb5ceSopenharmony_ci		} else
548d4afb5ceSopenharmony_ci			h->seqstate = SSSEQ_IDLE;
549d4afb5ceSopenharmony_ci
550d4afb5ceSopenharmony_ci		if (h->ss_dangling_connected) {
551d4afb5ceSopenharmony_ci			/* already disconnected, no action for DISCONNECT_ME */
552d4afb5ceSopenharmony_ci			r = lws_ss_event_helper(h, LWSSSCS_DISCONNECTED);
553d4afb5ceSopenharmony_ci			if (r != LWSSSSRET_OK)
554d4afb5ceSopenharmony_ci				return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
555d4afb5ceSopenharmony_ci		}
556d4afb5ceSopenharmony_ci		break;
557d4afb5ceSopenharmony_ci
558d4afb5ceSopenharmony_ci	case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
559d4afb5ceSopenharmony_ci
560d4afb5ceSopenharmony_ci		if (!h)
561d4afb5ceSopenharmony_ci			return -1;
562d4afb5ceSopenharmony_ci
563d4afb5ceSopenharmony_ci		lws_ss_assert_extant(wsi->a.context, wsi->tsi, h);
564d4afb5ceSopenharmony_ci		h->wsi = wsi; /* since we accept the wsi is bound to the SS,
565d4afb5ceSopenharmony_ci			       * ensure the SS feels the same way about the wsi */
566d4afb5ceSopenharmony_ci
567d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CONMON)
568d4afb5ceSopenharmony_ci		if (wsi->conmon.pcol == LWSCONMON_PCOL_NONE) {
569d4afb5ceSopenharmony_ci			wsi->conmon.pcol = LWSCONMON_PCOL_HTTP;
570d4afb5ceSopenharmony_ci			wsi->conmon.protocol_specific.http.response =
571d4afb5ceSopenharmony_ci					(int)lws_http_client_http_response(wsi);
572d4afb5ceSopenharmony_ci		}
573d4afb5ceSopenharmony_ci
574d4afb5ceSopenharmony_ci		lws_conmon_ss_json(h);
575d4afb5ceSopenharmony_ci#endif
576d4afb5ceSopenharmony_ci
577d4afb5ceSopenharmony_ci		status = (int)lws_http_client_http_response(wsi);
578d4afb5ceSopenharmony_ci		lwsl_info("%s: LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: %d\n", __func__, status);
579d4afb5ceSopenharmony_ci	//	if (!status)
580d4afb5ceSopenharmony_ci			/* it's just telling use we connected / joined the nwsi */
581d4afb5ceSopenharmony_ci	//		break;
582d4afb5ceSopenharmony_ci
583d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS)
584d4afb5ceSopenharmony_ci		if (status) {
585d4afb5ceSopenharmony_ci			lws_snprintf((char *)buf, 10, "%d", status);
586d4afb5ceSopenharmony_ci			lws_metrics_tag_ss_add(h, "http_resp", (char *)buf);
587d4afb5ceSopenharmony_ci		}
588d4afb5ceSopenharmony_ci#endif
589d4afb5ceSopenharmony_ci
590d4afb5ceSopenharmony_ci		if (status == HTTP_STATUS_SERVICE_UNAVAILABLE /* 503 */ ||
591d4afb5ceSopenharmony_ci		    status == 429 /* Too many requests */) {
592d4afb5ceSopenharmony_ci			/*
593d4afb5ceSopenharmony_ci			 * We understand this attempt failed, and that we should
594d4afb5ceSopenharmony_ci			 * conceal this attempt.  If there's a specified
595d4afb5ceSopenharmony_ci			 * retry-after, we should use that if larger than our
596d4afb5ceSopenharmony_ci			 * computed backoff
597d4afb5ceSopenharmony_ci			 */
598d4afb5ceSopenharmony_ci
599d4afb5ceSopenharmony_ci			inter = 0;
600d4afb5ceSopenharmony_ci			lws_http_check_retry_after(wsi, &inter);
601d4afb5ceSopenharmony_ci
602d4afb5ceSopenharmony_ci			r = _lws_ss_backoff(h, inter);
603d4afb5ceSopenharmony_ci			if (r != LWSSSSRET_OK)
604d4afb5ceSopenharmony_ci				return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
605d4afb5ceSopenharmony_ci
606d4afb5ceSopenharmony_ci			return -1; /* end this stream */
607d4afb5ceSopenharmony_ci		}
608d4afb5ceSopenharmony_ci
609d4afb5ceSopenharmony_ci		if (h->policy->u.http.resp_expect)
610d4afb5ceSopenharmony_ci			h->u.http.good_respcode =
611d4afb5ceSopenharmony_ci					status == h->policy->u.http.resp_expect;
612d4afb5ceSopenharmony_ci		else
613d4afb5ceSopenharmony_ci			h->u.http.good_respcode = (status >= 200 && status < 300);
614d4afb5ceSopenharmony_ci		// lwsl_err("%s: good resp %d %d\n", __func__, status, h->u.http.good_respcode);
615d4afb5ceSopenharmony_ci
616d4afb5ceSopenharmony_ci		if (lws_extract_metadata(h, wsi)) {
617d4afb5ceSopenharmony_ci			lwsl_info("%s: rx metadata extract failed\n", __func__);
618d4afb5ceSopenharmony_ci
619d4afb5ceSopenharmony_ci			return -1;
620d4afb5ceSopenharmony_ci		}
621d4afb5ceSopenharmony_ci
622d4afb5ceSopenharmony_ci		if (status) {
623d4afb5ceSopenharmony_ci			/*
624d4afb5ceSopenharmony_ci			 * Check and see if it's something from the response
625d4afb5ceSopenharmony_ci			 * map, if so, generate the requested status.  If we're
626d4afb5ceSopenharmony_ci			 * the proxy onward connection, metadata has priority
627d4afb5ceSopenharmony_ci			 * over state updates on the serialization, so the
628d4afb5ceSopenharmony_ci			 * state callback will see the right metadata.
629d4afb5ceSopenharmony_ci			 */
630d4afb5ceSopenharmony_ci			int n = lws_ss_http_resp_to_state(h, status);
631d4afb5ceSopenharmony_ci			if (n) {
632d4afb5ceSopenharmony_ci				r = lws_ss_event_helper(h, (lws_ss_constate_t)n);
633d4afb5ceSopenharmony_ci				if (r != LWSSSSRET_OK)
634d4afb5ceSopenharmony_ci					return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi,
635d4afb5ceSopenharmony_ci									&h);
636d4afb5ceSopenharmony_ci			}
637d4afb5ceSopenharmony_ci		}
638d4afb5ceSopenharmony_ci
639d4afb5ceSopenharmony_ci		if (h->u.http.good_respcode)
640d4afb5ceSopenharmony_ci			lwsl_info("%s: Connected streamtype %s, %d\n", __func__,
641d4afb5ceSopenharmony_ci				  h->policy->streamtype, status);
642d4afb5ceSopenharmony_ci		else
643d4afb5ceSopenharmony_ci			if (h->u.http.good_respcode)
644d4afb5ceSopenharmony_ci				lwsl_warn("%s: Connected streamtype %s, BAD %d\n",
645d4afb5ceSopenharmony_ci					  __func__, h->policy->streamtype,
646d4afb5ceSopenharmony_ci					  status);
647d4afb5ceSopenharmony_ci
648d4afb5ceSopenharmony_ci		h->hanging_som = 0;
649d4afb5ceSopenharmony_ci
650d4afb5ceSopenharmony_ci		h->retry = 0;
651d4afb5ceSopenharmony_ci		h->seqstate = SSSEQ_CONNECTED;
652d4afb5ceSopenharmony_ci		lws_sul_cancel(&h->sul);
653d4afb5ceSopenharmony_ci
654d4afb5ceSopenharmony_ci		if (h->prev_ss_state != LWSSSCS_CONNECTED) {
655d4afb5ceSopenharmony_ci			wsi->client_suppress_CONNECTION_ERROR = 1;
656d4afb5ceSopenharmony_ci			if (h->prev_ss_state != LWSSSCS_CONNECTED) {
657d4afb5ceSopenharmony_ci				r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
658d4afb5ceSopenharmony_ci				if (r != LWSSSSRET_OK)
659d4afb5ceSopenharmony_ci					return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
660d4afb5ceSopenharmony_ci			}
661d4afb5ceSopenharmony_ci		}
662d4afb5ceSopenharmony_ci
663d4afb5ceSopenharmony_ci		/*
664d4afb5ceSopenharmony_ci		 * Since it's an http transaction we initiated... this is
665d4afb5ceSopenharmony_ci		 * proof of connection validity
666d4afb5ceSopenharmony_ci		 */
667d4afb5ceSopenharmony_ci		lws_validity_confirmed(wsi);
668d4afb5ceSopenharmony_ci
669d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SS_RIDESHARE)
670d4afb5ceSopenharmony_ci
671d4afb5ceSopenharmony_ci		/*
672d4afb5ceSopenharmony_ci		 * There are two ways we might want to deal with multipart,
673d4afb5ceSopenharmony_ci		 * one is pass it through raw (although the user code needs
674d4afb5ceSopenharmony_ci		 * a helping hand for learning the boundary), and the other
675d4afb5ceSopenharmony_ci		 * is to deframe it and provide basically submessages in the
676d4afb5ceSopenharmony_ci		 * different parts.
677d4afb5ceSopenharmony_ci		 */
678d4afb5ceSopenharmony_ci
679d4afb5ceSopenharmony_ci		if (lws_hdr_copy(wsi, (char *)buf, sizeof(buf),
680d4afb5ceSopenharmony_ci				 WSI_TOKEN_HTTP_CONTENT_TYPE) > 0 &&
681d4afb5ceSopenharmony_ci		/* multipart/form-data;
682d4afb5ceSopenharmony_ci		 * boundary=----WebKitFormBoundarycc7YgAPEIHvgE9Bf */
683d4afb5ceSopenharmony_ci
684d4afb5ceSopenharmony_ci		    (!strncmp((char *)buf, "multipart/form-data", 19) ||
685d4afb5ceSopenharmony_ci		     !strncmp((char *)buf, "multipart/related", 17))) {
686d4afb5ceSopenharmony_ci			struct lws_tokenize ts;
687d4afb5ceSopenharmony_ci			lws_tokenize_elem e;
688d4afb5ceSopenharmony_ci
689d4afb5ceSopenharmony_ci			// puts((const char *)buf);
690d4afb5ceSopenharmony_ci
691d4afb5ceSopenharmony_ci			memset(&ts, 0, sizeof(ts));
692d4afb5ceSopenharmony_ci			ts.start = (char *)buf;
693d4afb5ceSopenharmony_ci			ts.len = strlen(ts.start);
694d4afb5ceSopenharmony_ci			ts.flags = LWS_TOKENIZE_F_RFC7230_DELIMS |
695d4afb5ceSopenharmony_ci					LWS_TOKENIZE_F_SLASH_NONTERM |
696d4afb5ceSopenharmony_ci					LWS_TOKENIZE_F_MINUS_NONTERM;
697d4afb5ceSopenharmony_ci
698d4afb5ceSopenharmony_ci			h->u.http.boundary[0] = '\0';
699d4afb5ceSopenharmony_ci			do {
700d4afb5ceSopenharmony_ci				e = lws_tokenize(&ts);
701d4afb5ceSopenharmony_ci				if (e == LWS_TOKZE_TOKEN_NAME_EQUALS &&
702d4afb5ceSopenharmony_ci				    !strncmp(ts.token, "boundary", 8) &&
703d4afb5ceSopenharmony_ci				    ts.token_len == 8) {
704d4afb5ceSopenharmony_ci					e = lws_tokenize(&ts);
705d4afb5ceSopenharmony_ci					if (e != LWS_TOKZE_TOKEN)
706d4afb5ceSopenharmony_ci						goto malformed;
707d4afb5ceSopenharmony_ci					h->u.http.boundary[0] = '\x0d';
708d4afb5ceSopenharmony_ci					h->u.http.boundary[1] = '\x0a';
709d4afb5ceSopenharmony_ci					h->u.http.boundary[2] = '-';
710d4afb5ceSopenharmony_ci					h->u.http.boundary[3] = '-';
711d4afb5ceSopenharmony_ci					lws_strnncpy(h->u.http.boundary + 4,
712d4afb5ceSopenharmony_ci						     ts.token, ts.token_len,
713d4afb5ceSopenharmony_ci						     sizeof(h->u.http.boundary) - 4);
714d4afb5ceSopenharmony_ci					h->u.http.boundary_len =
715d4afb5ceSopenharmony_ci						(uint8_t)(ts.token_len + 4);
716d4afb5ceSopenharmony_ci					h->u.http.boundary_seq = 2;
717d4afb5ceSopenharmony_ci					h->u.http.boundary_dashes = 0;
718d4afb5ceSopenharmony_ci				}
719d4afb5ceSopenharmony_ci			} while (e > 0);
720d4afb5ceSopenharmony_ci			lwsl_info("%s: multipart boundary '%s' len %d\n", __func__,
721d4afb5ceSopenharmony_ci					h->u.http.boundary, h->u.http.boundary_len);
722d4afb5ceSopenharmony_ci
723d4afb5ceSopenharmony_ci			/* inform the ss that a related message group begins */
724d4afb5ceSopenharmony_ci
725d4afb5ceSopenharmony_ci			if ((h->policy->flags & LWSSSPOLF_HTTP_MULTIPART_IN) &&
726d4afb5ceSopenharmony_ci			    h->u.http.boundary[0])
727d4afb5ceSopenharmony_ci				h->info.rx(ss_to_userobj(h), NULL, 0,
728d4afb5ceSopenharmony_ci					   LWSSS_FLAG_RELATED_START);
729d4afb5ceSopenharmony_ci
730d4afb5ceSopenharmony_ci			// lws_header_table_detach(wsi, 0);
731d4afb5ceSopenharmony_ci		}
732d4afb5ceSopenharmony_ci		break;
733d4afb5ceSopenharmony_cimalformed:
734d4afb5ceSopenharmony_ci		lwsl_notice("%s: malformed multipart header\n", __func__);
735d4afb5ceSopenharmony_ci		return -1;
736d4afb5ceSopenharmony_ci#else
737d4afb5ceSopenharmony_ci		break;
738d4afb5ceSopenharmony_ci#endif
739d4afb5ceSopenharmony_ci
740d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
741d4afb5ceSopenharmony_ci		if (!h)
742d4afb5ceSopenharmony_ci			return -1;
743d4afb5ceSopenharmony_ci		if (h->writeable_len)
744d4afb5ceSopenharmony_ci			wsi->http.writeable_len = h->writeable_len;
745d4afb5ceSopenharmony_ci
746d4afb5ceSopenharmony_ci		{
747d4afb5ceSopenharmony_ci			uint8_t **p = (uint8_t **)in, *end = (*p) + len,
748d4afb5ceSopenharmony_ci				*oin = *(uint8_t **)in;
749d4afb5ceSopenharmony_ci
750d4afb5ceSopenharmony_ci		/*
751d4afb5ceSopenharmony_ci		 * blob-based headers
752d4afb5ceSopenharmony_ci		 */
753d4afb5ceSopenharmony_ci
754d4afb5ceSopenharmony_ci		for (m = 0; m < _LWSSS_HBI_COUNT; m++) {
755d4afb5ceSopenharmony_ci			lws_system_blob_t *ab;
756d4afb5ceSopenharmony_ci			int o = 0, n;
757d4afb5ceSopenharmony_ci
758d4afb5ceSopenharmony_ci			if (!h->policy->u.http.blob_header[m])
759d4afb5ceSopenharmony_ci				continue;
760d4afb5ceSopenharmony_ci
761d4afb5ceSopenharmony_ci			/*
762d4afb5ceSopenharmony_ci			 * To be backward compatible, default is system-wide LWA auth,
763d4afb5ceSopenharmony_ci			 * and "http_auth_header" is for default LWA auth, current users do not
764d4afb5ceSopenharmony_ci			 * need any change in their policy.
765d4afb5ceSopenharmony_ci			 * If user wants different auth/token, need to specify the "use_auth"
766d4afb5ceSopenharmony_ci			 * and will be handled after metadata headers are applied.
767d4afb5ceSopenharmony_ci			 */
768d4afb5ceSopenharmony_ci
769d4afb5ceSopenharmony_ci			if (m == LWSSS_HBI_AUTH &&
770d4afb5ceSopenharmony_ci			    h->policy->u.http.auth_preamble)
771d4afb5ceSopenharmony_ci				o = lws_snprintf((char *)buf, sizeof(buf), "%s",
772d4afb5ceSopenharmony_ci					h->policy->u.http.auth_preamble);
773d4afb5ceSopenharmony_ci
774d4afb5ceSopenharmony_ci			if (o > (int)sizeof(buf) - 2)
775d4afb5ceSopenharmony_ci				return -1;
776d4afb5ceSopenharmony_ci
777d4afb5ceSopenharmony_ci			ab = lws_system_get_blob(wsi->a.context, blob_idx[m], 0);
778d4afb5ceSopenharmony_ci			if (!ab)
779d4afb5ceSopenharmony_ci				return -1;
780d4afb5ceSopenharmony_ci
781d4afb5ceSopenharmony_ci			buflen = sizeof(buf) - (unsigned int)o - 2u;
782d4afb5ceSopenharmony_ci			n = lws_system_blob_get(ab, buf + o, &buflen, 0);
783d4afb5ceSopenharmony_ci			if (n < 0)
784d4afb5ceSopenharmony_ci				return -1;
785d4afb5ceSopenharmony_ci
786d4afb5ceSopenharmony_ci			buf[(unsigned int)o + buflen] = '\0';
787d4afb5ceSopenharmony_ci			lwsl_debug("%s: adding blob %d: %s\n", __func__, m, buf);
788d4afb5ceSopenharmony_ci
789d4afb5ceSopenharmony_ci			if (lws_add_http_header_by_name(wsi,
790d4afb5ceSopenharmony_ci				 (uint8_t *)h->policy->u.http.blob_header[m],
791d4afb5ceSopenharmony_ci				 buf, (int)((int)buflen + o), p, end))
792d4afb5ceSopenharmony_ci				return -1;
793d4afb5ceSopenharmony_ci		}
794d4afb5ceSopenharmony_ci
795d4afb5ceSopenharmony_ci		/*
796d4afb5ceSopenharmony_ci		 * metadata-based headers
797d4afb5ceSopenharmony_ci		 */
798d4afb5ceSopenharmony_ci
799d4afb5ceSopenharmony_ci		if (lws_apply_metadata(h, wsi, buf, p, end))
800d4afb5ceSopenharmony_ci			return -1;
801d4afb5ceSopenharmony_ci
802d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
803d4afb5ceSopenharmony_ci		if (h->policy->flags & LWSSSPOLF_DIRECT_PROTO_STR) {
804d4afb5ceSopenharmony_ci			if (lws_apply_instant_metadata(h, wsi, buf, p, end))
805d4afb5ceSopenharmony_ci				return -1;
806d4afb5ceSopenharmony_ci		}
807d4afb5ceSopenharmony_ci#endif
808d4afb5ceSopenharmony_ci
809d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
810d4afb5ceSopenharmony_ci		if (h->policy->auth && h->policy->auth->type &&
811d4afb5ceSopenharmony_ci				!strcmp(h->policy->auth->type, "sigv4")) {
812d4afb5ceSopenharmony_ci
813d4afb5ceSopenharmony_ci			if (lws_ss_apply_sigv4(wsi, h, p, end))
814d4afb5ceSopenharmony_ci				return -1;
815d4afb5ceSopenharmony_ci		}
816d4afb5ceSopenharmony_ci#endif
817d4afb5ceSopenharmony_ci
818d4afb5ceSopenharmony_ci
819d4afb5ceSopenharmony_ci		(void)oin;
820d4afb5ceSopenharmony_ci		//if (*p != oin)
821d4afb5ceSopenharmony_ci		//	lwsl_hexdump_notice(oin, lws_ptr_diff_size_t(*p, oin));
822d4afb5ceSopenharmony_ci
823d4afb5ceSopenharmony_ci		}
824d4afb5ceSopenharmony_ci
825d4afb5ceSopenharmony_ci		/*
826d4afb5ceSopenharmony_ci		 * So when proxied, for POST we have to synthesize a CONNECTED
827d4afb5ceSopenharmony_ci		 * state, so it can request a writeable and deliver the POST
828d4afb5ceSopenharmony_ci		 * body
829d4afb5ceSopenharmony_ci		 */
830d4afb5ceSopenharmony_ci		if ((h->policy->protocol == LWSSSP_H1 ||
831d4afb5ceSopenharmony_ci		     h->policy->protocol == LWSSSP_H2) &&
832d4afb5ceSopenharmony_ci		     h->being_serialized && (
833d4afb5ceSopenharmony_ci				!strcmp(h->policy->u.http.method, "PUT") ||
834d4afb5ceSopenharmony_ci				!strcmp(h->policy->u.http.method, "PATCH") ||
835d4afb5ceSopenharmony_ci				!strcmp(h->policy->u.http.method, "POST"))) {
836d4afb5ceSopenharmony_ci
837d4afb5ceSopenharmony_ci			wsi->client_suppress_CONNECTION_ERROR = 1;
838d4afb5ceSopenharmony_ci			if (h->prev_ss_state != LWSSSCS_CONNECTED) {
839d4afb5ceSopenharmony_ci				r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
840d4afb5ceSopenharmony_ci				if (r)
841d4afb5ceSopenharmony_ci					return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
842d4afb5ceSopenharmony_ci			}
843d4afb5ceSopenharmony_ci		}
844d4afb5ceSopenharmony_ci
845d4afb5ceSopenharmony_ci		break;
846d4afb5ceSopenharmony_ci
847d4afb5ceSopenharmony_ci	/* chunks of chunked content, with header removed */
848d4afb5ceSopenharmony_ci	case LWS_CALLBACK_HTTP_BODY:
849d4afb5ceSopenharmony_ci	case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
850d4afb5ceSopenharmony_ci		lwsl_debug("%s: RECEIVE_CLIENT_HTTP_READ: read %d\n",
851d4afb5ceSopenharmony_ci				__func__, (int)len);
852d4afb5ceSopenharmony_ci		if (!h || !h->info.rx)
853d4afb5ceSopenharmony_ci			return 0;
854d4afb5ceSopenharmony_ci
855d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SS_RIDESHARE)
856d4afb5ceSopenharmony_ci		if ((h->policy->flags & LWSSSPOLF_HTTP_MULTIPART_IN) &&
857d4afb5ceSopenharmony_ci		    h->u.http.boundary[0])
858d4afb5ceSopenharmony_ci			return ss_http_multipart_parser(h, in, len);
859d4afb5ceSopenharmony_ci#endif
860d4afb5ceSopenharmony_ci
861d4afb5ceSopenharmony_ci		if (!h->subseq) {
862d4afb5ceSopenharmony_ci			f |= LWSSS_FLAG_SOM;
863d4afb5ceSopenharmony_ci			h->hanging_som = 1;
864d4afb5ceSopenharmony_ci			h->subseq = 1;
865d4afb5ceSopenharmony_ci		}
866d4afb5ceSopenharmony_ci
867d4afb5ceSopenharmony_ci	//	lwsl_notice("%s: HTTP_READ: client side sent len %d fl 0x%x\n",
868d4afb5ceSopenharmony_ci	//		    __func__, (int)len, (int)f);
869d4afb5ceSopenharmony_ci
870d4afb5ceSopenharmony_ci		h->wsi = wsi; /* since we accept the wsi is bound to the SS,
871d4afb5ceSopenharmony_ci			       * ensure the SS feels the same way about the wsi */
872d4afb5ceSopenharmony_ci		r = h->info.rx(ss_to_userobj(h), (const uint8_t *)in, len, f);
873d4afb5ceSopenharmony_ci		if (r != LWSSSSRET_OK)
874d4afb5ceSopenharmony_ci			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
875d4afb5ceSopenharmony_ci
876d4afb5ceSopenharmony_ci		return 0; /* don't passthru */
877d4afb5ceSopenharmony_ci
878d4afb5ceSopenharmony_ci	/* uninterpreted http content */
879d4afb5ceSopenharmony_ci	case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
880d4afb5ceSopenharmony_ci		{
881d4afb5ceSopenharmony_ci			char *px = (char *)buf + LWS_PRE; /* guarantees LWS_PRE */
882d4afb5ceSopenharmony_ci			int lenx = sizeof(buf) - LWS_PRE;
883d4afb5ceSopenharmony_ci
884d4afb5ceSopenharmony_ci			m = lws_http_client_read(wsi, &px, &lenx);
885d4afb5ceSopenharmony_ci			if (m < 0)
886d4afb5ceSopenharmony_ci				return m;
887d4afb5ceSopenharmony_ci		}
888d4afb5ceSopenharmony_ci		lws_set_timeout(wsi, 99, 30);
889d4afb5ceSopenharmony_ci
890d4afb5ceSopenharmony_ci		return 0; /* don't passthru */
891d4afb5ceSopenharmony_ci
892d4afb5ceSopenharmony_ci	case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
893d4afb5ceSopenharmony_ci		// lwsl_debug("%s: LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n", __func__);
894d4afb5ceSopenharmony_ci
895d4afb5ceSopenharmony_ci		if (!h)
896d4afb5ceSopenharmony_ci			return -1;
897d4afb5ceSopenharmony_ci
898d4afb5ceSopenharmony_ci		if (h->hanging_som) {
899d4afb5ceSopenharmony_ci			h->info.rx(ss_to_userobj(h), NULL, 0, LWSSS_FLAG_EOM);
900d4afb5ceSopenharmony_ci			h->hanging_som = 0;
901d4afb5ceSopenharmony_ci			h->subseq = 0;
902d4afb5ceSopenharmony_ci		}
903d4afb5ceSopenharmony_ci
904d4afb5ceSopenharmony_ci		wsi->http.writeable_len = h->writeable_len = 0;
905d4afb5ceSopenharmony_ci		lws_sul_cancel(&h->sul_timeout);
906d4afb5ceSopenharmony_ci
907d4afb5ceSopenharmony_ci		h->txn_ok = 1;
908d4afb5ceSopenharmony_ci
909d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS)
910d4afb5ceSopenharmony_ci		lws_metrics_tag_ss_add(h, "result",
911d4afb5ceSopenharmony_ci				       h->u.http.good_respcode ?
912d4afb5ceSopenharmony_ci				       "SS_ACK_REMOTE" : "SS_NACK_REMOTE");
913d4afb5ceSopenharmony_ci#endif
914d4afb5ceSopenharmony_ci
915d4afb5ceSopenharmony_ci		r = lws_ss_event_helper(h, h->u.http.good_respcode ?
916d4afb5ceSopenharmony_ci						LWSSSCS_QOS_ACK_REMOTE :
917d4afb5ceSopenharmony_ci						LWSSSCS_QOS_NACK_REMOTE);
918d4afb5ceSopenharmony_ci		if (r != LWSSSSRET_OK)
919d4afb5ceSopenharmony_ci			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
920d4afb5ceSopenharmony_ci
921d4afb5ceSopenharmony_ci		lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
922d4afb5ceSopenharmony_ci		break;
923d4afb5ceSopenharmony_ci
924d4afb5ceSopenharmony_ci	case LWS_CALLBACK_HTTP_WRITEABLE:
925d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLIENT_HTTP_WRITEABLE:
926d4afb5ceSopenharmony_ci
927d4afb5ceSopenharmony_ci		if (!h || !h->info.tx) {
928d4afb5ceSopenharmony_ci			lwsl_notice("%s: no handle / tx\n", __func__);
929d4afb5ceSopenharmony_ci			return 0;
930d4afb5ceSopenharmony_ci		}
931d4afb5ceSopenharmony_ci
932d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
933d4afb5ceSopenharmony_ci		if (h->txn_resp_pending) {
934d4afb5ceSopenharmony_ci			/*
935d4afb5ceSopenharmony_ci			 * If we're going to start sending something, we need to
936d4afb5ceSopenharmony_ci			 * to take care of the http response header for it first
937d4afb5ceSopenharmony_ci			 */
938d4afb5ceSopenharmony_ci			h->txn_resp_pending = 0;
939d4afb5ceSopenharmony_ci
940d4afb5ceSopenharmony_ci			if (lws_add_http_common_headers(wsi,
941d4afb5ceSopenharmony_ci					(unsigned int)(h->txn_resp_set ?
942d4afb5ceSopenharmony_ci						(h->txn_resp ? h->txn_resp : 200) :
943d4afb5ceSopenharmony_ci						HTTP_STATUS_NOT_FOUND),
944d4afb5ceSopenharmony_ci					NULL, h->wsi->http.writeable_len,
945d4afb5ceSopenharmony_ci					&p, end))
946d4afb5ceSopenharmony_ci				return 1;
947d4afb5ceSopenharmony_ci
948d4afb5ceSopenharmony_ci			/*
949d4afb5ceSopenharmony_ci			 * metadata-based headers
950d4afb5ceSopenharmony_ci			 */
951d4afb5ceSopenharmony_ci
952d4afb5ceSopenharmony_ci			if (lws_apply_metadata(h, wsi, buf, &p, end))
953d4afb5ceSopenharmony_ci				return -1;
954d4afb5ceSopenharmony_ci
955d4afb5ceSopenharmony_ci			if (lws_finalize_write_http_header(wsi, start, &p, end))
956d4afb5ceSopenharmony_ci				return 1;
957d4afb5ceSopenharmony_ci
958d4afb5ceSopenharmony_ci			/* write the body separately */
959d4afb5ceSopenharmony_ci			lws_callback_on_writable(wsi);
960d4afb5ceSopenharmony_ci
961d4afb5ceSopenharmony_ci			return 0;
962d4afb5ceSopenharmony_ci		}
963d4afb5ceSopenharmony_ci#endif
964d4afb5ceSopenharmony_ci
965d4afb5ceSopenharmony_ci		if (
966d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
967d4afb5ceSopenharmony_ci		    !(h->info.flags & LWSSSINFLAGS_ACCEPTED) && /* not accepted */
968d4afb5ceSopenharmony_ci#endif
969d4afb5ceSopenharmony_ci		    !h->rideshare)
970d4afb5ceSopenharmony_ci
971d4afb5ceSopenharmony_ci			h->rideshare = h->policy;
972d4afb5ceSopenharmony_ci
973d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SS_RIDESHARE)
974d4afb5ceSopenharmony_ci		if (
975d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
976d4afb5ceSopenharmony_ci		    !(h->info.flags & LWSSSINFLAGS_ACCEPTED) && /* not accepted */
977d4afb5ceSopenharmony_ci#endif
978d4afb5ceSopenharmony_ci		    !h->inside_msg && h->rideshare->u.http.multipart_name)
979d4afb5ceSopenharmony_ci			lws_client_http_multipart(wsi,
980d4afb5ceSopenharmony_ci				h->rideshare->u.http.multipart_name,
981d4afb5ceSopenharmony_ci				h->rideshare->u.http.multipart_filename,
982d4afb5ceSopenharmony_ci				h->rideshare->u.http.multipart_content_type,
983d4afb5ceSopenharmony_ci				(char **)&p, (char *)end);
984d4afb5ceSopenharmony_ci
985d4afb5ceSopenharmony_ci		buflen = lws_ptr_diff_size_t(end, p);
986d4afb5ceSopenharmony_ci		if (h->policy->u.http.multipart_name)
987d4afb5ceSopenharmony_ci			buflen -= 24; /* allow space for end of multipart */
988d4afb5ceSopenharmony_ci#else
989d4afb5ceSopenharmony_ci		buflen = lws_ptr_diff_size_t(end, p);
990d4afb5ceSopenharmony_ci#endif
991d4afb5ceSopenharmony_ci		r = h->info.tx(ss_to_userobj(h), h->txord++, p, &buflen, &f);
992d4afb5ceSopenharmony_ci		if (r == LWSSSSRET_TX_DONT_SEND)
993d4afb5ceSopenharmony_ci			return 0;
994d4afb5ceSopenharmony_ci		if (r < 0)
995d4afb5ceSopenharmony_ci			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
996d4afb5ceSopenharmony_ci
997d4afb5ceSopenharmony_ci		// lwsl_notice("%s: WRITEABLE: user tx says len %d fl 0x%x\n",
998d4afb5ceSopenharmony_ci		//	    __func__, (int)buflen, (int)f);
999d4afb5ceSopenharmony_ci
1000d4afb5ceSopenharmony_ci		p += buflen;
1001d4afb5ceSopenharmony_ci
1002d4afb5ceSopenharmony_ci		if (f & LWSSS_FLAG_EOM) {
1003d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
1004d4afb5ceSopenharmony_ci		    if (!(h->info.flags & LWSSSINFLAGS_ACCEPTED)) {
1005d4afb5ceSopenharmony_ci#endif
1006d4afb5ceSopenharmony_ci			conceal_eom = 1;
1007d4afb5ceSopenharmony_ci			/* end of rideshares */
1008d4afb5ceSopenharmony_ci			if (!h->rideshare->rideshare_streamtype) {
1009d4afb5ceSopenharmony_ci				lws_client_http_body_pending(wsi, 0);
1010d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SS_RIDESHARE)
1011d4afb5ceSopenharmony_ci				if (h->rideshare->u.http.multipart_name)
1012d4afb5ceSopenharmony_ci					lws_client_http_multipart(wsi, NULL, NULL, NULL,
1013d4afb5ceSopenharmony_ci						(char **)&p, (char *)end);
1014d4afb5ceSopenharmony_ci				conceal_eom = 0;
1015d4afb5ceSopenharmony_ci#endif
1016d4afb5ceSopenharmony_ci			} else {
1017d4afb5ceSopenharmony_ci				h->rideshare = lws_ss_policy_lookup(wsi->a.context,
1018d4afb5ceSopenharmony_ci						h->rideshare->rideshare_streamtype);
1019d4afb5ceSopenharmony_ci				lws_callback_on_writable(wsi);
1020d4afb5ceSopenharmony_ci			}
1021d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
1022d4afb5ceSopenharmony_ci		    }
1023d4afb5ceSopenharmony_ci#endif
1024d4afb5ceSopenharmony_ci
1025d4afb5ceSopenharmony_ci			h->inside_msg = 0;
1026d4afb5ceSopenharmony_ci		} else {
1027d4afb5ceSopenharmony_ci			/* otherwise we can spin with zero length writes */
1028d4afb5ceSopenharmony_ci			if (!f && !lws_ptr_diff(p, buf + LWS_PRE))
1029d4afb5ceSopenharmony_ci				break;
1030d4afb5ceSopenharmony_ci			h->inside_msg = 1;
1031d4afb5ceSopenharmony_ci			lws_callback_on_writable(wsi);
1032d4afb5ceSopenharmony_ci		}
1033d4afb5ceSopenharmony_ci
1034d4afb5ceSopenharmony_ci		lwsl_info("%s: lws_write %d %d\n", __func__,
1035d4afb5ceSopenharmony_ci			  lws_ptr_diff(p, buf + LWS_PRE), f);
1036d4afb5ceSopenharmony_ci
1037d4afb5ceSopenharmony_ci		if (lws_write(wsi, buf + LWS_PRE, lws_ptr_diff_size_t(p, buf + LWS_PRE),
1038d4afb5ceSopenharmony_ci			 (!conceal_eom && (f & LWSSS_FLAG_EOM)) ?
1039d4afb5ceSopenharmony_ci				    LWS_WRITE_HTTP_FINAL : LWS_WRITE_HTTP) !=
1040d4afb5ceSopenharmony_ci				(int)lws_ptr_diff(p, buf + LWS_PRE)) {
1041d4afb5ceSopenharmony_ci			lwsl_err("%s: write failed\n", __func__);
1042d4afb5ceSopenharmony_ci			return -1;
1043d4afb5ceSopenharmony_ci		}
1044d4afb5ceSopenharmony_ci
1045d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
1046d4afb5ceSopenharmony_ci		if ((h->info.flags & LWSSSINFLAGS_ACCEPTED) /* server */ &&
1047d4afb5ceSopenharmony_ci		    (f & LWSSS_FLAG_EOM) &&
1048d4afb5ceSopenharmony_ci		     lws_http_transaction_completed(wsi))
1049d4afb5ceSopenharmony_ci			return -1;
1050d4afb5ceSopenharmony_ci#else
1051d4afb5ceSopenharmony_ci		lws_set_timeout(wsi, 0, 0);
1052d4afb5ceSopenharmony_ci#endif
1053d4afb5ceSopenharmony_ci		break;
1054d4afb5ceSopenharmony_ci
1055d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
1056d4afb5ceSopenharmony_ci	case LWS_CALLBACK_HTTP:
1057d4afb5ceSopenharmony_ci
1058d4afb5ceSopenharmony_ci		if (!h)
1059d4afb5ceSopenharmony_ci			return -1;
1060d4afb5ceSopenharmony_ci
1061d4afb5ceSopenharmony_ci		lwsl_info("%s: LWS_CALLBACK_HTTP\n", __func__);
1062d4afb5ceSopenharmony_ci		{
1063d4afb5ceSopenharmony_ci
1064d4afb5ceSopenharmony_ci			h->txn_resp_set = 0;
1065d4afb5ceSopenharmony_ci			h->txn_resp_pending = 1;
1066d4afb5ceSopenharmony_ci			h->writeable_len = 0;
1067d4afb5ceSopenharmony_ci
1068d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2)
1069d4afb5ceSopenharmony_ci			m = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_METHOD);
1070d4afb5ceSopenharmony_ci			if (m) {
1071d4afb5ceSopenharmony_ci				if (lws_ss_alloc_set_metadata(h, "method",
1072d4afb5ceSopenharmony_ci						    lws_hdr_simple_ptr(wsi,
1073d4afb5ceSopenharmony_ci						     WSI_TOKEN_HTTP_COLON_METHOD), (unsigned int)m))
1074d4afb5ceSopenharmony_ci					return -1;
1075d4afb5ceSopenharmony_ci				m = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH);
1076d4afb5ceSopenharmony_ci				if (m && lws_ss_alloc_set_metadata(h, "path",
1077d4afb5ceSopenharmony_ci						    lws_hdr_simple_ptr(wsi,
1078d4afb5ceSopenharmony_ci						     WSI_TOKEN_HTTP_COLON_PATH), (unsigned int)m))
1079d4afb5ceSopenharmony_ci					return -1;
1080d4afb5ceSopenharmony_ci			} else
1081d4afb5ceSopenharmony_ci#endif
1082d4afb5ceSopenharmony_ci			{
1083d4afb5ceSopenharmony_ci				m = lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI);
1084d4afb5ceSopenharmony_ci				if (m) {
1085d4afb5ceSopenharmony_ci					if (lws_ss_alloc_set_metadata(h, "path",
1086d4afb5ceSopenharmony_ci							lws_hdr_simple_ptr(wsi,
1087d4afb5ceSopenharmony_ci								WSI_TOKEN_GET_URI), (unsigned int)m))
1088d4afb5ceSopenharmony_ci						return -1;
1089d4afb5ceSopenharmony_ci					if (lws_ss_alloc_set_metadata(h, "method", "GET", 3))
1090d4afb5ceSopenharmony_ci						return -1;
1091d4afb5ceSopenharmony_ci				} else {
1092d4afb5ceSopenharmony_ci					m = lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI);
1093d4afb5ceSopenharmony_ci					if (m) {
1094d4afb5ceSopenharmony_ci						if (lws_ss_alloc_set_metadata(h, "path",
1095d4afb5ceSopenharmony_ci								lws_hdr_simple_ptr(wsi,
1096d4afb5ceSopenharmony_ci									WSI_TOKEN_POST_URI), (unsigned int)m))
1097d4afb5ceSopenharmony_ci							return -1;
1098d4afb5ceSopenharmony_ci						if (lws_ss_alloc_set_metadata(h, "method", "POST", 4))
1099d4afb5ceSopenharmony_ci							return -1;
1100d4afb5ceSopenharmony_ci					} else {
1101d4afb5ceSopenharmony_ci						m = lws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI);
1102d4afb5ceSopenharmony_ci						if (m) {
1103d4afb5ceSopenharmony_ci							if (lws_ss_alloc_set_metadata(h, "path",
1104d4afb5ceSopenharmony_ci									lws_hdr_simple_ptr(wsi,
1105d4afb5ceSopenharmony_ci										WSI_TOKEN_PATCH_URI), (unsigned int)m))
1106d4afb5ceSopenharmony_ci								return -1;
1107d4afb5ceSopenharmony_ci							if (lws_ss_alloc_set_metadata(h, "method", "PATCH", 5))
1108d4afb5ceSopenharmony_ci								return -1;
1109d4afb5ceSopenharmony_ci						}
1110d4afb5ceSopenharmony_ci					}
1111d4afb5ceSopenharmony_ci				}
1112d4afb5ceSopenharmony_ci			}
1113d4afb5ceSopenharmony_ci		}
1114d4afb5ceSopenharmony_ci
1115d4afb5ceSopenharmony_ci		if (!h->ss_dangling_connected) {
1116d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS)
1117d4afb5ceSopenharmony_ci			/*
1118d4afb5ceSopenharmony_ci			 * If any hanging caliper measurement, dump it, and free any tags
1119d4afb5ceSopenharmony_ci			 */
1120d4afb5ceSopenharmony_ci			lws_metrics_caliper_report_hist(h->cal_txn, (struct lws *)NULL);
1121d4afb5ceSopenharmony_ci#endif
1122d4afb5ceSopenharmony_ci			wsi->client_suppress_CONNECTION_ERROR = 1;
1123d4afb5ceSopenharmony_ci			if (h->prev_ss_state != LWSSSCS_CONNECTED) {
1124d4afb5ceSopenharmony_ci				r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
1125d4afb5ceSopenharmony_ci				if (r)
1126d4afb5ceSopenharmony_ci					return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
1127d4afb5ceSopenharmony_ci			}
1128d4afb5ceSopenharmony_ci		}
1129d4afb5ceSopenharmony_ci
1130d4afb5ceSopenharmony_ci		r = lws_ss_event_helper(h, LWSSSCS_SERVER_TXN);
1131d4afb5ceSopenharmony_ci		if (r)
1132d4afb5ceSopenharmony_ci			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r,
1133d4afb5ceSopenharmony_ci								wsi, &h);
1134d4afb5ceSopenharmony_ci
1135d4afb5ceSopenharmony_ci		return 0;
1136d4afb5ceSopenharmony_ci#endif
1137d4afb5ceSopenharmony_ci
1138d4afb5ceSopenharmony_ci	default:
1139d4afb5ceSopenharmony_ci		break;
1140d4afb5ceSopenharmony_ci	}
1141d4afb5ceSopenharmony_ci
1142d4afb5ceSopenharmony_ci	return lws_callback_http_dummy(wsi, reason, user, in, len);
1143d4afb5ceSopenharmony_ci}
1144d4afb5ceSopenharmony_ci
1145d4afb5ceSopenharmony_ciconst struct lws_protocols protocol_secstream_h1 = {
1146d4afb5ceSopenharmony_ci	"lws-secstream-h1",
1147d4afb5ceSopenharmony_ci	secstream_h1,
1148d4afb5ceSopenharmony_ci	0, 0, 0, NULL, 0
1149d4afb5ceSopenharmony_ci};
1150d4afb5ceSopenharmony_ci
1151d4afb5ceSopenharmony_ci/*
1152d4afb5ceSopenharmony_ci * Munge connect info according to protocol-specific considerations... this
1153d4afb5ceSopenharmony_ci * usually means interpreting aux in a protocol-specific way and using the
1154d4afb5ceSopenharmony_ci * pieces at connection setup time, eg, http url pieces.
1155d4afb5ceSopenharmony_ci *
1156d4afb5ceSopenharmony_ci * len bytes of buf can be used for things with scope until after the actual
1157d4afb5ceSopenharmony_ci * connect.
1158d4afb5ceSopenharmony_ci */
1159d4afb5ceSopenharmony_ci
1160d4afb5ceSopenharmony_cistatic int
1161d4afb5ceSopenharmony_cisecstream_connect_munge_h1(lws_ss_handle_t *h, char *buf, size_t len,
1162d4afb5ceSopenharmony_ci			   struct lws_client_connect_info *i,
1163d4afb5ceSopenharmony_ci			   union lws_ss_contemp *ct)
1164d4afb5ceSopenharmony_ci{
1165d4afb5ceSopenharmony_ci	const char *pbasis = h->policy->u.http.url;
1166d4afb5ceSopenharmony_ci	size_t used_in, used_out;
1167d4afb5ceSopenharmony_ci	lws_strexp_t exp;
1168d4afb5ceSopenharmony_ci
1169d4afb5ceSopenharmony_ci	/* i.path on entry is used to override the policy urlpath if not "" */
1170d4afb5ceSopenharmony_ci
1171d4afb5ceSopenharmony_ci	if (i->path[0])
1172d4afb5ceSopenharmony_ci		pbasis = i->path;
1173d4afb5ceSopenharmony_ci
1174d4afb5ceSopenharmony_ci	if (!pbasis)
1175d4afb5ceSopenharmony_ci		return 0;
1176d4afb5ceSopenharmony_ci
1177d4afb5ceSopenharmony_ci	/* uncomment to force h1 */
1178d4afb5ceSopenharmony_ci	// i->alpn = "http/1.1";
1179d4afb5ceSopenharmony_ci
1180d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SS_RIDESHARE)
1181d4afb5ceSopenharmony_ci	if (h->policy->flags & LWSSSPOLF_HTTP_MULTIPART)
1182d4afb5ceSopenharmony_ci		i->ssl_connection |= LCCSCF_HTTP_MULTIPART_MIME;
1183d4afb5ceSopenharmony_ci
1184d4afb5ceSopenharmony_ci	if (h->policy->flags & LWSSSPOLF_HTTP_X_WWW_FORM_URLENCODED)
1185d4afb5ceSopenharmony_ci		i->ssl_connection |= LCCSCF_HTTP_X_WWW_FORM_URLENCODED;
1186d4afb5ceSopenharmony_ci#endif
1187d4afb5ceSopenharmony_ci
1188d4afb5ceSopenharmony_ci	if (h->policy->flags & LWSSSPOLF_HTTP_CACHE_COOKIES)
1189d4afb5ceSopenharmony_ci		i->ssl_connection |= LCCSCF_CACHE_COOKIES;
1190d4afb5ceSopenharmony_ci
1191d4afb5ceSopenharmony_ci	/* protocol aux is the path part */
1192d4afb5ceSopenharmony_ci
1193d4afb5ceSopenharmony_ci	i->path = buf;
1194d4afb5ceSopenharmony_ci
1195d4afb5ceSopenharmony_ci	/* skip the unnessary '/' */
1196d4afb5ceSopenharmony_ci	if (*pbasis == '/')
1197d4afb5ceSopenharmony_ci		pbasis = pbasis + 1;
1198d4afb5ceSopenharmony_ci
1199d4afb5ceSopenharmony_ci	buf[0] = '/';
1200d4afb5ceSopenharmony_ci
1201d4afb5ceSopenharmony_ci	lws_strexp_init(&exp, (void *)h, lws_ss_exp_cb_metadata, buf + 1, len - 1);
1202d4afb5ceSopenharmony_ci
1203d4afb5ceSopenharmony_ci	if (lws_strexp_expand(&exp, pbasis, strlen(pbasis),
1204d4afb5ceSopenharmony_ci			      &used_in, &used_out) != LSTRX_DONE)
1205d4afb5ceSopenharmony_ci		return 1;
1206d4afb5ceSopenharmony_ci
1207d4afb5ceSopenharmony_ci	return 0;
1208d4afb5ceSopenharmony_ci}
1209d4afb5ceSopenharmony_ci
1210d4afb5ceSopenharmony_ci
1211d4afb5ceSopenharmony_ciconst struct ss_pcols ss_pcol_h1 = {
1212d4afb5ceSopenharmony_ci	"h1",
1213d4afb5ceSopenharmony_ci	"http/1.1",
1214d4afb5ceSopenharmony_ci	&protocol_secstream_h1,
1215d4afb5ceSopenharmony_ci	secstream_connect_munge_h1,
1216d4afb5ceSopenharmony_ci	NULL, NULL
1217d4afb5ceSopenharmony_ci};
1218