• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 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 
25 #include "private-lib-core.h"
26 
27 #if defined(LWS_WITH_TLS)
28 int
lws_client_create_tls(struct lws * wsi,const char ** pcce,int do_c1)29 lws_client_create_tls(struct lws *wsi, const char **pcce, int do_c1)
30 {
31 	int n;
32 
33 	/* we can retry this... just cook the SSL BIO the first time */
34 
35 	if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
36 
37 		if (!wsi->tls.ssl) {
38 			if (lws_ssl_client_bio_create(wsi) < 0) {
39 				*pcce = "bio_create failed";
40 				return -1;
41 			}
42 
43 			if (!wsi->transaction_from_pipeline_queue &&
44 			    lws_tls_restrict_borrow(wsi->context)) {
45 				*pcce = "tls restriction limit";
46 				return -1;
47 			}
48 		}
49 
50 		if (!do_c1)
51 			return 0;
52 
53 		n = lws_ssl_client_connect1(wsi);
54 		if (!n)
55 			return 1; /* caller should return 0 */
56 		if (n < 0) {
57 			*pcce = "lws_ssl_client_connect1 failed";
58 			return -1;
59 		}
60 	} else
61 		wsi->tls.ssl = NULL;
62 
63 #if defined (LWS_WITH_HTTP2)
64 	if (wsi->client_h2_alpn) {
65 		/*
66 		 * We connected to the server and set up tls, and
67 		 * negotiated "h2".
68 		 *
69 		 * So this is it, we are an h2 master client connection
70 		 * now, not an h1 client connection.
71 		 */
72 #if defined(LWS_WITH_TLS)
73 		lws_tls_server_conn_alpn(wsi);
74 #endif
75 
76 		/* send the H2 preface to legitimize the connection */
77 		if (lws_h2_issue_preface(wsi)) {
78 			*pcce = "error sending h2 preface";
79 			return -1;
80 		}
81 	}
82 #endif
83 
84 	return 0; /* OK */
85 }
86 
87 #endif
88 
89 void
lws_client_http_body_pending(struct lws * wsi,int something_left_to_send)90 lws_client_http_body_pending(struct lws *wsi, int something_left_to_send)
91 {
92 	wsi->client_http_body_pending = !!something_left_to_send;
93 }
94 
95 int
lws_client_socket_service(struct lws * wsi,struct lws_pollfd * pollfd)96 lws_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd)
97 {
98 	struct lws_context *context = wsi->context;
99 	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
100 	char *p = (char *)&pt->serv_buf[0];
101 #if defined(LWS_WITH_TLS)
102 	char ebuf[128];
103 #endif
104 	const char *cce = NULL;
105 	char *sb = p;
106 	int n = 0;
107 
108 	switch (lwsi_state(wsi)) {
109 
110 	case LRS_WAITING_DNS:
111 		/*
112 		 * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
113 		 * timeout protection set in client-handshake.c
114 		 */
115 		lwsl_err("%s: wsi %p: WAITING_DNS\n", __func__, wsi);
116 		if (!lws_client_connect_2_dnsreq(wsi)) {
117 			/* closed */
118 			lwsl_client("closed\n");
119 			return -1;
120 		}
121 
122 		/* either still pending connection, or changed mode */
123 		return 0;
124 
125 	case LRS_WAITING_CONNECT:
126 
127 		/*
128 		 * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
129 		 * timeout protection set in client-handshake.c
130 		 */
131 		if (pollfd->revents & LWS_POLLOUT)
132 			lws_client_connect_3_connect(wsi, NULL, NULL, 0, NULL);
133 		break;
134 
135 #if defined(LWS_WITH_SOCKS5)
136 	/* SOCKS Greeting Reply */
137 	case LRS_WAITING_SOCKS_GREETING_REPLY:
138 	case LRS_WAITING_SOCKS_AUTH_REPLY:
139 	case LRS_WAITING_SOCKS_CONNECT_REPLY:
140 
141 		switch (lws_socks5c_handle_state(wsi, pollfd, &cce)) {
142 		case LW5CHS_RET_RET0:
143 			return 0;
144 		case LW5CHS_RET_BAIL3:
145 			goto bail3;
146 		case LW5CHS_RET_STARTHS:
147 			goto start_ws_handshake;
148 		default:
149 			break;
150 		}
151 		break;
152 #endif
153 
154 #if defined(LWS_CLIENT_HTTP_PROXYING) && (defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2))
155 
156 	case LRS_WAITING_PROXY_REPLY:
157 
158 		/* handle proxy hung up on us */
159 
160 		if (pollfd->revents & LWS_POLLHUP) {
161 
162 			lwsl_warn("Proxy connection %p (fd=%d) dead\n",
163 				  (void *)wsi, pollfd->fd);
164 
165 			cce = "proxy conn dead";
166 			goto bail3;
167 		}
168 
169 		n = recv(wsi->desc.sockfd, sb, context->pt_serv_buf_size, 0);
170 		if (n < 0) {
171 			if (LWS_ERRNO == LWS_EAGAIN) {
172 				lwsl_debug("Proxy read EAGAIN... retrying\n");
173 				return 0;
174 			}
175 			lwsl_err("ERROR reading from proxy socket\n");
176 			cce = "proxy read err";
177 			goto bail3;
178 		}
179 
180 		pt->serv_buf[13] = '\0';
181 		if (n < 13 || (strncmp(sb, "HTTP/1.0 200 ", 13) &&
182 		    strncmp(sb, "HTTP/1.1 200 ", 13))) {
183 			lwsl_err("%s: ERROR proxy did not reply with h1\n",
184 					__func__);
185 			/* lwsl_hexdump_notice(sb, n); */
186 			cce = "proxy not h1";
187 			goto bail3;
188 		}
189 
190 		lwsl_info("%s: proxy connection extablished\n", __func__);
191 
192 		/* clear his proxy connection timeout */
193 
194 		lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
195 
196 		/* fallthru */
197 
198 #endif
199 
200 	case LRS_H1C_ISSUE_HANDSHAKE:
201 
202 		/*
203 		 * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
204 		 * timeout protection set in client-handshake.c
205 		 *
206 		 * take care of our lws_callback_on_writable
207 		 * happening at a time when there's no real connection yet
208 		 */
209 #if defined(LWS_WITH_SOCKS5)
210 start_ws_handshake:
211 #endif
212 		if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
213 			return -1;
214 
215 #if defined(LWS_WITH_TLS)
216 		n = lws_client_create_tls(wsi, &cce, 1);
217 		if (n < 0)
218 			goto bail3;
219 		if (n == 1)
220 			return 0;
221 
222 		/* fallthru */
223 
224 	case LRS_WAITING_SSL:
225 
226 		if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
227 			n = lws_ssl_client_connect2(wsi, ebuf, sizeof(ebuf));
228 			if (!n)
229 				return 0;
230 			if (n < 0) {
231 				cce = ebuf;
232 				goto bail3;
233 			}
234 		} else
235 			wsi->tls.ssl = NULL;
236 #endif
237 #if defined(LWS_WITH_DETAILED_LATENCY)
238 		if (context->detailed_latency_cb) {
239 			wsi->detlat.type = LDLT_TLS_NEG_CLIENT;
240 			wsi->detlat.latencies[LAT_DUR_PROXY_CLIENT_REQ_TO_WRITE] =
241 				lws_now_usecs() -
242 				wsi->detlat.earliest_write_req_pre_write;
243 			wsi->detlat.latencies[LAT_DUR_USERCB] = 0;
244 			lws_det_lat_cb(wsi->context, &wsi->detlat);
245 		}
246 #endif
247 #if defined (LWS_WITH_HTTP2)
248 		if (wsi->client_h2_alpn) {
249 			/*
250 			 * We connected to the server and set up tls, and
251 			 * negotiated "h2".
252 			 *
253 			 * So this is it, we are an h2 master client connection
254 			 * now, not an h1 client connection.
255 			 */
256 #if defined(LWS_WITH_TLS)
257 			lws_tls_server_conn_alpn(wsi);
258 #endif
259 
260 			/* send the H2 preface to legitimize the connection */
261 			if (lws_h2_issue_preface(wsi)) {
262 				cce = "error sending h2 preface";
263 				goto bail3;
264 			}
265 
266 		//	lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2);
267 			lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND,
268 					context->timeout_secs);
269 
270 			break;
271 		}
272 #endif
273 
274 		/* fallthru */
275 
276 	case LRS_H1C_ISSUE_HANDSHAKE2:
277 		p = lws_generate_client_handshake(wsi, p);
278 		if (p == NULL) {
279 			if (wsi->role_ops == &role_ops_raw_skt
280 #if defined(LWS_ROLE_RAW_FILE)
281 				|| wsi->role_ops == &role_ops_raw_file
282 #endif
283 			    )
284 				return 0;
285 
286 			lwsl_err("Failed to generate handshake for client\n");
287 			lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
288 					   "chs");
289 			return 0;
290 		}
291 
292 		/* send our request to the server */
293 
294 		lwsl_info("%s: HANDSHAKE2: %p: sending headers "
295 			  "(wsistate 0x%lx), w sock %d\n",
296 			  __func__, wsi, (unsigned long)wsi->wsistate,
297 			  wsi->desc.sockfd);
298 #if defined(LWS_WITH_DETAILED_LATENCY)
299 		wsi->detlat.earliest_write_req_pre_write = lws_now_usecs();
300 #endif
301 		n = lws_ssl_capable_write(wsi, (unsigned char *)sb, (int)(p - sb));
302 		switch (n) {
303 		case LWS_SSL_CAPABLE_ERROR:
304 			lwsl_debug("ERROR writing to client socket\n");
305 			lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
306 					   "cws");
307 			return 0;
308 		case LWS_SSL_CAPABLE_MORE_SERVICE:
309 			lws_callback_on_writable(wsi);
310 			break;
311 		}
312 
313 		if (wsi->client_http_body_pending) {
314 			lwsl_debug("body pending\n");
315 			lwsi_set_state(wsi, LRS_ISSUE_HTTP_BODY);
316 			lws_set_timeout(wsi,
317 					PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD,
318 					context->timeout_secs);
319 
320 			if (wsi->flags & LCCSCF_HTTP_X_WWW_FORM_URLENCODED)
321 				lws_callback_on_writable(wsi);
322 #if defined(LWS_WITH_HTTP_PROXY)
323 			if (wsi->http.proxy_clientside)
324 				lws_callback_on_writable(wsi);
325 #endif
326 			/* user code must ask for writable callback */
327 			break;
328 		}
329 
330 		lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
331 		wsi->hdr_parsing_completed = 0;
332 
333 		if (lwsi_state(wsi) == LRS_IDLING) {
334 			lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
335 			wsi->hdr_parsing_completed = 0;
336 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
337 			wsi->http.ah->parser_state = WSI_TOKEN_NAME_PART;
338 			wsi->http.ah->lextable_pos = 0;
339 			wsi->http.ah->unk_pos = 0;
340 			/* If we're (re)starting on hdr, need other implied init */
341 			wsi->http.ah->ues = URIES_IDLE;
342 #endif
343 		}
344 
345 		lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
346 				wsi->context->timeout_secs);
347 
348 		lws_callback_on_writable(wsi);
349 
350 		goto client_http_body_sent;
351 
352 	case LRS_ISSUE_HTTP_BODY:
353 #if defined(LWS_WITH_HTTP_PROXY)
354 			if (wsi->http.proxy_clientside) {
355 				lws_callback_on_writable(wsi);
356 				break;
357 			}
358 #endif
359 		if (wsi->client_http_body_pending) {
360 			//lws_set_timeout(wsi,
361 			//		PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD,
362 			//		context->timeout_secs);
363 			/* user code must ask for writable callback */
364 			break;
365 		}
366 client_http_body_sent:
367 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
368 		/* prepare ourselves to do the parsing */
369 		wsi->http.ah->parser_state = WSI_TOKEN_NAME_PART;
370 		wsi->http.ah->lextable_pos = 0;
371 		wsi->http.ah->unk_pos = 0;
372 #endif
373 		lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
374 		lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
375 				context->timeout_secs);
376 		break;
377 
378 	case LRS_WAITING_SERVER_REPLY:
379 		/*
380 		 * handle server hanging up on us...
381 		 * but if there is POLLIN waiting, handle that first
382 		 */
383 		if ((pollfd->revents & (LWS_POLLIN | LWS_POLLHUP)) ==
384 								LWS_POLLHUP) {
385 
386 			lwsl_debug("Server connection %p (fd=%d) dead\n",
387 				(void *)wsi, pollfd->fd);
388 			cce = "Peer hung up";
389 			goto bail3;
390 		}
391 
392 		if (!(pollfd->revents & LWS_POLLIN))
393 			break;
394 
395 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
396 		/* interpret the server response
397 		 *
398 		 *  HTTP/1.1 101 Switching Protocols
399 		 *  Upgrade: websocket
400 		 *  Connection: Upgrade
401 		 *  Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
402 		 *  Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
403 		 *  Sec-WebSocket-Protocol: chat
404 		 *
405 		 * we have to take some care here to only take from the
406 		 * socket bytewise.  The browser may (and has been seen to
407 		 * in the case that onopen() performs websocket traffic)
408 		 * coalesce both handshake response and websocket traffic
409 		 * in one packet, since at that point the connection is
410 		 * definitively ready from browser pov.
411 		 */
412 		while (wsi->http.ah->parser_state != WSI_PARSING_COMPLETE) {
413 			struct lws_tokens eb;
414 			int n, m, buffered;
415 
416 			eb.token = NULL;
417 			eb.len = 0;
418 			buffered = lws_buflist_aware_read(pt, wsi, &eb, 0, __func__);
419 			lwsl_debug("%s: buflist-aware-read %d %d\n", __func__,
420 					buffered, eb.len);
421 			if (eb.len == LWS_SSL_CAPABLE_MORE_SERVICE)
422 				return 0;
423 			if (buffered < 0 || eb.len < 0) {
424 				cce = "read failed";
425 				goto bail3;
426 			}
427 			if (!eb.len)
428 				return 0;
429 
430 			n = eb.len;
431 			if (lws_parse(wsi, eb.token, &n)) {
432 				lwsl_warn("problems parsing header\n");
433 				cce = "problems parsing header";
434 				goto bail3;
435 			}
436 
437 			m = eb.len - n;
438 			if (lws_buflist_aware_finished_consuming(wsi, &eb, m,
439 								 buffered,
440 								 __func__))
441 			        return -1;
442 			eb.token += m;
443 			eb.len -= m;
444 
445 			if (n) {
446 				assert(wsi->http.ah->parser_state ==
447 						WSI_PARSING_COMPLETE);
448 
449 				break;
450 			}
451 		}
452 
453 		/*
454 		 * hs may also be coming in multiple packets, there is a 5-sec
455 		 * libwebsocket timeout still active here too, so if parsing did
456 		 * not complete just wait for next packet coming in this state
457 		 */
458 		if (wsi->http.ah->parser_state != WSI_PARSING_COMPLETE)
459 			break;
460 #endif
461 
462 		/*
463 		 * otherwise deal with the handshake.  If there's any
464 		 * packet traffic already arrived we'll trigger poll() again
465 		 * right away and deal with it that way
466 		 */
467 		return lws_client_interpret_server_handshake(wsi);
468 
469 bail3:
470 		lwsl_info("closing conn at LWS_CONNMODE...SERVER_REPLY\n");
471 		if (cce)
472 			lwsl_info("reason: %s\n", cce);
473 		lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
474 
475 		lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "cbail3");
476 		return -1;
477 
478 	default:
479 		break;
480 	}
481 
482 	return 0;
483 }
484 
485 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
486 
487 int LWS_WARN_UNUSED_RESULT
lws_http_transaction_completed_client(struct lws * wsi)488 lws_http_transaction_completed_client(struct lws *wsi)
489 {
490 	int n;
491 
492 	lwsl_info("%s: wsi: %p (%s)\n", __func__, wsi, wsi->protocol->name);
493 
494 	if (user_callback_handle_rxflow(wsi->protocol->callback, wsi,
495 					LWS_CALLBACK_COMPLETED_CLIENT_HTTP,
496 					wsi->user_space, NULL, 0)) {
497 		lwsl_debug("%s: Completed call returned nonzero (role 0x%lx)\n",
498 			   __func__, (unsigned long)lwsi_role(wsi));
499 		return -1;
500 	}
501 
502 	wsi->http.rx_content_length = 0;
503 
504 	/*
505 	 * For h1, wsi may pass some assets on to a queued child and be
506 	 * destroyed during this.
507 	 */
508 	n = _lws_generic_transaction_completed_active_conn(&wsi);
509 
510 	if (wsi->http.ah) {
511 		if (wsi->client_mux_substream)
512 			/*
513 			 * As an h2 client, once we did our transaction, that is
514 			 * it for us.  Further transactions will happen as new
515 			 * SIDs on the connection.
516 			 */
517 			__lws_header_table_detach(wsi, 0);
518 		else
519 			if (!n)
520 				_lws_header_table_reset(wsi->http.ah);
521 	}
522 
523 	if (!n || !wsi->http.ah)
524 		return 0;
525 
526 	/*
527 	 * H1: we can serialize the queued guys into the same ah
528 	 * H2: everybody needs their own ah until their own STREAM_END
529 	 */
530 
531 	/* otherwise set ourselves up ready to go again */
532 	lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
533 
534 	wsi->http.ah->parser_state = WSI_TOKEN_NAME_PART;
535 	wsi->http.ah->lextable_pos = 0;
536 	wsi->http.ah->unk_pos = 0;
537 
538 	lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
539 			wsi->context->timeout_secs);
540 
541 	/* If we're (re)starting on headers, need other implied init */
542 	wsi->http.ah->ues = URIES_IDLE;
543 	lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2);
544 
545 	lwsl_info("%s: %p: new queued transaction\n", __func__, wsi);
546 	lws_callback_on_writable(wsi);
547 
548 	return 0;
549 }
550 
551 unsigned int
lws_http_client_http_response(struct lws * wsi)552 lws_http_client_http_response(struct lws *wsi)
553 {
554 	if (wsi->http.ah && wsi->http.ah->http_response)
555 		return wsi->http.ah->http_response;
556 
557 	return 0;
558 }
559 #endif
560 
561 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
562 
563 int
lws_http_is_redirected_to_get(struct lws * wsi)564 lws_http_is_redirected_to_get(struct lws *wsi)
565 {
566 	return wsi->redirected_to_get;
567 }
568 
569 int
lws_client_interpret_server_handshake(struct lws * wsi)570 lws_client_interpret_server_handshake(struct lws *wsi)
571 {
572 	int n, port = 0, ssl = 0;
573 	int close_reason = LWS_CLOSE_STATUS_PROTOCOL_ERR;
574 	const char *prot, *ads = NULL, *path, *cce = NULL;
575 	struct allocated_headers *ah, *ah1;
576 	struct lws *nwsi = lws_get_network_wsi(wsi);
577 	char *p = NULL, *q;
578 	char new_path[300];
579 
580 	lws_free_set_NULL(wsi->stash);
581 
582 	ah = wsi->http.ah;
583 	if (!wsi->do_ws) {
584 		/* we are being an http client...
585 		 */
586 #if defined(LWS_ROLE_H2)
587 		if (wsi->client_h2_alpn || wsi->client_mux_substream) {
588 			lwsl_debug("%s: %p: transitioning to h2 client\n",
589 				   __func__, wsi);
590 			lws_role_transition(wsi, LWSIFR_CLIENT,
591 					    LRS_ESTABLISHED, &role_ops_h2);
592 		} else
593 #endif
594 		{
595 #if defined(LWS_ROLE_H1)
596 			{
597 			lwsl_debug("%s: %p: transitioning to h1 client\n",
598 				   __func__, wsi);
599 			lws_role_transition(wsi, LWSIFR_CLIENT,
600 					    LRS_ESTABLISHED, &role_ops_h1);
601 			}
602 #else
603 			return -1;
604 #endif
605 		}
606 
607 		wsi->http.ah = ah;
608 		ah->http_response = 0;
609 	}
610 
611 	/*
612 	 * well, what the server sent looked reasonable for syntax.
613 	 * Now let's confirm it sent all the necessary headers
614 	 *
615 	 * http (non-ws) client will expect something like this
616 	 *
617 	 * HTTP/1.0.200
618 	 * server:.libwebsockets
619 	 * content-type:.text/html
620 	 * content-length:.17703
621 	 * set-cookie:.test=LWS_1456736240_336776_COOKIE;Max-Age=360000
622 	 */
623 
624 	wsi->http.conn_type = HTTP_CONNECTION_KEEP_ALIVE;
625 	if (!wsi->client_mux_substream) {
626 		p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP);
627 		/*
628 		if (wsi->do_ws && !p) {
629 			lwsl_info("no URI\n");
630 			cce = "HS: URI missing";
631 			goto bail3;
632 		}
633 		*/
634 		if (!p) {
635 			p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP1_0);
636 			wsi->http.conn_type = HTTP_CONNECTION_CLOSE;
637 		}
638 		if (!p) {
639 			cce = "HS: URI missing";
640 			lwsl_info("no URI\n");
641 			goto bail3;
642 		}
643 #if defined(LWS_ROLE_H2)
644 	} else {
645 		p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_STATUS);
646 		if (!p) {
647 			cce = "HS: :status missing";
648 			lwsl_info("no status\n");
649 			goto bail3;
650 		}
651 #endif
652 	}
653 #if !defined(LWS_ROLE_H2)
654 	if (!p) {
655 		cce = "HS: :status missing";
656 		lwsl_info("no status\n");
657 		goto bail3;
658 	}
659 #endif
660 	n = atoi(p);
661 	if (ah)
662 		ah->http_response = n;
663 
664 	if (!wsi->client_no_follow_redirect &&
665 #if defined(LWS_WITH_HTTP_PROXY)
666 	    !wsi->http.proxy_clientside &&
667 #endif
668 	    (n == 301 || n == 302 || n == 303 || n == 307 || n == 308)) {
669 		p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_LOCATION);
670 		if (!p) {
671 			cce = "HS: Redirect code but no Location";
672 			goto bail3;
673 		}
674 
675 		/*
676 		 * Some redirect codes imply we have to change the method
677 		 * used for the subsequent transaction, commonly POST ->
678 		 * 303 -> GET.
679 		 */
680 
681 		if (n == 303) {
682 			char *mp = lws_hdr_simple_ptr(wsi,_WSI_TOKEN_CLIENT_METHOD);
683 			int ml = lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_METHOD);
684 
685 			if (ml >= 3 && mp) {
686 				lwsl_info("%s: 303 switching to GET\n", __func__);
687 				memcpy(mp, "GET", 4);
688 				wsi->redirected_to_get = 1;
689 				wsi->http.ah->frags[wsi->http.ah->frag_index[
690 				             _WSI_TOKEN_CLIENT_METHOD]].len = 3;
691 			}
692 		}
693 
694 		/* Relative reference absolute path */
695 		if (p[0] == '/' || !strchr(p, ':')) {
696 #if defined(LWS_WITH_TLS)
697 			ssl = nwsi->tls.use_ssl & LCCSCF_USE_SSL;
698 #endif
699 			ads = lws_hdr_simple_ptr(wsi,
700 						 _WSI_TOKEN_CLIENT_PEER_ADDRESS);
701 			port = nwsi->c_port;
702 			path = p;
703 			/* lws_client_reset expects leading / omitted */
704 			if (*path == '/')
705 				path++;
706 		}
707 		/* Absolute (Full) URI */
708 		else if (strchr(p, ':')) {
709 			if (lws_parse_uri(p, &prot, &ads, &port, &path)) {
710 				cce = "HS: URI did not parse";
711 				goto bail3;
712 			}
713 
714 			if (!strcmp(prot, "wss") || !strcmp(prot, "https"))
715 				ssl = LCCSCF_USE_SSL;
716 		}
717 		/* Relative reference relative path */
718 		else {
719 			/* This doesn't try to calculate an absolute path,
720 			 * that will be left to the server */
721 #if defined(LWS_WITH_TLS)
722 			ssl = nwsi->tls.use_ssl & LCCSCF_USE_SSL;
723 #endif
724 			ads = lws_hdr_simple_ptr(wsi,
725 						 _WSI_TOKEN_CLIENT_PEER_ADDRESS);
726 			port = wsi->c_port;
727 			/* +1 as lws_client_reset expects leading / omitted */
728 			path = new_path + 1;
729 			if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI))
730 				lws_strncpy(new_path, lws_hdr_simple_ptr(wsi,
731 				   _WSI_TOKEN_CLIENT_URI), sizeof(new_path));
732 			else {
733 				new_path[0] = '/';
734 				new_path[1] = '\0';
735 			}
736 			q = strrchr(new_path, '/');
737 			if (q)
738 				lws_strncpy(q + 1, p, sizeof(new_path) -
739 							(q - new_path) - 1);
740 			else
741 				path = p;
742 		}
743 
744 #if defined(LWS_WITH_TLS)
745 		if ((wsi->tls.use_ssl & LCCSCF_USE_SSL) && !ssl) {
746 			cce = "HS: Redirect attempted SSL downgrade";
747 			goto bail3;
748 		}
749 #endif
750 
751 		if (!ads) /* make coverity happy */ {
752 			cce = "no ads";
753 			goto bail3;
754 		}
755 
756 		if (!lws_client_reset(&wsi, ssl, ads, port, path, ads, 1)) {
757 			/*
758 			 * There are two ways to fail out with NULL return...
759 			 * simple, early problem where the wsi is intact, or
760 			 * we went through with the reconnect attempt and the
761 			 * wsi is already closed.  In the latter case, the wsi
762 			 * has been set to NULL additionally.
763 			 */
764 			lwsl_err("Redirect failed\n");
765 			cce = "HS: Redirect failed";
766 			/* coverity[reverse_inull] */
767 			if (wsi)
768 				goto bail3;
769 
770 			/* wsi has closed */
771 			return 1;
772 		}
773 		return 0;
774 	}
775 
776 	if (!wsi->do_ws) {
777 
778 		/* if h1 KA is allowed, enable the queued pipeline guys */
779 
780 		if (!wsi->client_h2_alpn && !wsi->client_mux_substream) {
781 			/* ie, coming to this for the first time */
782 			if (wsi->http.conn_type == HTTP_CONNECTION_KEEP_ALIVE)
783 				wsi->keepalive_active = 1;
784 			else {
785 				/*
786 				 * Ugh... now the main http connection has seen
787 				 * both sides, we learn the server doesn't
788 				 * support keepalive.
789 				 *
790 				 * That means any guys queued on us are going
791 				 * to have to be restarted from connect2 with
792 				 * their own connections.
793 				 */
794 
795 				/*
796 				 * stick around telling any new guys they can't
797 				 * pipeline to this server
798 				 */
799 				wsi->keepalive_rejected = 1;
800 
801 				lws_vhost_lock(wsi->vhost);
802 				lws_start_foreach_dll_safe(struct lws_dll2 *,
803 							   d, d1,
804 				  wsi->dll2_cli_txn_queue_owner.head) {
805 					struct lws *ww = lws_container_of(d,
806 						struct lws,
807 						dll2_cli_txn_queue);
808 
809 					/* remove him from our queue */
810 					lws_dll2_remove(&ww->dll2_cli_txn_queue);
811 					/* give up on pipelining */
812 					ww->client_pipeline = 0;
813 
814 					/* go back to "trying to connect" state */
815 					lws_role_transition(ww, LWSIFR_CLIENT,
816 							    LRS_UNCONNECTED,
817 #if defined(LWS_ROLE_H1)
818 							    &role_ops_h1);
819 #else
820 #if defined (LWS_ROLE_H2)
821 							    &role_ops_h2);
822 #else
823 							    &role_ops_raw);
824 #endif
825 #endif
826 					ww->user_space = NULL;
827 				} lws_end_foreach_dll_safe(d, d1);
828 				lws_vhost_unlock(wsi->vhost);
829 			}
830 		}
831 
832 #ifdef LWS_WITH_HTTP_PROXY
833 		wsi->http.perform_rewrite = 0;
834 		if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)) {
835 			if (!strncmp(lws_hdr_simple_ptr(wsi,
836 						WSI_TOKEN_HTTP_CONTENT_TYPE),
837 						"text/html", 9))
838 				wsi->http.perform_rewrite = 0;
839 		}
840 #endif
841 
842 		/* allocate the per-connection user memory (if any) */
843 		if (lws_ensure_user_space(wsi)) {
844 			lwsl_err("Problem allocating wsi user mem\n");
845 			cce = "HS: OOM";
846 			goto bail2;
847 		}
848 
849 		/* he may choose to send us stuff in chunked transfer-coding */
850 		wsi->chunked = 0;
851 		wsi->chunk_remaining = 0; /* ie, next thing is chunk size */
852 		if (lws_hdr_total_length(wsi,
853 					WSI_TOKEN_HTTP_TRANSFER_ENCODING)) {
854 			wsi->chunked = !strcmp(lws_hdr_simple_ptr(wsi,
855 					       WSI_TOKEN_HTTP_TRANSFER_ENCODING),
856 						"chunked");
857 			/* first thing is hex, after payload there is crlf */
858 			wsi->chunk_parser = ELCP_HEX;
859 		}
860 
861 		wsi->http.content_length_given = 0;
862 		if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
863 			wsi->http.rx_content_length =
864 					atoll(lws_hdr_simple_ptr(wsi,
865 						WSI_TOKEN_HTTP_CONTENT_LENGTH));
866 			lwsl_info("%s: incoming content length %llu\n",
867 				    __func__, (unsigned long long)
868 					    wsi->http.rx_content_length);
869 			wsi->http.rx_content_remain =
870 					wsi->http.rx_content_length;
871 			wsi->http.content_length_given = 1;
872 		} else { /* can't do 1.1 without a content length or chunked */
873 			if (!wsi->chunked)
874 				wsi->http.conn_type = HTTP_CONNECTION_CLOSE;
875 			lwsl_debug("%s: no content length\n", __func__);
876 		}
877 
878 		/*
879 		 * we seem to be good to go, give client last chance to check
880 		 * headers and OK it
881 		 */
882 		ah1 = wsi->http.ah;
883 		wsi->http.ah = ah;
884 		if (wsi->protocol->callback(wsi,
885 				LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH,
886 					    wsi->user_space, NULL, 0)) {
887 			wsi->http.ah = ah1;
888 			cce = "HS: disallowed by client filter";
889 			goto bail2;
890 		}
891 
892 		/* clear his proxy connection timeout */
893 		lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
894 
895 		wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
896 
897 		/* call him back to inform him he is up */
898 		if (wsi->protocol->callback(wsi,
899 					    LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP,
900 					    wsi->user_space, NULL, 0)) {
901 			wsi->http.ah = ah1;
902 			cce = "HS: disallowed at ESTABLISHED";
903 			goto bail3;
904 		}
905 
906 		wsi->http.ah = ah1;
907 
908 		lwsl_info("%s: wsi %p: client connection up\n", __func__, wsi);
909 
910 		/*
911 		 * Did we get a response from the server with an explicit
912 		 * content-length of zero?  If so, this transaction is already
913 		 * completed at the end of the header processing...
914 		 */
915 		if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH) &&
916 		    !wsi->http.rx_content_length)
917 		        return !!lws_http_transaction_completed_client(wsi);
918 
919 		/*
920 		 * We can also get a case where it's http/1 and there's no
921 		 * content-length at all, so anything that comes is the body
922 		 * until it hangs up on us.  With that situation, hanging up
923 		 * on us past this point should generate a valid
924 		 * LWS_CALLBACK_COMPLETED_CLIENT_HTTP.
925 		 *
926 		 * In that situation, he can't pipeline because in h1 there's
927 		 * no post-header in-band way to signal the end of the
928 		 * transaction except hangup.
929 		 *
930 		 * lws_http_transaction_completed_client() is the right guy to
931 		 * issue it when we see the peer has hung up on us.
932 		 */
933 
934 		return 0;
935 	}
936 
937 #if defined(LWS_ROLE_WS)
938 	switch (lws_client_ws_upgrade(wsi, &cce)) {
939 	case 2:
940 		goto bail2;
941 	case 3:
942 		goto bail3;
943 	}
944 
945 	return 0;
946 #endif
947 
948 bail3:
949 	close_reason = LWS_CLOSE_STATUS_NOSTATUS;
950 
951 bail2:
952 	if (wsi->protocol) {
953 		n = 0;
954 		if (cce)
955 			n = (int)strlen(cce);
956 
957 		lws_inform_client_conn_fail(wsi, (void *)cce, (unsigned int)n);
958 	}
959 
960 	lwsl_info("closing connection (prot %s) "
961 		  "due to bail2 connection error: %s\n", wsi->protocol ?
962 				  wsi->protocol->name : "unknown", cce);
963 
964 	/* closing will free up his parsing allocations */
965 	lws_close_free_wsi(wsi, close_reason, "c hs interp");
966 
967 	return 1;
968 }
969 #endif
970 
971 /*
972  * set the boundary string and the content-type for client multipart mime
973  */
974 
975 uint8_t *
lws_http_multipart_headers(struct lws * wsi,uint8_t * p)976 lws_http_multipart_headers(struct lws *wsi, uint8_t *p)
977 {
978 	char buf[10], arg[48];
979 	int n;
980 
981 	lws_get_random(wsi->context, (uint8_t *)buf, sizeof(buf));
982 	lws_b64_encode_string(buf, sizeof(buf),
983 			       wsi->http.multipart_boundary,
984 			       sizeof(wsi->http.multipart_boundary));
985 
986 	n = lws_snprintf(arg, sizeof(arg), "multipart/form-data; boundary=\"%s\"",
987 			 wsi->http.multipart_boundary);
988 
989 	if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
990 					 (uint8_t *)arg, n, &p, p + 100))
991 		return NULL;
992 
993 	wsi->http.multipart = wsi->http.multipart_issue_boundary = 1;
994 	lws_client_http_body_pending(wsi, 1);
995 
996 	return p;
997 }
998 
999 int
lws_client_http_multipart(struct lws * wsi,const char * name,const char * filename,const char * content_type,char ** p,char * end)1000 lws_client_http_multipart(struct lws *wsi, const char *name,
1001 			  const char *filename, const char *content_type,
1002 			  char **p, char *end)
1003 {
1004 	/*
1005 	 * Client conn must have been created with LCCSCF_HTTP_MULTIPART_MIME
1006 	 * flag to use this api
1007 	 */
1008 	assert(wsi->http.multipart);
1009 
1010 	if (!name) {
1011 		*p += lws_snprintf((char *)(*p), lws_ptr_diff(end, p),
1012 					"\xd\xa--%s--\xd\xa",
1013 					wsi->http.multipart_boundary);
1014 
1015 		return 0;
1016 	}
1017 
1018 	if (wsi->client_subsequent_mime_part)
1019 		*p += lws_snprintf((char *)(*p), lws_ptr_diff(end, p), "\xd\xa");
1020 	wsi->client_subsequent_mime_part = 1;
1021 
1022 	*p += lws_snprintf((char *)(*p), lws_ptr_diff(end, p), "--%s\xd\xa"
1023 				    "Content-Disposition: form-data; "
1024 				      "name=\"%s\"",
1025 				      wsi->http.multipart_boundary, name);
1026 	if (filename)
1027 		*p += lws_snprintf((char *)(*p), lws_ptr_diff(end, p),
1028 				   "; filename=\"%s\"", filename);
1029 
1030 	if (content_type)
1031 		*p += lws_snprintf((char *)(*p), lws_ptr_diff(end, p), "\xd\xa"
1032 				"Content-Type: %s", content_type);
1033 
1034 	*p += lws_snprintf((char *)(*p), lws_ptr_diff(end, p), "\xd\xa\xd\xa");
1035 
1036 	return *p == end;
1037 }
1038 
1039 char *
lws_generate_client_handshake(struct lws * wsi,char * pkt)1040 lws_generate_client_handshake(struct lws *wsi, char *pkt)
1041 {
1042 	const char *meth, *pp = lws_hdr_simple_ptr(wsi,
1043 				_WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
1044 	char *p = pkt, *p1;
1045 
1046 	meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
1047 	if (!meth) {
1048 		meth = "GET";
1049 		wsi->do_ws = 1;
1050 	} else {
1051 		wsi->do_ws = 0;
1052 	}
1053 
1054 	if (!strcmp(meth, "RAW")) {
1055 		lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
1056 		lwsl_notice("client transition to raw\n");
1057 
1058 		if (pp) {
1059 			const struct lws_protocols *pr;
1060 
1061 			pr = lws_vhost_name_to_protocol(wsi->vhost, pp);
1062 
1063 			if (!pr) {
1064 				lwsl_err("protocol %s not enabled on vhost\n",
1065 					 pp);
1066 				return NULL;
1067 			}
1068 
1069 			lws_bind_protocol(wsi, pr, __func__);
1070 		}
1071 
1072 		if ((wsi->protocol->callback)(wsi, LWS_CALLBACK_RAW_ADOPT,
1073 					      wsi->user_space, NULL, 0))
1074 			return NULL;
1075 
1076 		lws_role_transition(wsi, LWSIFR_CLIENT, LRS_ESTABLISHED,
1077 				    &role_ops_raw_skt);
1078 		lws_header_table_detach(wsi, 1);
1079 
1080 		return NULL;
1081 	}
1082 
1083 	/*
1084 	 * 04 example client handshake
1085 	 *
1086 	 * GET /chat HTTP/1.1
1087 	 * Host: server.example.com
1088 	 * Upgrade: websocket
1089 	 * Connection: Upgrade
1090 	 * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
1091 	 * Sec-WebSocket-Origin: http://example.com
1092 	 * Sec-WebSocket-Protocol: chat, superchat
1093 	 * Sec-WebSocket-Version: 4
1094 	 */
1095 
1096 	p += lws_snprintf(p, 2048, "%s %s HTTP/1.1\x0d\x0a", meth,
1097 		     lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI));
1098 
1099 	p += lws_snprintf(p, 64, "Pragma: no-cache\x0d\x0a"
1100 			"Cache-Control: no-cache\x0d\x0a");
1101 
1102 	p += lws_snprintf(p, 128, "Host: %s\x0d\x0a",
1103 		     lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST));
1104 
1105 	if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN)) {
1106 		if (lws_check_opt(wsi->context->options,
1107 				  LWS_SERVER_OPTION_JUST_USE_RAW_ORIGIN))
1108 			p += lws_snprintf(p, 128, "Origin: %s\x0d\x0a",
1109 				     lws_hdr_simple_ptr(wsi,
1110 						     _WSI_TOKEN_CLIENT_ORIGIN));
1111 		else
1112 			p += lws_snprintf(p, 128, "Origin: http://%s\x0d\x0a",
1113 				     lws_hdr_simple_ptr(wsi,
1114 						     _WSI_TOKEN_CLIENT_ORIGIN));
1115 	}
1116 
1117 	if (wsi->flags & LCCSCF_HTTP_MULTIPART_MIME) {
1118 		p1 = (char *)lws_http_multipart_headers(wsi, (uint8_t *)p);
1119 		if (!p1)
1120 			return NULL;
1121 		p = p1;
1122 	}
1123 
1124 #if defined(LWS_WITH_HTTP_PROXY)
1125 	if (wsi->parent &&
1126 	    lws_hdr_total_length(wsi->parent, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
1127 		p += lws_snprintf(p, 128, "Content-Length: %s\x0d\x0a",
1128 			lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_CONTENT_LENGTH));
1129 		if (atoi(lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_CONTENT_LENGTH)))
1130 			wsi->client_http_body_pending = 1;
1131 	}
1132 	if (wsi->parent &&
1133 	    lws_hdr_total_length(wsi->parent, WSI_TOKEN_HTTP_AUTHORIZATION)) {
1134 		p += lws_snprintf(p, 128, "Authorization: %s\x0d\x0a",
1135 			lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_AUTHORIZATION));
1136 	}
1137 	if (wsi->parent &&
1138 	    lws_hdr_total_length(wsi->parent, WSI_TOKEN_HTTP_CONTENT_TYPE)) {
1139 		p += lws_snprintf(p, 128, "Content-Type: %s\x0d\x0a",
1140 			lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_CONTENT_TYPE));
1141 	}
1142 #endif
1143 
1144 #if defined(LWS_ROLE_WS)
1145 	if (wsi->do_ws) {
1146 		const char *conn1 = "";
1147 	//	if (!wsi->client_pipeline)
1148 	//		conn1 = "close, ";
1149 		p = lws_generate_client_ws_handshake(wsi, p, conn1);
1150 	} else
1151 #endif
1152 	{
1153 		if (!wsi->client_pipeline)
1154 			p += lws_snprintf(p, 64, "connection: close\x0d\x0a");
1155 	}
1156 
1157 	/* give userland a chance to append, eg, cookies */
1158 
1159 	if (wsi->protocol->callback(wsi,
1160 			LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
1161 			wsi->user_space, &p,
1162 			(pkt + wsi->context->pt_serv_buf_size) - p - 12))
1163 		return NULL;
1164 
1165 	if (wsi->flags & LCCSCF_HTTP_X_WWW_FORM_URLENCODED) {
1166 		p += lws_snprintf(p, 128, "Content-Type: application/x-www-form-urlencoded\x0d\x0a");
1167 		p += lws_snprintf(p, 128, "Content-Length: %lu\x0d\x0a", wsi->http.writeable_len);
1168 		lws_client_http_body_pending(wsi, 1);
1169 	}
1170 
1171 	p += lws_snprintf(p, 4, "\x0d\x0a");
1172 
1173 	if (wsi->client_http_body_pending)
1174 		lws_callback_on_writable(wsi);
1175 
1176 	// puts(pkt);
1177 
1178 	return p;
1179 }
1180 
1181 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
1182 #if defined(LWS_WITH_HTTP_BASIC_AUTH)
1183 
1184 int
lws_http_basic_auth_gen(const char * user,const char * pw,char * buf,size_t len)1185 lws_http_basic_auth_gen(const char *user, const char *pw, char *buf, size_t len)
1186 {
1187 	size_t n = strlen(user), m = strlen(pw);
1188 	char b[128];
1189 
1190 	if (len < 6 + ((4 * (n + m + 1)) / 3) + 1)
1191 		return 1;
1192 
1193 	memcpy(buf, "Basic ", 6);
1194 
1195 	n = lws_snprintf(b, sizeof(b), "%s:%s", user, pw);
1196 	if (n >= sizeof(b) - 2)
1197 		return 2;
1198 
1199 	lws_b64_encode_string(b, (int)n, buf + 6, (int)len - 6);
1200 	buf[len - 1] = '\0';
1201 
1202 	return 0;
1203 }
1204 
1205 #endif
1206 
1207 int
lws_http_client_read(struct lws * wsi,char ** buf,int * len)1208 lws_http_client_read(struct lws *wsi, char **buf, int *len)
1209 {
1210 	struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
1211 	struct lws_tokens eb;
1212 	int buffered, n, consumed = 0;
1213 
1214 	/*
1215 	 * If the caller provided a non-NULL *buf and nonzero *len, we should
1216 	 * use that as the buffer for the read action, limititing it to *len
1217 	 * (actual payload will be less if chunked headers inside).
1218 	 *
1219 	 * If it's NULL / 0 length, buflist_aware_read will use the pt_serv_buf
1220 	 */
1221 
1222 	eb.token = (unsigned char *)*buf;
1223 	eb.len = *len;
1224 
1225 	buffered = lws_buflist_aware_read(pt, wsi, &eb, 0, __func__);
1226 	*buf = (char *)eb.token; /* may be pointing to buflist or pt_serv_buf */
1227 	*len = 0;
1228 
1229 	/*
1230 	 * we're taking on responsibility for handling used / unused eb
1231 	 * when we leave, via lws_buflist_aware_finished_consuming()
1232 	 */
1233 
1234 //	lwsl_notice("%s: eb.len %d ENTRY chunk remaining %d\n", __func__, eb.len,
1235 //			wsi->chunk_remaining);
1236 
1237 	/* allow the source to signal he has data again next time */
1238 	if (lws_change_pollfd(wsi, 0, LWS_POLLIN))
1239 		return -1;
1240 
1241 	if (buffered < 0) {
1242 		lwsl_debug("%s: SSL capable error\n", __func__);
1243 
1244 		if (wsi->http.ah &&
1245 		    wsi->http.ah->parser_state == WSI_PARSING_COMPLETE &&
1246 		    !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH))
1247 			/*
1248 			 * We had the headers from this stream, but as there
1249 			 * was no content-length: we had to wait until the
1250 			 * stream ended to inform the user code the transaction
1251 			 * has completed to the best of our knowledge
1252 			 */
1253 			if (lws_http_transaction_completed_client(wsi))
1254 				/*
1255 				 * We're going to close anyway, but that api has
1256 				 * warn_unused_result
1257 				 */
1258 				return -1;
1259 
1260 		return -1;
1261 	}
1262 
1263 	if (eb.len <= 0)
1264 		return 0;
1265 
1266 	*len = eb.len;
1267 	wsi->client_rx_avail = 0;
1268 
1269 	/*
1270 	 * server may insist on transfer-encoding: chunked,
1271 	 * so http client must deal with it
1272 	 */
1273 spin_chunks:
1274 	//lwsl_notice("%s: len %d SPIN chunk remaining %d\n", __func__, *len,
1275 	//		wsi->chunk_remaining);
1276 	while (wsi->chunked && (wsi->chunk_parser != ELCP_CONTENT) && *len) {
1277 		switch (wsi->chunk_parser) {
1278 		case ELCP_HEX:
1279 			if ((*buf)[0] == '\x0d') {
1280 				wsi->chunk_parser = ELCP_CR;
1281 				break;
1282 			}
1283 			n = char_to_hex((*buf)[0]);
1284 			if (n < 0) {
1285 				lwsl_err("%s: chunking failure A\n", __func__);
1286 				return -1;
1287 			}
1288 			wsi->chunk_remaining <<= 4;
1289 			wsi->chunk_remaining |= n;
1290 			break;
1291 		case ELCP_CR:
1292 			if ((*buf)[0] != '\x0a') {
1293 				lwsl_err("%s: chunking failure B\n", __func__);
1294 				return -1;
1295 			}
1296 			if (wsi->chunk_remaining) {
1297 				wsi->chunk_parser = ELCP_CONTENT;
1298 				//lwsl_notice("starting chunk size %d (block rem %d)\n",
1299 				//		wsi->chunk_remaining, *len);
1300 				break;
1301 			}
1302 
1303 			wsi->chunk_parser = ELCP_TRAILER_CR;
1304 			break;
1305 
1306 		case ELCP_CONTENT:
1307 			break;
1308 
1309 		case ELCP_POST_CR:
1310 			if ((*buf)[0] != '\x0d') {
1311 				lwsl_err("%s: chunking failure C\n", __func__);
1312 				lwsl_hexdump_err(*buf, *len);
1313 
1314 				return -1;
1315 			}
1316 
1317 			wsi->chunk_parser = ELCP_POST_LF;
1318 			break;
1319 
1320 		case ELCP_POST_LF:
1321 			if ((*buf)[0] != '\x0a') {
1322 				lwsl_err("%s: chunking failure D\n", __func__);
1323 
1324 				return -1;
1325 			}
1326 
1327 			wsi->chunk_parser = ELCP_HEX;
1328 			wsi->chunk_remaining = 0;
1329 			break;
1330 
1331 		case ELCP_TRAILER_CR:
1332 			if ((*buf)[0] != '\x0d') {
1333 				lwsl_err("%s: chunking failure F\n", __func__);
1334 				lwsl_hexdump_err(*buf, *len);
1335 
1336 				return -1;
1337 			}
1338 
1339 			wsi->chunk_parser = ELCP_TRAILER_LF;
1340 			break;
1341 
1342 		case ELCP_TRAILER_LF:
1343 			if ((*buf)[0] != '\x0a') {
1344 				lwsl_err("%s: chunking failure F\n", __func__);
1345 				lwsl_hexdump_err(*buf, *len);
1346 
1347 				return -1;
1348 			}
1349 
1350 			(*buf)++;
1351 			(*len)--;
1352 			consumed++;
1353 
1354 			lwsl_info("final chunk\n");
1355 			goto completed;
1356 		}
1357 		(*buf)++;
1358 		(*len)--;
1359 		consumed++;
1360 	}
1361 
1362 	if (wsi->chunked && !wsi->chunk_remaining)
1363 		goto account_and_ret;
1364 
1365 	if (wsi->http.rx_content_remain &&
1366 	    wsi->http.rx_content_remain < (unsigned int)*len)
1367 		n = (int)wsi->http.rx_content_remain;
1368 	else
1369 		n = *len;
1370 
1371 	if (wsi->chunked && wsi->chunk_remaining &&
1372 	    wsi->chunk_remaining < n)
1373 		n = wsi->chunk_remaining;
1374 
1375 #if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_WITH_HUBBUB)
1376 	/* hubbub */
1377 	if (wsi->http.perform_rewrite)
1378 		lws_rewrite_parse(wsi->http.rw, (unsigned char *)*buf, n);
1379 	else
1380 #endif
1381 	{
1382 		if (
1383 #if defined(LWS_WITH_HTTP_PROXY)
1384 		    !wsi->protocol_bind_balance ==
1385 		    !!wsi->http.proxy_clientside
1386 #else
1387 		    !!wsi->protocol_bind_balance
1388 #endif
1389 		  ) {
1390 			if (user_callback_handle_rxflow(wsi->protocol->callback,
1391 				wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,
1392 				wsi->user_space, *buf, n)) {
1393 				lwsl_info("%s: RECEIVE_CLIENT_HTTP_READ returned -1\n",
1394 						__func__);
1395 
1396 				return -1;
1397 			}
1398 		} else
1399 			lwsl_notice("%s: swallowed read (%d)\n", __func__, n);
1400 	}
1401 
1402 	(*buf) += n;
1403 	*len -= n;
1404 	if (wsi->chunked && wsi->chunk_remaining)
1405 		wsi->chunk_remaining -= n;
1406 
1407 	//lwsl_notice("chunk_remaining <- %d, block remaining %d\n",
1408 	//		wsi->chunk_remaining, *len);
1409 
1410 	consumed += n;
1411 	//eb.token += n;
1412 	//eb.len -= n;
1413 
1414 	if (wsi->chunked && !wsi->chunk_remaining)
1415 		wsi->chunk_parser = ELCP_POST_CR;
1416 
1417 	if (wsi->chunked && *len)
1418 		goto spin_chunks;
1419 
1420 	if (wsi->chunked)
1421 		goto account_and_ret;
1422 
1423 	/* if we know the content length, decrement the content remaining */
1424 	if (wsi->http.rx_content_length > 0)
1425 		wsi->http.rx_content_remain -= n;
1426 
1427 	// lwsl_notice("rx_content_remain %lld, rx_content_length %lld, giv %d\n",
1428 	//	    wsi->http.rx_content_remain, wsi->http.rx_content_length,
1429 	//	    wsi->http.content_length_given);
1430 
1431 	if (wsi->http.rx_content_remain || !wsi->http.content_length_given)
1432 		goto account_and_ret;
1433 
1434 completed:
1435 
1436 	if (lws_http_transaction_completed_client(wsi)) {
1437 		lwsl_notice("%s: transaction completed says -1\n", __func__);
1438 		return -1;
1439 	}
1440 
1441 account_and_ret:
1442 //	lwsl_warn("%s: on way out, consuming %d / %d\n", __func__, consumed, eb.len);
1443 	if (lws_buflist_aware_finished_consuming(wsi, &eb, consumed, buffered,
1444 							__func__))
1445 		return -1;
1446 
1447 	return 0;
1448 }
1449 
1450 #endif
1451