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