• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  *
24  * 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 / PATCH 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, "PATCH") ||
257 		 !strcmp(h->policy->u.http.method, "PUT"))) &&
258 	    wsi->http.writeable_len) {
259 		if (!(h->policy->flags &
260 			LWSSSPOLF_HTTP_NO_CONTENT_LENGTH)) {
261 			int n = lws_snprintf((char *)buf, 20, "%u",
262 				(unsigned int)wsi->http.writeable_len);
263 			if (lws_add_http_header_by_token(wsi,
264 					WSI_TOKEN_HTTP_CONTENT_LENGTH,
265 					buf, n, pp, end))
266 				return -1;
267 		}
268 		lws_client_http_body_pending(wsi, 1);
269 	}
270 
271 	return 0;
272 }
273 
274 
275 #if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
276 static int
lws_apply_instant_metadata(lws_ss_handle_t * h,struct lws * wsi,uint8_t * buf,uint8_t ** pp,uint8_t * end)277 lws_apply_instant_metadata(lws_ss_handle_t *h, struct lws *wsi, uint8_t *buf,
278 		   uint8_t **pp, uint8_t *end)
279 {
280 	lws_ss_metadata_t *imd = h->instant_metadata;
281 
282 	while (imd) {
283 		if (imd->name && imd->value__may_own_heap) {
284 			lwsl_debug("%s add header %s %s %d\n", __func__,
285 					           imd->name,
286 			                           (char *)imd->value__may_own_heap,
287 						   (int)imd->length);
288 			if (lws_add_http_header_by_name(wsi,
289 					(const unsigned char *)imd->name,
290 					(const unsigned char *)imd->value__may_own_heap,
291 					(int)imd->length, pp, end))
292 			return -1;
293 
294 			/* it's possible user set content-length directly */
295 			if (!strncmp(imd->name,
296 				     "content-length", 14) &&
297 			    atoi(imd->value__may_own_heap))
298 				lws_client_http_body_pending(wsi, 1);
299 
300 		}
301 
302 		imd = imd->next;
303 	}
304 
305 	return 0;
306 }
307 #endif
308 /*
309  * Check if any metadata headers present in the server headers, and record
310  * them into the associated metadata item if so.
311  */
312 
313 static int
lws_extract_metadata(lws_ss_handle_t * h,struct lws * wsi)314 lws_extract_metadata(lws_ss_handle_t *h, struct lws *wsi)
315 {
316 	lws_ss_metadata_t *polmd = h->policy->metadata, *omd;
317 	int n;
318 
319 	while (polmd) {
320 
321 		if (polmd->value_is_http_token != LWS_HTTP_NO_KNOWN_HEADER) {
322 
323 			/* it's a well-known header token */
324 
325 			n = lws_hdr_total_length(wsi, polmd->value_is_http_token);
326 			if (n) {
327 				const char *cp = lws_hdr_simple_ptr(wsi,
328 						polmd->value_is_http_token);
329 				omd = lws_ss_get_handle_metadata(h, polmd->name);
330 				if (!omd || !cp)
331 					return 1;
332 
333 				assert(!strcmp(omd->name, polmd->name));
334 
335 				/*
336 				 * it's present on the wsi, we want to
337 				 * set the related metadata name to it then
338 				 */
339 
340 				_lws_ss_alloc_set_metadata(omd, polmd->name, cp,
341 							   (unsigned int)n);
342 
343 #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
344 				/*
345 				 * ...and because we are doing it from parsing
346 				 * onward rx, we want to mark the metadata as
347 				 * needing passing to the client
348 				 */
349 				omd->pending_onward = 1;
350 #endif
351 			}
352 		}
353 
354 #if defined(LWS_WITH_CUSTOM_HEADERS)
355 		else
356 
357 			/* has to have a non-empty header string */
358 
359 			if (polmd->value__may_own_heap &&
360 			    ((uint8_t *)polmd->value__may_own_heap)[0]) {
361 				char *p;
362 
363 				/*
364 				 * Can it be a custom header?
365 				 */
366 
367 				n = lws_hdr_custom_length(wsi, (const char *)
368 						    polmd->value__may_own_heap,
369 						    polmd->value_length);
370 				if (n > 0) {
371 
372 					p = lws_malloc((unsigned int)n + 1, __func__);
373 					if (!p)
374 						return 1;
375 
376 					/* if needed, free any previous value */
377 
378 					if (polmd->value_on_lws_heap) {
379 						lws_free(
380 						    polmd->value__may_own_heap);
381 						polmd->value_on_lws_heap = 0;
382 					}
383 
384 					/*
385 					 * copy the named custom header value
386 					 * into the malloc'd buffer
387 					 */
388 
389 					if (lws_hdr_custom_copy(wsi, p, n + 1,
390 						     (const char *)
391 						     polmd->value__may_own_heap,
392 						     polmd->value_length) < 0) {
393 						lws_free(p);
394 
395 						return 1;
396 					}
397 
398 					omd = lws_ss_get_handle_metadata(h,
399 								   polmd->name);
400 					if (omd) {
401 
402 						_lws_ss_set_metadata(omd,
403 							polmd->name, p, (size_t)n);
404 						omd->value_on_lws_heap = 1;
405 
406 #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
407 						omd->pending_onward = 1;
408 #endif
409 					}
410 				}
411 			}
412 #endif
413 
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 		} else {
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 
483 		h->wsi = NULL;
484 		r = lws_ss_backoff(h);
485 		if (r != LWSSSSRET_OK) {
486 			if (h->inside_connect) {
487 				h->pending_ret = r;
488 				break;
489 			}
490 			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
491 		}
492 		break;
493 
494 	case LWS_CALLBACK_CLIENT_HTTP_REDIRECT:
495 
496 		if (!h)
497 			return -1;
498 
499 		if (h->policy->u.http.fail_redirect)
500 			lws_system_cpd_set(lws_get_context(wsi),
501 					   LWS_CPD_CAPTIVE_PORTAL);
502 		/* unless it's explicitly allowed, reject to follow it */
503 		return !(h->policy->flags & LWSSSPOLF_ALLOW_REDIRECTS);
504 
505 	case LWS_CALLBACK_CLOSED_HTTP: /* server */
506 	case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
507 		if (!h)
508 			break;
509 
510 		lws_sul_cancel(&h->sul_timeout);
511 
512 		lws_ss_assert_extant(wsi->a.context, wsi->tsi, h);
513 
514 #if defined(LWS_WITH_CONMON)
515 		if (wsi->conmon.pcol == LWSCONMON_PCOL_NONE) {
516 			wsi->conmon.pcol = LWSCONMON_PCOL_HTTP;
517 			wsi->conmon.protocol_specific.http.response =
518 					(int)lws_http_client_http_response(wsi);
519 		}
520 
521 		lws_conmon_ss_json(h);
522 #endif
523 
524 		lws_metrics_caliper_report_hist(h->cal_txn, wsi);
525 		//lwsl_notice("%s: %s LWS_CALLBACK_CLOSED_CLIENT_HTTP\n",
526 		//		__func__, wsi->lc.gutag);
527 
528 		h->wsi = NULL;
529 		h->hanging_som = 0;
530 		h->subseq = 0;
531 
532 #if defined(LWS_WITH_SERVER)
533 		lws_pt_lock(pt, __func__);
534 		lws_dll2_remove(&h->cli_list);
535 		lws_pt_unlock(pt);
536 #endif
537 
538 		if (h->policy && !(h->policy->flags & LWSSSPOLF_OPPORTUNISTIC) &&
539 #if defined(LWS_WITH_SERVER)
540 		    !(h->info.flags & LWSSSINFLAGS_ACCEPTED) && /* not server */
541 #endif
542 		    !h->txn_ok && !wsi->a.context->being_destroyed) {
543 			r = lws_ss_backoff(h);
544 			if (r != LWSSSSRET_OK)
545 				return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
546 			break;
547 		} else
548 			h->seqstate = SSSEQ_IDLE;
549 
550 		if (h->ss_dangling_connected) {
551 			/* already disconnected, no action for DISCONNECT_ME */
552 			r = lws_ss_event_helper(h, LWSSSCS_DISCONNECTED);
553 			if (r != LWSSSSRET_OK)
554 				return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
555 		}
556 		break;
557 
558 	case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
559 
560 		if (!h)
561 			return -1;
562 
563 		lws_ss_assert_extant(wsi->a.context, wsi->tsi, h);
564 		h->wsi = wsi; /* since we accept the wsi is bound to the SS,
565 			       * ensure the SS feels the same way about the wsi */
566 
567 #if defined(LWS_WITH_CONMON)
568 		if (wsi->conmon.pcol == LWSCONMON_PCOL_NONE) {
569 			wsi->conmon.pcol = LWSCONMON_PCOL_HTTP;
570 			wsi->conmon.protocol_specific.http.response =
571 					(int)lws_http_client_http_response(wsi);
572 		}
573 
574 		lws_conmon_ss_json(h);
575 #endif
576 
577 		status = (int)lws_http_client_http_response(wsi);
578 		lwsl_info("%s: LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: %d\n", __func__, status);
579 	//	if (!status)
580 			/* it's just telling use we connected / joined the nwsi */
581 	//		break;
582 
583 #if defined(LWS_WITH_SYS_METRICS)
584 		if (status) {
585 			lws_snprintf((char *)buf, 10, "%d", status);
586 			lws_metrics_tag_ss_add(h, "http_resp", (char *)buf);
587 		}
588 #endif
589 
590 		if (status == HTTP_STATUS_SERVICE_UNAVAILABLE /* 503 */ ||
591 		    status == 429 /* Too many requests */) {
592 			/*
593 			 * We understand this attempt failed, and that we should
594 			 * conceal this attempt.  If there's a specified
595 			 * retry-after, we should use that if larger than our
596 			 * computed backoff
597 			 */
598 
599 			inter = 0;
600 			lws_http_check_retry_after(wsi, &inter);
601 
602 			r = _lws_ss_backoff(h, inter);
603 			if (r != LWSSSSRET_OK)
604 				return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
605 
606 			return -1; /* end this stream */
607 		}
608 
609 		if (h->policy->u.http.resp_expect)
610 			h->u.http.good_respcode =
611 					status == h->policy->u.http.resp_expect;
612 		else
613 			h->u.http.good_respcode = (status >= 200 && status < 300);
614 		// lwsl_err("%s: good resp %d %d\n", __func__, status, h->u.http.good_respcode);
615 
616 		if (lws_extract_metadata(h, wsi)) {
617 			lwsl_info("%s: rx metadata extract failed\n", __func__);
618 
619 			return -1;
620 		}
621 
622 		if (status) {
623 			/*
624 			 * Check and see if it's something from the response
625 			 * map, if so, generate the requested status.  If we're
626 			 * the proxy onward connection, metadata has priority
627 			 * over state updates on the serialization, so the
628 			 * state callback will see the right metadata.
629 			 */
630 			int n = lws_ss_http_resp_to_state(h, status);
631 			if (n) {
632 				r = lws_ss_event_helper(h, (lws_ss_constate_t)n);
633 				if (r != LWSSSSRET_OK)
634 					return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi,
635 									&h);
636 			}
637 		}
638 
639 		if (h->u.http.good_respcode)
640 			lwsl_info("%s: Connected streamtype %s, %d\n", __func__,
641 				  h->policy->streamtype, status);
642 		else
643 			if (h->u.http.good_respcode)
644 				lwsl_warn("%s: Connected streamtype %s, BAD %d\n",
645 					  __func__, h->policy->streamtype,
646 					  status);
647 
648 		h->hanging_som = 0;
649 
650 		h->retry = 0;
651 		h->seqstate = SSSEQ_CONNECTED;
652 		lws_sul_cancel(&h->sul);
653 
654 		if (h->prev_ss_state != LWSSSCS_CONNECTED) {
655 			wsi->client_suppress_CONNECTION_ERROR = 1;
656 			if (h->prev_ss_state != LWSSSCS_CONNECTED) {
657 				r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
658 				if (r != LWSSSSRET_OK)
659 					return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
660 			}
661 		}
662 
663 		/*
664 		 * Since it's an http transaction we initiated... this is
665 		 * proof of connection validity
666 		 */
667 		lws_validity_confirmed(wsi);
668 
669 #if defined(LWS_WITH_SS_RIDESHARE)
670 
671 		/*
672 		 * There are two ways we might want to deal with multipart,
673 		 * one is pass it through raw (although the user code needs
674 		 * a helping hand for learning the boundary), and the other
675 		 * is to deframe it and provide basically submessages in the
676 		 * different parts.
677 		 */
678 
679 		if (lws_hdr_copy(wsi, (char *)buf, sizeof(buf),
680 				 WSI_TOKEN_HTTP_CONTENT_TYPE) > 0 &&
681 		/* multipart/form-data;
682 		 * boundary=----WebKitFormBoundarycc7YgAPEIHvgE9Bf */
683 
684 		    (!strncmp((char *)buf, "multipart/form-data", 19) ||
685 		     !strncmp((char *)buf, "multipart/related", 17))) {
686 			struct lws_tokenize ts;
687 			lws_tokenize_elem e;
688 
689 			// puts((const char *)buf);
690 
691 			memset(&ts, 0, sizeof(ts));
692 			ts.start = (char *)buf;
693 			ts.len = strlen(ts.start);
694 			ts.flags = LWS_TOKENIZE_F_RFC7230_DELIMS |
695 					LWS_TOKENIZE_F_SLASH_NONTERM |
696 					LWS_TOKENIZE_F_MINUS_NONTERM;
697 
698 			h->u.http.boundary[0] = '\0';
699 			do {
700 				e = lws_tokenize(&ts);
701 				if (e == LWS_TOKZE_TOKEN_NAME_EQUALS &&
702 				    !strncmp(ts.token, "boundary", 8) &&
703 				    ts.token_len == 8) {
704 					e = lws_tokenize(&ts);
705 					if (e != LWS_TOKZE_TOKEN)
706 						goto malformed;
707 					h->u.http.boundary[0] = '\x0d';
708 					h->u.http.boundary[1] = '\x0a';
709 					h->u.http.boundary[2] = '-';
710 					h->u.http.boundary[3] = '-';
711 					lws_strnncpy(h->u.http.boundary + 4,
712 						     ts.token, ts.token_len,
713 						     sizeof(h->u.http.boundary) - 4);
714 					h->u.http.boundary_len =
715 						(uint8_t)(ts.token_len + 4);
716 					h->u.http.boundary_seq = 2;
717 					h->u.http.boundary_dashes = 0;
718 				}
719 			} while (e > 0);
720 			lwsl_info("%s: multipart boundary '%s' len %d\n", __func__,
721 					h->u.http.boundary, h->u.http.boundary_len);
722 
723 			/* inform the ss that a related message group begins */
724 
725 			if ((h->policy->flags & LWSSSPOLF_HTTP_MULTIPART_IN) &&
726 			    h->u.http.boundary[0])
727 				h->info.rx(ss_to_userobj(h), NULL, 0,
728 					   LWSSS_FLAG_RELATED_START);
729 
730 			// lws_header_table_detach(wsi, 0);
731 		}
732 		break;
733 malformed:
734 		lwsl_notice("%s: malformed multipart header\n", __func__);
735 		return -1;
736 #else
737 		break;
738 #endif
739 
740 	case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
741 		if (!h)
742 			return -1;
743 		if (h->writeable_len)
744 			wsi->http.writeable_len = h->writeable_len;
745 
746 		{
747 			uint8_t **p = (uint8_t **)in, *end = (*p) + len,
748 				*oin = *(uint8_t **)in;
749 
750 		/*
751 		 * blob-based headers
752 		 */
753 
754 		for (m = 0; m < _LWSSS_HBI_COUNT; m++) {
755 			lws_system_blob_t *ab;
756 			int o = 0, n;
757 
758 			if (!h->policy->u.http.blob_header[m])
759 				continue;
760 
761 			/*
762 			 * To be backward compatible, default is system-wide LWA auth,
763 			 * and "http_auth_header" is for default LWA auth, current users do not
764 			 * need any change in their policy.
765 			 * If user wants different auth/token, need to specify the "use_auth"
766 			 * and will be handled after metadata headers are applied.
767 			 */
768 
769 			if (m == LWSSS_HBI_AUTH &&
770 			    h->policy->u.http.auth_preamble)
771 				o = lws_snprintf((char *)buf, sizeof(buf), "%s",
772 					h->policy->u.http.auth_preamble);
773 
774 			if (o > (int)sizeof(buf) - 2)
775 				return -1;
776 
777 			ab = lws_system_get_blob(wsi->a.context, blob_idx[m], 0);
778 			if (!ab)
779 				return -1;
780 
781 			buflen = sizeof(buf) - (unsigned int)o - 2u;
782 			n = lws_system_blob_get(ab, buf + o, &buflen, 0);
783 			if (n < 0)
784 				return -1;
785 
786 			buf[(unsigned int)o + buflen] = '\0';
787 			lwsl_debug("%s: adding blob %d: %s\n", __func__, m, buf);
788 
789 			if (lws_add_http_header_by_name(wsi,
790 				 (uint8_t *)h->policy->u.http.blob_header[m],
791 				 buf, (int)((int)buflen + o), p, end))
792 				return -1;
793 		}
794 
795 		/*
796 		 * metadata-based headers
797 		 */
798 
799 		if (lws_apply_metadata(h, wsi, buf, p, end))
800 			return -1;
801 
802 #if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
803 		if (h->policy->flags & LWSSSPOLF_DIRECT_PROTO_STR) {
804 			if (lws_apply_instant_metadata(h, wsi, buf, p, end))
805 				return -1;
806 		}
807 #endif
808 
809 #if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
810 		if (h->policy->auth && h->policy->auth->type &&
811 				!strcmp(h->policy->auth->type, "sigv4")) {
812 
813 			if (lws_ss_apply_sigv4(wsi, h, p, end))
814 				return -1;
815 		}
816 #endif
817 
818 
819 		(void)oin;
820 		//if (*p != oin)
821 		//	lwsl_hexdump_notice(oin, lws_ptr_diff_size_t(*p, oin));
822 
823 		}
824 
825 		/*
826 		 * So when proxied, for POST we have to synthesize a CONNECTED
827 		 * state, so it can request a writeable and deliver the POST
828 		 * body
829 		 */
830 		if ((h->policy->protocol == LWSSSP_H1 ||
831 		     h->policy->protocol == LWSSSP_H2) &&
832 		     h->being_serialized && (
833 				!strcmp(h->policy->u.http.method, "PUT") ||
834 				!strcmp(h->policy->u.http.method, "PATCH") ||
835 				!strcmp(h->policy->u.http.method, "POST"))) {
836 
837 			wsi->client_suppress_CONNECTION_ERROR = 1;
838 			if (h->prev_ss_state != LWSSSCS_CONNECTED) {
839 				r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
840 				if (r)
841 					return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
842 			}
843 		}
844 
845 		break;
846 
847 	/* chunks of chunked content, with header removed */
848 	case LWS_CALLBACK_HTTP_BODY:
849 	case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
850 		lwsl_debug("%s: RECEIVE_CLIENT_HTTP_READ: read %d\n",
851 				__func__, (int)len);
852 		if (!h || !h->info.rx)
853 			return 0;
854 
855 #if defined(LWS_WITH_SS_RIDESHARE)
856 		if ((h->policy->flags & LWSSSPOLF_HTTP_MULTIPART_IN) &&
857 		    h->u.http.boundary[0])
858 			return ss_http_multipart_parser(h, in, len);
859 #endif
860 
861 		if (!h->subseq) {
862 			f |= LWSSS_FLAG_SOM;
863 			h->hanging_som = 1;
864 			h->subseq = 1;
865 		}
866 
867 	//	lwsl_notice("%s: HTTP_READ: client side sent len %d fl 0x%x\n",
868 	//		    __func__, (int)len, (int)f);
869 
870 		h->wsi = wsi; /* since we accept the wsi is bound to the SS,
871 			       * ensure the SS feels the same way about the wsi */
872 		r = h->info.rx(ss_to_userobj(h), (const uint8_t *)in, len, f);
873 		if (r != LWSSSSRET_OK)
874 			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
875 
876 		return 0; /* don't passthru */
877 
878 	/* uninterpreted http content */
879 	case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
880 		{
881 			char *px = (char *)buf + LWS_PRE; /* guarantees LWS_PRE */
882 			int lenx = sizeof(buf) - LWS_PRE;
883 
884 			m = lws_http_client_read(wsi, &px, &lenx);
885 			if (m < 0)
886 				return m;
887 		}
888 		lws_set_timeout(wsi, 99, 30);
889 
890 		return 0; /* don't passthru */
891 
892 	case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
893 		// lwsl_debug("%s: LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n", __func__);
894 
895 		if (!h)
896 			return -1;
897 
898 		if (h->hanging_som) {
899 			h->info.rx(ss_to_userobj(h), NULL, 0, LWSSS_FLAG_EOM);
900 			h->hanging_som = 0;
901 			h->subseq = 0;
902 		}
903 
904 		wsi->http.writeable_len = h->writeable_len = 0;
905 		lws_sul_cancel(&h->sul_timeout);
906 
907 		h->txn_ok = 1;
908 
909 #if defined(LWS_WITH_SYS_METRICS)
910 		lws_metrics_tag_ss_add(h, "result",
911 				       h->u.http.good_respcode ?
912 				       "SS_ACK_REMOTE" : "SS_NACK_REMOTE");
913 #endif
914 
915 		r = lws_ss_event_helper(h, h->u.http.good_respcode ?
916 						LWSSSCS_QOS_ACK_REMOTE :
917 						LWSSSCS_QOS_NACK_REMOTE);
918 		if (r != LWSSSSRET_OK)
919 			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
920 
921 		lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
922 		break;
923 
924 	case LWS_CALLBACK_HTTP_WRITEABLE:
925 	case LWS_CALLBACK_CLIENT_HTTP_WRITEABLE:
926 
927 		if (!h || !h->info.tx) {
928 			lwsl_notice("%s: no handle / tx\n", __func__);
929 			return 0;
930 		}
931 
932 #if defined(LWS_WITH_SERVER)
933 		if (h->txn_resp_pending) {
934 			/*
935 			 * If we're going to start sending something, we need to
936 			 * to take care of the http response header for it first
937 			 */
938 			h->txn_resp_pending = 0;
939 
940 			if (lws_add_http_common_headers(wsi,
941 					(unsigned int)(h->txn_resp_set ?
942 						(h->txn_resp ? h->txn_resp : 200) :
943 						HTTP_STATUS_NOT_FOUND),
944 					NULL, h->wsi->http.writeable_len,
945 					&p, end))
946 				return 1;
947 
948 			/*
949 			 * metadata-based headers
950 			 */
951 
952 			if (lws_apply_metadata(h, wsi, buf, &p, end))
953 				return -1;
954 
955 			if (lws_finalize_write_http_header(wsi, start, &p, end))
956 				return 1;
957 
958 			/* write the body separately */
959 			lws_callback_on_writable(wsi);
960 
961 			return 0;
962 		}
963 #endif
964 
965 		if (
966 #if defined(LWS_WITH_SERVER)
967 		    !(h->info.flags & LWSSSINFLAGS_ACCEPTED) && /* not accepted */
968 #endif
969 		    !h->rideshare)
970 
971 			h->rideshare = h->policy;
972 
973 #if defined(LWS_WITH_SS_RIDESHARE)
974 		if (
975 #if defined(LWS_WITH_SERVER)
976 		    !(h->info.flags & LWSSSINFLAGS_ACCEPTED) && /* not accepted */
977 #endif
978 		    !h->inside_msg && h->rideshare->u.http.multipart_name)
979 			lws_client_http_multipart(wsi,
980 				h->rideshare->u.http.multipart_name,
981 				h->rideshare->u.http.multipart_filename,
982 				h->rideshare->u.http.multipart_content_type,
983 				(char **)&p, (char *)end);
984 
985 		buflen = lws_ptr_diff_size_t(end, p);
986 		if (h->policy->u.http.multipart_name)
987 			buflen -= 24; /* allow space for end of multipart */
988 #else
989 		buflen = lws_ptr_diff_size_t(end, p);
990 #endif
991 		r = h->info.tx(ss_to_userobj(h), h->txord++, p, &buflen, &f);
992 		if (r == LWSSSSRET_TX_DONT_SEND)
993 			return 0;
994 		if (r < 0)
995 			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
996 
997 		// lwsl_notice("%s: WRITEABLE: user tx says len %d fl 0x%x\n",
998 		//	    __func__, (int)buflen, (int)f);
999 
1000 		p += buflen;
1001 
1002 		if (f & LWSSS_FLAG_EOM) {
1003 #if defined(LWS_WITH_SERVER)
1004 		    if (!(h->info.flags & LWSSSINFLAGS_ACCEPTED)) {
1005 #endif
1006 			conceal_eom = 1;
1007 			/* end of rideshares */
1008 			if (!h->rideshare->rideshare_streamtype) {
1009 				lws_client_http_body_pending(wsi, 0);
1010 #if defined(LWS_WITH_SS_RIDESHARE)
1011 				if (h->rideshare->u.http.multipart_name)
1012 					lws_client_http_multipart(wsi, NULL, NULL, NULL,
1013 						(char **)&p, (char *)end);
1014 				conceal_eom = 0;
1015 #endif
1016 			} else {
1017 				h->rideshare = lws_ss_policy_lookup(wsi->a.context,
1018 						h->rideshare->rideshare_streamtype);
1019 				lws_callback_on_writable(wsi);
1020 			}
1021 #if defined(LWS_WITH_SERVER)
1022 		    }
1023 #endif
1024 
1025 			h->inside_msg = 0;
1026 		} else {
1027 			/* otherwise we can spin with zero length writes */
1028 			if (!f && !lws_ptr_diff(p, buf + LWS_PRE))
1029 				break;
1030 			h->inside_msg = 1;
1031 			lws_callback_on_writable(wsi);
1032 		}
1033 
1034 		lwsl_info("%s: lws_write %d %d\n", __func__,
1035 			  lws_ptr_diff(p, buf + LWS_PRE), f);
1036 
1037 		if (lws_write(wsi, buf + LWS_PRE, lws_ptr_diff_size_t(p, buf + LWS_PRE),
1038 			 (!conceal_eom && (f & LWSSS_FLAG_EOM)) ?
1039 				    LWS_WRITE_HTTP_FINAL : LWS_WRITE_HTTP) !=
1040 				(int)lws_ptr_diff(p, buf + LWS_PRE)) {
1041 			lwsl_err("%s: write failed\n", __func__);
1042 			return -1;
1043 		}
1044 
1045 #if defined(LWS_WITH_SERVER)
1046 		if ((h->info.flags & LWSSSINFLAGS_ACCEPTED) /* server */ &&
1047 		    (f & LWSSS_FLAG_EOM) &&
1048 		     lws_http_transaction_completed(wsi))
1049 			return -1;
1050 #else
1051 		lws_set_timeout(wsi, 0, 0);
1052 #endif
1053 		break;
1054 
1055 #if defined(LWS_WITH_SERVER)
1056 	case LWS_CALLBACK_HTTP:
1057 
1058 		if (!h)
1059 			return -1;
1060 
1061 		lwsl_info("%s: LWS_CALLBACK_HTTP\n", __func__);
1062 		{
1063 
1064 			h->txn_resp_set = 0;
1065 			h->txn_resp_pending = 1;
1066 			h->writeable_len = 0;
1067 
1068 #if defined(LWS_ROLE_H2)
1069 			m = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_METHOD);
1070 			if (m) {
1071 				if (lws_ss_alloc_set_metadata(h, "method",
1072 						    lws_hdr_simple_ptr(wsi,
1073 						     WSI_TOKEN_HTTP_COLON_METHOD), (unsigned int)m))
1074 					return -1;
1075 				m = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH);
1076 				if (m && lws_ss_alloc_set_metadata(h, "path",
1077 						    lws_hdr_simple_ptr(wsi,
1078 						     WSI_TOKEN_HTTP_COLON_PATH), (unsigned int)m))
1079 					return -1;
1080 			} else
1081 #endif
1082 			{
1083 				m = lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI);
1084 				if (m) {
1085 					if (lws_ss_alloc_set_metadata(h, "path",
1086 							lws_hdr_simple_ptr(wsi,
1087 								WSI_TOKEN_GET_URI), (unsigned int)m))
1088 						return -1;
1089 					if (lws_ss_alloc_set_metadata(h, "method", "GET", 3))
1090 						return -1;
1091 				} else {
1092 					m = lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI);
1093 					if (m) {
1094 						if (lws_ss_alloc_set_metadata(h, "path",
1095 								lws_hdr_simple_ptr(wsi,
1096 									WSI_TOKEN_POST_URI), (unsigned int)m))
1097 							return -1;
1098 						if (lws_ss_alloc_set_metadata(h, "method", "POST", 4))
1099 							return -1;
1100 					} else {
1101 						m = lws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI);
1102 						if (m) {
1103 							if (lws_ss_alloc_set_metadata(h, "path",
1104 									lws_hdr_simple_ptr(wsi,
1105 										WSI_TOKEN_PATCH_URI), (unsigned int)m))
1106 								return -1;
1107 							if (lws_ss_alloc_set_metadata(h, "method", "PATCH", 5))
1108 								return -1;
1109 						}
1110 					}
1111 				}
1112 			}
1113 		}
1114 
1115 		if (!h->ss_dangling_connected) {
1116 #if defined(LWS_WITH_SYS_METRICS)
1117 			/*
1118 			 * If any hanging caliper measurement, dump it, and free any tags
1119 			 */
1120 			lws_metrics_caliper_report_hist(h->cal_txn, (struct lws *)NULL);
1121 #endif
1122 			wsi->client_suppress_CONNECTION_ERROR = 1;
1123 			if (h->prev_ss_state != LWSSSCS_CONNECTED) {
1124 				r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
1125 				if (r)
1126 					return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
1127 			}
1128 		}
1129 
1130 		r = lws_ss_event_helper(h, LWSSSCS_SERVER_TXN);
1131 		if (r)
1132 			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r,
1133 								wsi, &h);
1134 
1135 		return 0;
1136 #endif
1137 
1138 	default:
1139 		break;
1140 	}
1141 
1142 	return lws_callback_http_dummy(wsi, reason, user, in, len);
1143 }
1144 
1145 const struct lws_protocols protocol_secstream_h1 = {
1146 	"lws-secstream-h1",
1147 	secstream_h1,
1148 	0, 0, 0, NULL, 0
1149 };
1150 
1151 /*
1152  * Munge connect info according to protocol-specific considerations... this
1153  * usually means interpreting aux in a protocol-specific way and using the
1154  * pieces at connection setup time, eg, http url pieces.
1155  *
1156  * len bytes of buf can be used for things with scope until after the actual
1157  * connect.
1158  */
1159 
1160 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)1161 secstream_connect_munge_h1(lws_ss_handle_t *h, char *buf, size_t len,
1162 			   struct lws_client_connect_info *i,
1163 			   union lws_ss_contemp *ct)
1164 {
1165 	const char *pbasis = h->policy->u.http.url;
1166 	size_t used_in, used_out;
1167 	lws_strexp_t exp;
1168 
1169 	/* i.path on entry is used to override the policy urlpath if not "" */
1170 
1171 	if (i->path[0])
1172 		pbasis = i->path;
1173 
1174 	if (!pbasis)
1175 		return 0;
1176 
1177 	/* uncomment to force h1 */
1178 	// i->alpn = "http/1.1";
1179 
1180 #if defined(LWS_WITH_SS_RIDESHARE)
1181 	if (h->policy->flags & LWSSSPOLF_HTTP_MULTIPART)
1182 		i->ssl_connection |= LCCSCF_HTTP_MULTIPART_MIME;
1183 
1184 	if (h->policy->flags & LWSSSPOLF_HTTP_X_WWW_FORM_URLENCODED)
1185 		i->ssl_connection |= LCCSCF_HTTP_X_WWW_FORM_URLENCODED;
1186 #endif
1187 
1188 	if (h->policy->flags & LWSSSPOLF_HTTP_CACHE_COOKIES)
1189 		i->ssl_connection |= LCCSCF_CACHE_COOKIES;
1190 
1191 	/* protocol aux is the path part */
1192 
1193 	i->path = buf;
1194 
1195 	/* skip the unnessary '/' */
1196 	if (*pbasis == '/')
1197 		pbasis = pbasis + 1;
1198 
1199 	buf[0] = '/';
1200 
1201 	lws_strexp_init(&exp, (void *)h, lws_ss_exp_cb_metadata, buf + 1, len - 1);
1202 
1203 	if (lws_strexp_expand(&exp, pbasis, strlen(pbasis),
1204 			      &used_in, &used_out) != LSTRX_DONE)
1205 		return 1;
1206 
1207 	return 0;
1208 }
1209 
1210 
1211 const struct ss_pcols ss_pcol_h1 = {
1212 	"h1",
1213 	"http/1.1",
1214 	&protocol_secstream_h1,
1215 	secstream_connect_munge_h1,
1216 	NULL, NULL
1217 };
1218