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)
34static int
35ss_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
149around:
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
194static int
195lws_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
213static int
214lws_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)
276static int
277lws_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
313static int
314lws_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
420static 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
427int
428secstream_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;
733malformed:
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
1145const 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
1160static int
1161secstream_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
1211const 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