1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to
8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the
9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions:
12d4afb5ceSopenharmony_ci *
13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in
14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software.
15d4afb5ceSopenharmony_ci *
16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22d4afb5ceSopenharmony_ci * IN THE SOFTWARE.
23d4afb5ceSopenharmony_ci */
24d4afb5ceSopenharmony_ci
25d4afb5ceSopenharmony_ci#include "private-lib-core.h"
26d4afb5ceSopenharmony_ci
27d4afb5ceSopenharmony_ci/* max individual proxied header payload size */
28d4afb5ceSopenharmony_ci#define MAXHDRVAL 1024
29d4afb5ceSopenharmony_ci
30d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_PROXY)
31d4afb5ceSopenharmony_cistatic int
32d4afb5ceSopenharmony_ciproxy_header(struct lws *wsi, struct lws *par, unsigned char *temp,
33d4afb5ceSopenharmony_ci	     int temp_len, int index, unsigned char **p, unsigned char *end)
34d4afb5ceSopenharmony_ci{
35d4afb5ceSopenharmony_ci	int n = lws_hdr_total_length(par, (enum lws_token_indexes)index);
36d4afb5ceSopenharmony_ci
37d4afb5ceSopenharmony_ci	if (n < 1) {
38d4afb5ceSopenharmony_ci		lwsl_wsi_debug(wsi, "no index %d:", index);
39d4afb5ceSopenharmony_ci
40d4afb5ceSopenharmony_ci		return 0;
41d4afb5ceSopenharmony_ci	}
42d4afb5ceSopenharmony_ci
43d4afb5ceSopenharmony_ci	if (lws_hdr_copy(par, (char *)temp, temp_len, (enum lws_token_indexes)index) < 0) {
44d4afb5ceSopenharmony_ci		lwsl_wsi_notice(wsi, "unable to copy par hdr idx %d (len %d)",
45d4afb5ceSopenharmony_ci				      index, n);
46d4afb5ceSopenharmony_ci		return -1;
47d4afb5ceSopenharmony_ci	}
48d4afb5ceSopenharmony_ci
49d4afb5ceSopenharmony_ci	lwsl_wsi_debug(wsi, "index %d: %s", index, (char *)temp);
50d4afb5ceSopenharmony_ci
51d4afb5ceSopenharmony_ci	if (lws_add_http_header_by_token(wsi, (enum lws_token_indexes)index, temp, n, p, end)) {
52d4afb5ceSopenharmony_ci		lwsl_wsi_notice(wsi, "unable to append par hdr idx %d (len %d)",
53d4afb5ceSopenharmony_ci				     index, n);
54d4afb5ceSopenharmony_ci		return -1;
55d4afb5ceSopenharmony_ci	}
56d4afb5ceSopenharmony_ci
57d4afb5ceSopenharmony_ci	return 0;
58d4afb5ceSopenharmony_ci}
59d4afb5ceSopenharmony_ci
60d4afb5ceSopenharmony_cistatic int
61d4afb5ceSopenharmony_cistream_close(struct lws *wsi)
62d4afb5ceSopenharmony_ci{
63d4afb5ceSopenharmony_ci	char buf[LWS_PRE + 6], *out = buf + LWS_PRE;
64d4afb5ceSopenharmony_ci
65d4afb5ceSopenharmony_ci	if (wsi->http.did_stream_close)
66d4afb5ceSopenharmony_ci		return 0;
67d4afb5ceSopenharmony_ci
68d4afb5ceSopenharmony_ci	wsi->http.did_stream_close = 1;
69d4afb5ceSopenharmony_ci
70d4afb5ceSopenharmony_ci	if (wsi->mux_substream) {
71d4afb5ceSopenharmony_ci		if (lws_write(wsi, (unsigned char *)buf + LWS_PRE, 0,
72d4afb5ceSopenharmony_ci			      LWS_WRITE_HTTP_FINAL) < 0)
73d4afb5ceSopenharmony_ci			goto bail;
74d4afb5ceSopenharmony_ci
75d4afb5ceSopenharmony_ci		return 0;
76d4afb5ceSopenharmony_ci	}
77d4afb5ceSopenharmony_ci
78d4afb5ceSopenharmony_ci	*out++ = '0';
79d4afb5ceSopenharmony_ci	*out++ = '\x0d';
80d4afb5ceSopenharmony_ci	*out++ = '\x0a';
81d4afb5ceSopenharmony_ci	*out++ = '\x0d';
82d4afb5ceSopenharmony_ci	*out++ = '\x0a';
83d4afb5ceSopenharmony_ci
84d4afb5ceSopenharmony_ci	if (lws_write(wsi, (unsigned char *)buf + LWS_PRE, 5,
85d4afb5ceSopenharmony_ci		      LWS_WRITE_HTTP_FINAL) < 0)
86d4afb5ceSopenharmony_ci		goto bail;
87d4afb5ceSopenharmony_ci
88d4afb5ceSopenharmony_ci	return 0;
89d4afb5ceSopenharmony_ci
90d4afb5ceSopenharmony_cibail:
91d4afb5ceSopenharmony_ci	lwsl_wsi_info(wsi, "h2 fin wr failed");
92d4afb5ceSopenharmony_ci
93d4afb5ceSopenharmony_ci	return -1;
94d4afb5ceSopenharmony_ci}
95d4afb5ceSopenharmony_ci
96d4afb5ceSopenharmony_ci#endif
97d4afb5ceSopenharmony_ci
98d4afb5ceSopenharmony_cistruct lws_proxy_pkt {
99d4afb5ceSopenharmony_ci	struct lws_dll2 pkt_list;
100d4afb5ceSopenharmony_ci	size_t len;
101d4afb5ceSopenharmony_ci	char binary;
102d4afb5ceSopenharmony_ci	char first;
103d4afb5ceSopenharmony_ci	char final;
104d4afb5ceSopenharmony_ci
105d4afb5ceSopenharmony_ci	/* data follows */
106d4afb5ceSopenharmony_ci};
107d4afb5ceSopenharmony_ci
108d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_ROLE_WS)
109d4afb5ceSopenharmony_ciint
110d4afb5ceSopenharmony_cilws_callback_ws_proxy(struct lws *wsi, enum lws_callback_reasons reason,
111d4afb5ceSopenharmony_ci			void *user, void *in, size_t len)
112d4afb5ceSopenharmony_ci{
113d4afb5ceSopenharmony_ci	struct lws_proxy_pkt *pkt;
114d4afb5ceSopenharmony_ci	struct lws_dll2 *dll;
115d4afb5ceSopenharmony_ci
116d4afb5ceSopenharmony_ci	switch (reason) {
117d4afb5ceSopenharmony_ci
118d4afb5ceSopenharmony_ci	/* h1 ws proxying... child / client / onward */
119d4afb5ceSopenharmony_ci
120d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLIENT_ESTABLISHED:
121d4afb5ceSopenharmony_ci		if (!wsi->h1_ws_proxied || !wsi->parent)
122d4afb5ceSopenharmony_ci			break;
123d4afb5ceSopenharmony_ci
124d4afb5ceSopenharmony_ci		if (lws_process_ws_upgrade2(wsi->parent))
125d4afb5ceSopenharmony_ci			return -1;
126d4afb5ceSopenharmony_ci
127d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP2)
128d4afb5ceSopenharmony_ci		if (wsi->parent->mux_substream)
129d4afb5ceSopenharmony_ci			lwsl_wsi_info(wsi, "proxied h2 -> h1 ws established");
130d4afb5ceSopenharmony_ci#endif
131d4afb5ceSopenharmony_ci		break;
132d4afb5ceSopenharmony_ci
133d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED:
134d4afb5ceSopenharmony_ci		return 1;
135d4afb5ceSopenharmony_ci
136d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
137d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLIENT_CLOSED:
138d4afb5ceSopenharmony_ci		lwsl_wsi_info(wsi, "client closed: parent %s",
139d4afb5ceSopenharmony_ci				   lws_wsi_tag(wsi->parent));
140d4afb5ceSopenharmony_ci		if (wsi->parent)
141d4afb5ceSopenharmony_ci                       lws_set_timeout(wsi->parent, 1, LWS_TO_KILL_ASYNC);
142d4afb5ceSopenharmony_ci		break;
143d4afb5ceSopenharmony_ci
144d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
145d4afb5ceSopenharmony_ci	{
146d4afb5ceSopenharmony_ci		unsigned char **p = (unsigned char **)in, *end = (*p) + len,
147d4afb5ceSopenharmony_ci				    tmp[MAXHDRVAL];
148d4afb5ceSopenharmony_ci
149d4afb5ceSopenharmony_ci		proxy_header(wsi, wsi->parent, tmp, sizeof(tmp),
150d4afb5ceSopenharmony_ci			      WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, p, end);
151d4afb5ceSopenharmony_ci
152d4afb5ceSopenharmony_ci		proxy_header(wsi, wsi->parent, tmp, sizeof(tmp),
153d4afb5ceSopenharmony_ci			      WSI_TOKEN_HTTP_COOKIE, p, end);
154d4afb5ceSopenharmony_ci
155d4afb5ceSopenharmony_ci		proxy_header(wsi, wsi->parent, tmp, sizeof(tmp),
156d4afb5ceSopenharmony_ci			      WSI_TOKEN_HTTP_SET_COOKIE, p, end);
157d4afb5ceSopenharmony_ci		break;
158d4afb5ceSopenharmony_ci	}
159d4afb5ceSopenharmony_ci
160d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLIENT_RECEIVE:
161d4afb5ceSopenharmony_ci		wsi->parent->ws->proxy_buffered += len;
162d4afb5ceSopenharmony_ci		if (wsi->parent->ws->proxy_buffered > 10 * 1024 * 1024) {
163d4afb5ceSopenharmony_ci			lwsl_wsi_err(wsi, "proxied ws connection "
164d4afb5ceSopenharmony_ci					  "excessive buffering: dropping");
165d4afb5ceSopenharmony_ci			return -1;
166d4afb5ceSopenharmony_ci		}
167d4afb5ceSopenharmony_ci		pkt = lws_zalloc(sizeof(*pkt) + LWS_PRE + len, __func__);
168d4afb5ceSopenharmony_ci		if (!pkt)
169d4afb5ceSopenharmony_ci			return -1;
170d4afb5ceSopenharmony_ci
171d4afb5ceSopenharmony_ci		pkt->len = len;
172d4afb5ceSopenharmony_ci		pkt->first = (char)lws_is_first_fragment(wsi);
173d4afb5ceSopenharmony_ci		pkt->final = (char)lws_is_final_fragment(wsi);
174d4afb5ceSopenharmony_ci		pkt->binary = (char)lws_frame_is_binary(wsi);
175d4afb5ceSopenharmony_ci
176d4afb5ceSopenharmony_ci		memcpy(((uint8_t *)&pkt[1]) + LWS_PRE, in, len);
177d4afb5ceSopenharmony_ci
178d4afb5ceSopenharmony_ci		lws_dll2_add_tail(&pkt->pkt_list, &wsi->parent->ws->proxy_owner);
179d4afb5ceSopenharmony_ci		lws_callback_on_writable(wsi->parent);
180d4afb5ceSopenharmony_ci		break;
181d4afb5ceSopenharmony_ci
182d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLIENT_WRITEABLE:
183d4afb5ceSopenharmony_ci		dll = lws_dll2_get_head(&wsi->ws->proxy_owner);
184d4afb5ceSopenharmony_ci		if (!dll)
185d4afb5ceSopenharmony_ci			break;
186d4afb5ceSopenharmony_ci
187d4afb5ceSopenharmony_ci		pkt = (struct lws_proxy_pkt *)dll;
188d4afb5ceSopenharmony_ci		if (lws_write(wsi, ((unsigned char *)&pkt[1]) +
189d4afb5ceSopenharmony_ci			      LWS_PRE, pkt->len, (enum lws_write_protocol)lws_write_ws_flags(
190d4afb5ceSopenharmony_ci				pkt->binary ? LWS_WRITE_BINARY : LWS_WRITE_TEXT,
191d4afb5ceSopenharmony_ci					pkt->first, pkt->final)) < 0)
192d4afb5ceSopenharmony_ci			return -1;
193d4afb5ceSopenharmony_ci
194d4afb5ceSopenharmony_ci		lws_dll2_remove(dll);
195d4afb5ceSopenharmony_ci		lws_free(pkt);
196d4afb5ceSopenharmony_ci
197d4afb5ceSopenharmony_ci		if (lws_dll2_get_head(&wsi->ws->proxy_owner))
198d4afb5ceSopenharmony_ci			lws_callback_on_writable(wsi);
199d4afb5ceSopenharmony_ci		break;
200d4afb5ceSopenharmony_ci
201d4afb5ceSopenharmony_ci	/* h1 ws proxying... parent / server / incoming */
202d4afb5ceSopenharmony_ci
203d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CONFIRM_EXTENSION_OKAY:
204d4afb5ceSopenharmony_ci		return 1;
205d4afb5ceSopenharmony_ci
206d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLOSED:
207d4afb5ceSopenharmony_ci		lwsl_wsi_info(wsi, "closed");
208d4afb5ceSopenharmony_ci		return -1;
209d4afb5ceSopenharmony_ci
210d4afb5ceSopenharmony_ci	case LWS_CALLBACK_RECEIVE:
211d4afb5ceSopenharmony_ci		pkt = lws_zalloc(sizeof(*pkt) + LWS_PRE + len, __func__);
212d4afb5ceSopenharmony_ci		if (!pkt)
213d4afb5ceSopenharmony_ci			return -1;
214d4afb5ceSopenharmony_ci
215d4afb5ceSopenharmony_ci		pkt->len = len;
216d4afb5ceSopenharmony_ci		pkt->first = (char)lws_is_first_fragment(wsi);
217d4afb5ceSopenharmony_ci		pkt->final = (char)lws_is_final_fragment(wsi);
218d4afb5ceSopenharmony_ci		pkt->binary = (char)lws_frame_is_binary(wsi);
219d4afb5ceSopenharmony_ci
220d4afb5ceSopenharmony_ci		memcpy(((uint8_t *)&pkt[1]) + LWS_PRE, in, len);
221d4afb5ceSopenharmony_ci
222d4afb5ceSopenharmony_ci		lws_dll2_add_tail(&pkt->pkt_list, &wsi->child_list->ws->proxy_owner);
223d4afb5ceSopenharmony_ci		lws_callback_on_writable(wsi->child_list);
224d4afb5ceSopenharmony_ci		break;
225d4afb5ceSopenharmony_ci
226d4afb5ceSopenharmony_ci	case LWS_CALLBACK_SERVER_WRITEABLE:
227d4afb5ceSopenharmony_ci		dll = lws_dll2_get_head(&wsi->ws->proxy_owner);
228d4afb5ceSopenharmony_ci		if (!dll)
229d4afb5ceSopenharmony_ci			break;
230d4afb5ceSopenharmony_ci
231d4afb5ceSopenharmony_ci		pkt = (struct lws_proxy_pkt *)dll;
232d4afb5ceSopenharmony_ci		if (lws_write(wsi, ((unsigned char *)&pkt[1]) +
233d4afb5ceSopenharmony_ci			      LWS_PRE, pkt->len, (enum lws_write_protocol)lws_write_ws_flags(
234d4afb5ceSopenharmony_ci				pkt->binary ? LWS_WRITE_BINARY : LWS_WRITE_TEXT,
235d4afb5ceSopenharmony_ci					pkt->first, pkt->final)) < 0)
236d4afb5ceSopenharmony_ci			return -1;
237d4afb5ceSopenharmony_ci
238d4afb5ceSopenharmony_ci		wsi->ws->proxy_buffered -= pkt->len;
239d4afb5ceSopenharmony_ci
240d4afb5ceSopenharmony_ci		lws_dll2_remove(dll);
241d4afb5ceSopenharmony_ci		lws_free(pkt);
242d4afb5ceSopenharmony_ci
243d4afb5ceSopenharmony_ci		if (lws_dll2_get_head(&wsi->ws->proxy_owner))
244d4afb5ceSopenharmony_ci			lws_callback_on_writable(wsi);
245d4afb5ceSopenharmony_ci		break;
246d4afb5ceSopenharmony_ci
247d4afb5ceSopenharmony_ci	default:
248d4afb5ceSopenharmony_ci		return 0;
249d4afb5ceSopenharmony_ci	}
250d4afb5ceSopenharmony_ci
251d4afb5ceSopenharmony_ci	return 0;
252d4afb5ceSopenharmony_ci}
253d4afb5ceSopenharmony_ci
254d4afb5ceSopenharmony_ciconst struct lws_protocols lws_ws_proxy = {
255d4afb5ceSopenharmony_ci		"lws-ws-proxy",
256d4afb5ceSopenharmony_ci		lws_callback_ws_proxy,
257d4afb5ceSopenharmony_ci		0,
258d4afb5ceSopenharmony_ci		8192,
259d4afb5ceSopenharmony_ci		8192, NULL, 0
260d4afb5ceSopenharmony_ci};
261d4afb5ceSopenharmony_ci
262d4afb5ceSopenharmony_ci#endif
263d4afb5ceSopenharmony_ci
264d4afb5ceSopenharmony_ci
265d4afb5ceSopenharmony_ciint
266d4afb5ceSopenharmony_cilws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
267d4afb5ceSopenharmony_ci			void *user, void *in, size_t len)
268d4afb5ceSopenharmony_ci{
269d4afb5ceSopenharmony_ci	struct lws_ssl_info *si;
270d4afb5ceSopenharmony_ci#ifdef LWS_WITH_CGI
271d4afb5ceSopenharmony_ci	struct lws_cgi_args *args;
272d4afb5ceSopenharmony_ci#endif
273d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CGI) || defined(LWS_WITH_HTTP_PROXY)
274d4afb5ceSopenharmony_ci	char buf[LWS_PRE + 32 + 8192];
275d4afb5ceSopenharmony_ci	int n;
276d4afb5ceSopenharmony_ci#endif
277d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_PROXY)
278d4afb5ceSopenharmony_ci	unsigned char **p, *end;
279d4afb5ceSopenharmony_ci	struct lws *parent;
280d4afb5ceSopenharmony_ci#endif
281d4afb5ceSopenharmony_ci
282d4afb5ceSopenharmony_ci	switch (reason) {
283d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
284d4afb5ceSopenharmony_ci	case LWS_CALLBACK_HTTP:
285d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
286d4afb5ceSopenharmony_ci		if (lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL))
287d4afb5ceSopenharmony_ci			return -1;
288d4afb5ceSopenharmony_ci
289d4afb5ceSopenharmony_ci		if (lws_http_transaction_completed(wsi))
290d4afb5ceSopenharmony_ci#endif
291d4afb5ceSopenharmony_ci			return -1;
292d4afb5ceSopenharmony_ci		break;
293d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
294d4afb5ceSopenharmony_ci	case LWS_CALLBACK_HTTP_BODY_COMPLETION:
295d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_PROXY)
296d4afb5ceSopenharmony_ci		if (wsi->child_list) {
297d4afb5ceSopenharmony_ci			lwsl_wsi_info(wsi, "HTTP_BODY_COMPLETION: %d",
298d4afb5ceSopenharmony_ci					   (int)len);
299d4afb5ceSopenharmony_ci			lws_callback_on_writable(wsi->child_list);
300d4afb5ceSopenharmony_ci			break;
301d4afb5ceSopenharmony_ci		}
302d4afb5ceSopenharmony_ci#endif
303d4afb5ceSopenharmony_ci		if (lws_return_http_status(wsi, 200, NULL))
304d4afb5ceSopenharmony_ci			return -1;
305d4afb5ceSopenharmony_ci		break;
306d4afb5ceSopenharmony_ci
307d4afb5ceSopenharmony_ci		/* fallthru */
308d4afb5ceSopenharmony_ci	case LWS_CALLBACK_HTTP_FILE_COMPLETION:
309d4afb5ceSopenharmony_ci		if (lws_http_transaction_completed(wsi))
310d4afb5ceSopenharmony_ci			return -1;
311d4afb5ceSopenharmony_ci		break;
312d4afb5ceSopenharmony_ci#endif
313d4afb5ceSopenharmony_ci
314d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_PROXY)
315d4afb5ceSopenharmony_ci	case LWS_CALLBACK_HTTP_BODY:
316d4afb5ceSopenharmony_ci		if (wsi->child_list) {
317d4afb5ceSopenharmony_ci			lwsl_wsi_info(wsi, "HTTP_BODY: stashing %d", (int)len);
318d4afb5ceSopenharmony_ci			if (lws_buflist_append_segment(
319d4afb5ceSopenharmony_ci				     &wsi->http.buflist_post_body, in, len) < 0)
320d4afb5ceSopenharmony_ci				return -1;
321d4afb5ceSopenharmony_ci			lws_client_http_body_pending(wsi->child_list, 1);
322d4afb5ceSopenharmony_ci			lws_callback_on_writable(wsi->child_list);
323d4afb5ceSopenharmony_ci		}
324d4afb5ceSopenharmony_ci		break;
325d4afb5ceSopenharmony_ci#endif
326d4afb5ceSopenharmony_ci
327d4afb5ceSopenharmony_ci	case LWS_CALLBACK_HTTP_WRITEABLE:
328d4afb5ceSopenharmony_ci		// lwsl_err("%s: LWS_CALLBACK_HTTP_WRITEABLE\n", __func__);
329d4afb5ceSopenharmony_ci#ifdef LWS_WITH_CGI
330d4afb5ceSopenharmony_ci		if (wsi->reason_bf & (LWS_CB_REASON_AUX_BF__CGI_HEADERS |
331d4afb5ceSopenharmony_ci				      LWS_CB_REASON_AUX_BF__CGI)) {
332d4afb5ceSopenharmony_ci			n = lws_cgi_write_split_stdout_headers(wsi);
333d4afb5ceSopenharmony_ci			if (n < 0) {
334d4afb5ceSopenharmony_ci				lwsl_wsi_debug(wsi, "AUX_BF__CGI forcing close");
335d4afb5ceSopenharmony_ci				return -1;
336d4afb5ceSopenharmony_ci			}
337d4afb5ceSopenharmony_ci			if (!n && wsi->http.cgi && wsi->http.cgi->lsp &&
338d4afb5ceSopenharmony_ci			    wsi->http.cgi->lsp->stdwsi[LWS_STDOUT])
339d4afb5ceSopenharmony_ci				lws_rx_flow_control(
340d4afb5ceSopenharmony_ci					wsi->http.cgi->lsp->stdwsi[LWS_STDOUT], 1);
341d4afb5ceSopenharmony_ci
342d4afb5ceSopenharmony_ci			if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_HEADERS)
343d4afb5ceSopenharmony_ci				wsi->reason_bf &=
344d4afb5ceSopenharmony_ci					(char)~LWS_CB_REASON_AUX_BF__CGI_HEADERS;
345d4afb5ceSopenharmony_ci			else
346d4afb5ceSopenharmony_ci				wsi->reason_bf &= (char)~LWS_CB_REASON_AUX_BF__CGI;
347d4afb5ceSopenharmony_ci
348d4afb5ceSopenharmony_ci			if (wsi->http.cgi && wsi->http.cgi->cgi_transaction_over) {
349d4afb5ceSopenharmony_ci				lwsl_wsi_info(wsi, "txn over");
350d4afb5ceSopenharmony_ci				return -1;
351d4afb5ceSopenharmony_ci			}
352d4afb5ceSopenharmony_ci
353d4afb5ceSopenharmony_ci			break;
354d4afb5ceSopenharmony_ci		}
355d4afb5ceSopenharmony_ci
356d4afb5ceSopenharmony_ci		if ((wsi->http.cgi && wsi->http.cgi->cgi_transaction_over) ||
357d4afb5ceSopenharmony_ci		    (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_CHUNK_END)) {
358d4afb5ceSopenharmony_ci			if (!wsi->mux_substream) {
359d4afb5ceSopenharmony_ci				memcpy(buf + LWS_PRE, "0\x0d\x0a\x0d\x0a", 5);
360d4afb5ceSopenharmony_ci				lwsl_wsi_debug(wsi, "wr chunk term and exiting");
361d4afb5ceSopenharmony_ci				lws_write(wsi, (unsigned char *)buf +
362d4afb5ceSopenharmony_ci						   LWS_PRE, 5, LWS_WRITE_HTTP);
363d4afb5ceSopenharmony_ci			} else
364d4afb5ceSopenharmony_ci				lws_write(wsi, (unsigned char *)buf +
365d4afb5ceSopenharmony_ci						   LWS_PRE, 0,
366d4afb5ceSopenharmony_ci						   LWS_WRITE_HTTP_FINAL);
367d4afb5ceSopenharmony_ci
368d4afb5ceSopenharmony_ci			/* always close after sending it */
369d4afb5ceSopenharmony_ci			if (lws_http_transaction_completed(wsi))
370d4afb5ceSopenharmony_ci				return -1;
371d4afb5ceSopenharmony_ci			return 0;
372d4afb5ceSopenharmony_ci		}
373d4afb5ceSopenharmony_ci#endif
374d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_PROXY)
375d4afb5ceSopenharmony_ci
376d4afb5ceSopenharmony_ci		if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY_HEADERS) {
377d4afb5ceSopenharmony_ci
378d4afb5ceSopenharmony_ci			wsi->reason_bf &=
379d4afb5ceSopenharmony_ci				     (char)~LWS_CB_REASON_AUX_BF__PROXY_HEADERS;
380d4afb5ceSopenharmony_ci
381d4afb5ceSopenharmony_ci			n = LWS_WRITE_HTTP_HEADERS;
382d4afb5ceSopenharmony_ci			if (!wsi->http.prh_content_length)
383d4afb5ceSopenharmony_ci				n |= LWS_WRITE_H2_STREAM_END;
384d4afb5ceSopenharmony_ci
385d4afb5ceSopenharmony_ci			lwsl_wsi_debug(wsi, "issuing proxy headers: clen %d",
386d4afb5ceSopenharmony_ci				    (int)wsi->http.prh_content_length);
387d4afb5ceSopenharmony_ci			n = lws_write(wsi, wsi->http.pending_return_headers +
388d4afb5ceSopenharmony_ci					   LWS_PRE,
389d4afb5ceSopenharmony_ci				      wsi->http.pending_return_headers_len,
390d4afb5ceSopenharmony_ci				      (enum lws_write_protocol)n);
391d4afb5ceSopenharmony_ci
392d4afb5ceSopenharmony_ci			lws_free_set_NULL(wsi->http.pending_return_headers);
393d4afb5ceSopenharmony_ci
394d4afb5ceSopenharmony_ci			if (n < 0) {
395d4afb5ceSopenharmony_ci				lwsl_wsi_err(wsi, "EST_CLIENT_HTTP: wr failed");
396d4afb5ceSopenharmony_ci
397d4afb5ceSopenharmony_ci				return -1;
398d4afb5ceSopenharmony_ci			}
399d4afb5ceSopenharmony_ci
400d4afb5ceSopenharmony_ci			lws_callback_on_writable(wsi);
401d4afb5ceSopenharmony_ci			break;
402d4afb5ceSopenharmony_ci		}
403d4afb5ceSopenharmony_ci
404d4afb5ceSopenharmony_ci		if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY) {
405d4afb5ceSopenharmony_ci			char *px = buf + LWS_PRE;
406d4afb5ceSopenharmony_ci			int lenx = sizeof(buf) - LWS_PRE - 32;
407d4afb5ceSopenharmony_ci
408d4afb5ceSopenharmony_ci			/*
409d4afb5ceSopenharmony_ci			 * our sink is writeable and our source has something
410d4afb5ceSopenharmony_ci			 * to read.  So read a lump of source material of
411d4afb5ceSopenharmony_ci			 * suitable size to send or what's available, whichever
412d4afb5ceSopenharmony_ci			 * is the smaller.
413d4afb5ceSopenharmony_ci			 */
414d4afb5ceSopenharmony_ci			wsi->reason_bf &= (char)~LWS_CB_REASON_AUX_BF__PROXY;
415d4afb5ceSopenharmony_ci			if (!lws_get_child(wsi))
416d4afb5ceSopenharmony_ci				break;
417d4afb5ceSopenharmony_ci
418d4afb5ceSopenharmony_ci			/* this causes LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ */
419d4afb5ceSopenharmony_ci			if (lws_http_client_read(lws_get_child(wsi), &px,
420d4afb5ceSopenharmony_ci						 &lenx) < 0) {
421d4afb5ceSopenharmony_ci				lwsl_wsi_info(wsi, "LWS_CB_REASON_AUX_BF__PROXY: "
422d4afb5ceSopenharmony_ci					   "client closed");
423d4afb5ceSopenharmony_ci
424d4afb5ceSopenharmony_ci				stream_close(wsi);
425d4afb5ceSopenharmony_ci
426d4afb5ceSopenharmony_ci				return -1;
427d4afb5ceSopenharmony_ci			}
428d4afb5ceSopenharmony_ci			break;
429d4afb5ceSopenharmony_ci		}
430d4afb5ceSopenharmony_ci
431d4afb5ceSopenharmony_ci		if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY_TRANS_END) {
432d4afb5ceSopenharmony_ci			lwsl_wsi_info(wsi, "PROXY_TRANS_END");
433d4afb5ceSopenharmony_ci
434d4afb5ceSopenharmony_ci			wsi->reason_bf &= (char)~LWS_CB_REASON_AUX_BF__PROXY_TRANS_END;
435d4afb5ceSopenharmony_ci
436d4afb5ceSopenharmony_ci			if (stream_close(wsi))
437d4afb5ceSopenharmony_ci				return -1;
438d4afb5ceSopenharmony_ci
439d4afb5ceSopenharmony_ci			if (lws_http_transaction_completed(wsi))
440d4afb5ceSopenharmony_ci				return -1;
441d4afb5ceSopenharmony_ci		}
442d4afb5ceSopenharmony_ci#endif
443d4afb5ceSopenharmony_ci		break;
444d4afb5ceSopenharmony_ci
445d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_PROXY)
446d4afb5ceSopenharmony_ci	case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
447d4afb5ceSopenharmony_ci		assert(lws_get_parent(wsi));
448d4afb5ceSopenharmony_ci		if (!lws_get_parent(wsi))
449d4afb5ceSopenharmony_ci			break;
450d4afb5ceSopenharmony_ci		lws_get_parent(wsi)->reason_bf |= LWS_CB_REASON_AUX_BF__PROXY;
451d4afb5ceSopenharmony_ci		lws_callback_on_writable(lws_get_parent(wsi));
452d4afb5ceSopenharmony_ci		break;
453d4afb5ceSopenharmony_ci
454d4afb5ceSopenharmony_ci	case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: {
455d4afb5ceSopenharmony_ci		char *out = buf + LWS_PRE;
456d4afb5ceSopenharmony_ci
457d4afb5ceSopenharmony_ci		assert(lws_get_parent(wsi));
458d4afb5ceSopenharmony_ci
459d4afb5ceSopenharmony_ci		if (wsi->http.proxy_parent_chunked) {
460d4afb5ceSopenharmony_ci
461d4afb5ceSopenharmony_ci			if (len > sizeof(buf) - LWS_PRE - 16) {
462d4afb5ceSopenharmony_ci				lwsl_wsi_err(wsi, "oversize buf %d %d", (int)len,
463d4afb5ceSopenharmony_ci						(int)sizeof(buf) - LWS_PRE - 16);
464d4afb5ceSopenharmony_ci				return -1;
465d4afb5ceSopenharmony_ci			}
466d4afb5ceSopenharmony_ci
467d4afb5ceSopenharmony_ci			/*
468d4afb5ceSopenharmony_ci			 * this only needs dealing with on http/1.1 to allow
469d4afb5ceSopenharmony_ci			 * pipelining
470d4afb5ceSopenharmony_ci			 */
471d4afb5ceSopenharmony_ci			n = lws_snprintf(out, 14, "%X\x0d\x0a", (int)len);
472d4afb5ceSopenharmony_ci			out += n;
473d4afb5ceSopenharmony_ci			memcpy(out, in, len);
474d4afb5ceSopenharmony_ci			out += len;
475d4afb5ceSopenharmony_ci			*out++ = '\x0d';
476d4afb5ceSopenharmony_ci			*out++ = '\x0a';
477d4afb5ceSopenharmony_ci
478d4afb5ceSopenharmony_ci			n = lws_write(lws_get_parent(wsi),
479d4afb5ceSopenharmony_ci				      (unsigned char *)buf + LWS_PRE,
480d4afb5ceSopenharmony_ci				      (size_t)(unsigned int)(len + (unsigned int)n + 2), LWS_WRITE_HTTP);
481d4afb5ceSopenharmony_ci		} else
482d4afb5ceSopenharmony_ci			n = lws_write(lws_get_parent(wsi), (unsigned char *)in,
483d4afb5ceSopenharmony_ci				      len, LWS_WRITE_HTTP);
484d4afb5ceSopenharmony_ci		if (n < 0)
485d4afb5ceSopenharmony_ci			return -1;
486d4afb5ceSopenharmony_ci		break; }
487d4afb5ceSopenharmony_ci
488d4afb5ceSopenharmony_ci	/* h1 http proxying... */
489d4afb5ceSopenharmony_ci
490d4afb5ceSopenharmony_ci	case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: {
491d4afb5ceSopenharmony_ci		unsigned char *start, *p, *end;
492d4afb5ceSopenharmony_ci
493d4afb5ceSopenharmony_ci		/*
494d4afb5ceSopenharmony_ci		 * We want to proxy these headers, but we are being called
495d4afb5ceSopenharmony_ci		 * at the point the onward client was established, which is
496d4afb5ceSopenharmony_ci		 * unrelated to the state or writability of our proxy
497d4afb5ceSopenharmony_ci		 * connection.
498d4afb5ceSopenharmony_ci		 *
499d4afb5ceSopenharmony_ci		 * Therefore produce the headers using the onward client ah
500d4afb5ceSopenharmony_ci		 * while we have it, and stick them on the output buflist to be
501d4afb5ceSopenharmony_ci		 * written on the proxy connection as soon as convenient.
502d4afb5ceSopenharmony_ci		 */
503d4afb5ceSopenharmony_ci
504d4afb5ceSopenharmony_ci		parent = lws_get_parent(wsi);
505d4afb5ceSopenharmony_ci
506d4afb5ceSopenharmony_ci		if (!parent)
507d4afb5ceSopenharmony_ci			return 0;
508d4afb5ceSopenharmony_ci
509d4afb5ceSopenharmony_ci		start = p = (unsigned char *)buf + LWS_PRE;
510d4afb5ceSopenharmony_ci		end = p + sizeof(buf) - LWS_PRE - MAXHDRVAL;
511d4afb5ceSopenharmony_ci
512d4afb5ceSopenharmony_ci		if (lws_add_http_header_status(lws_get_parent(wsi),
513d4afb5ceSopenharmony_ci				lws_http_client_http_response(wsi), &p, end))
514d4afb5ceSopenharmony_ci			return 1;
515d4afb5ceSopenharmony_ci
516d4afb5ceSopenharmony_ci		/*
517d4afb5ceSopenharmony_ci		 * copy these headers from the client connection to the parent
518d4afb5ceSopenharmony_ci		 */
519d4afb5ceSopenharmony_ci
520d4afb5ceSopenharmony_ci		proxy_header(parent, wsi, end, MAXHDRVAL,
521d4afb5ceSopenharmony_ci			     WSI_TOKEN_HTTP_CONTENT_LENGTH, &p, end);
522d4afb5ceSopenharmony_ci		proxy_header(parent, wsi, end, MAXHDRVAL,
523d4afb5ceSopenharmony_ci			     WSI_TOKEN_HTTP_CONTENT_TYPE, &p, end);
524d4afb5ceSopenharmony_ci		proxy_header(parent, wsi, end, MAXHDRVAL,
525d4afb5ceSopenharmony_ci			     WSI_TOKEN_HTTP_ETAG, &p, end);
526d4afb5ceSopenharmony_ci		proxy_header(parent, wsi, end, MAXHDRVAL,
527d4afb5ceSopenharmony_ci			     WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, &p, end);
528d4afb5ceSopenharmony_ci		proxy_header(parent, wsi, end, MAXHDRVAL,
529d4afb5ceSopenharmony_ci			     WSI_TOKEN_HTTP_CONTENT_ENCODING, &p, end);
530d4afb5ceSopenharmony_ci		proxy_header(parent, wsi, end, MAXHDRVAL,
531d4afb5ceSopenharmony_ci			     WSI_TOKEN_HTTP_CACHE_CONTROL, &p, end);
532d4afb5ceSopenharmony_ci		proxy_header(parent, wsi, end, MAXHDRVAL,
533d4afb5ceSopenharmony_ci			     WSI_TOKEN_HTTP_SET_COOKIE, &p, end);
534d4afb5ceSopenharmony_ci		proxy_header(parent, wsi, end, MAXHDRVAL,
535d4afb5ceSopenharmony_ci			     WSI_TOKEN_HTTP_LOCATION, &p, end);
536d4afb5ceSopenharmony_ci
537d4afb5ceSopenharmony_ci		if (!parent->mux_substream)
538d4afb5ceSopenharmony_ci			if (lws_add_http_header_by_token(parent,
539d4afb5ceSopenharmony_ci				WSI_TOKEN_CONNECTION, (unsigned char *)"close",
540d4afb5ceSopenharmony_ci				5, &p, end))
541d4afb5ceSopenharmony_ci			return -1;
542d4afb5ceSopenharmony_ci
543d4afb5ceSopenharmony_ci		/*
544d4afb5ceSopenharmony_ci		 * We proxy using h1 only atm, and strip any chunking so it
545d4afb5ceSopenharmony_ci		 * can go back out on h2 just fine.
546d4afb5ceSopenharmony_ci		 *
547d4afb5ceSopenharmony_ci		 * However if we are actually going out on h1, we need to add
548d4afb5ceSopenharmony_ci		 * our own chunking since we still don't know the size.
549d4afb5ceSopenharmony_ci		 */
550d4afb5ceSopenharmony_ci
551d4afb5ceSopenharmony_ci		if (!parent->mux_substream &&
552d4afb5ceSopenharmony_ci		    !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
553d4afb5ceSopenharmony_ci			lwsl_wsi_debug(wsi, "downstream parent chunked");
554d4afb5ceSopenharmony_ci			if (lws_add_http_header_by_token(parent,
555d4afb5ceSopenharmony_ci					WSI_TOKEN_HTTP_TRANSFER_ENCODING,
556d4afb5ceSopenharmony_ci					(unsigned char *)"chunked", 7, &p, end))
557d4afb5ceSopenharmony_ci				return -1;
558d4afb5ceSopenharmony_ci
559d4afb5ceSopenharmony_ci			wsi->http.proxy_parent_chunked = 1;
560d4afb5ceSopenharmony_ci		}
561d4afb5ceSopenharmony_ci
562d4afb5ceSopenharmony_ci		if (lws_finalize_http_header(parent, &p, end))
563d4afb5ceSopenharmony_ci			return 1;
564d4afb5ceSopenharmony_ci
565d4afb5ceSopenharmony_ci		parent->http.prh_content_length = (size_t)-1;
566d4afb5ceSopenharmony_ci		if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH))
567d4afb5ceSopenharmony_ci			parent->http.prh_content_length = (size_t)atoll(
568d4afb5ceSopenharmony_ci				lws_hdr_simple_ptr(wsi,
569d4afb5ceSopenharmony_ci						WSI_TOKEN_HTTP_CONTENT_LENGTH));
570d4afb5ceSopenharmony_ci
571d4afb5ceSopenharmony_ci		parent->http.pending_return_headers_len = lws_ptr_diff_size_t(p, start);
572d4afb5ceSopenharmony_ci		parent->http.pending_return_headers =
573d4afb5ceSopenharmony_ci			lws_malloc(parent->http.pending_return_headers_len +
574d4afb5ceSopenharmony_ci				    LWS_PRE, "return proxy headers");
575d4afb5ceSopenharmony_ci		if (!parent->http.pending_return_headers)
576d4afb5ceSopenharmony_ci			return -1;
577d4afb5ceSopenharmony_ci
578d4afb5ceSopenharmony_ci		memcpy(parent->http.pending_return_headers + LWS_PRE, start,
579d4afb5ceSopenharmony_ci		       parent->http.pending_return_headers_len);
580d4afb5ceSopenharmony_ci
581d4afb5ceSopenharmony_ci		parent->reason_bf |= LWS_CB_REASON_AUX_BF__PROXY_HEADERS;
582d4afb5ceSopenharmony_ci
583d4afb5ceSopenharmony_ci		lwsl_wsi_debug(wsi, "ESTABLISHED_CLIENT_HTTP: "
584d4afb5ceSopenharmony_ci			   "prepared %d headers (len %d)",
585d4afb5ceSopenharmony_ci			   lws_http_client_http_response(wsi),
586d4afb5ceSopenharmony_ci			   (int)parent->http.prh_content_length);
587d4afb5ceSopenharmony_ci
588d4afb5ceSopenharmony_ci		/*
589d4afb5ceSopenharmony_ci		 * so at this point, the onward client connection can bear
590d4afb5ceSopenharmony_ci		 * traffic.  We might be doing a POST and have pending cached
591d4afb5ceSopenharmony_ci		 * inbound stuff to send, it can go now.
592d4afb5ceSopenharmony_ci		 */
593d4afb5ceSopenharmony_ci
594d4afb5ceSopenharmony_ci		lws_callback_on_writable(parent);
595d4afb5ceSopenharmony_ci
596d4afb5ceSopenharmony_ci		break; }
597d4afb5ceSopenharmony_ci
598d4afb5ceSopenharmony_ci	case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
599d4afb5ceSopenharmony_ci		lwsl_wsi_info(wsi, "COMPLETED_CLIENT_HTTP: (parent %s)",
600d4afb5ceSopenharmony_ci				   lws_wsi_tag(lws_get_parent(wsi)));
601d4afb5ceSopenharmony_ci		if (!lws_get_parent(wsi))
602d4afb5ceSopenharmony_ci			break;
603d4afb5ceSopenharmony_ci		lws_get_parent(wsi)->reason_bf |=
604d4afb5ceSopenharmony_ci				LWS_CB_REASON_AUX_BF__PROXY_TRANS_END;
605d4afb5ceSopenharmony_ci		lws_callback_on_writable(lws_get_parent(wsi));
606d4afb5ceSopenharmony_ci		break;
607d4afb5ceSopenharmony_ci
608d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
609d4afb5ceSopenharmony_ci		if (!lws_get_parent(wsi))
610d4afb5ceSopenharmony_ci			break;
611d4afb5ceSopenharmony_ci	//	lwsl_err("%s: LWS_CALLBACK_CLOSED_CLIENT_HTTP\n", __func__);
612d4afb5ceSopenharmony_ci               lws_set_timeout(lws_get_parent(wsi),
613d4afb5ceSopenharmony_ci        		       (enum pending_timeout)LWS_TO_KILL_ASYNC,
614d4afb5ceSopenharmony_ci                               (int)PENDING_TIMEOUT_KILLED_BY_PROXY_CLIENT_CLOSE);
615d4afb5ceSopenharmony_ci		break;
616d4afb5ceSopenharmony_ci
617d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
618d4afb5ceSopenharmony_ci		parent = lws_get_parent(wsi);
619d4afb5ceSopenharmony_ci		if (!parent)
620d4afb5ceSopenharmony_ci			break;
621d4afb5ceSopenharmony_ci
622d4afb5ceSopenharmony_ci		p = (unsigned char **)in;
623d4afb5ceSopenharmony_ci		end = (*p) + len;
624d4afb5ceSopenharmony_ci
625d4afb5ceSopenharmony_ci		/*
626d4afb5ceSopenharmony_ci		 * copy these headers from the parent request to the client
627d4afb5ceSopenharmony_ci		 * connection's request
628d4afb5ceSopenharmony_ci		 */
629d4afb5ceSopenharmony_ci
630d4afb5ceSopenharmony_ci		proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
631d4afb5ceSopenharmony_ci				WSI_TOKEN_HTTP_ETAG, p, end);
632d4afb5ceSopenharmony_ci		proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
633d4afb5ceSopenharmony_ci				WSI_TOKEN_HTTP_IF_MODIFIED_SINCE, p, end);
634d4afb5ceSopenharmony_ci		proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
635d4afb5ceSopenharmony_ci				WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, p, end);
636d4afb5ceSopenharmony_ci		proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
637d4afb5ceSopenharmony_ci				WSI_TOKEN_HTTP_ACCEPT_ENCODING, p, end);
638d4afb5ceSopenharmony_ci		proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
639d4afb5ceSopenharmony_ci				WSI_TOKEN_HTTP_CACHE_CONTROL, p, end);
640d4afb5ceSopenharmony_ci		proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
641d4afb5ceSopenharmony_ci				WSI_TOKEN_HTTP_COOKIE, p, end);
642d4afb5ceSopenharmony_ci
643d4afb5ceSopenharmony_ci		buf[0] = '\0';
644d4afb5ceSopenharmony_ci		lws_get_peer_simple(parent, buf, sizeof(buf));
645d4afb5ceSopenharmony_ci		if (lws_add_http_header_by_token(wsi, WSI_TOKEN_X_FORWARDED_FOR,
646d4afb5ceSopenharmony_ci				(unsigned char *)buf, (int)strlen(buf), p, end))
647d4afb5ceSopenharmony_ci			return -1;
648d4afb5ceSopenharmony_ci
649d4afb5ceSopenharmony_ci		break;
650d4afb5ceSopenharmony_ci#endif
651d4afb5ceSopenharmony_ci
652d4afb5ceSopenharmony_ci#ifdef LWS_WITH_CGI
653d4afb5ceSopenharmony_ci	/* CGI IO events (POLLIN/OUT) appear here, our default policy is:
654d4afb5ceSopenharmony_ci	 *
655d4afb5ceSopenharmony_ci	 *  - POST data goes on subprocess stdin
656d4afb5ceSopenharmony_ci	 *  - subprocess stdout goes on http via writeable callback
657d4afb5ceSopenharmony_ci	 *  - subprocess stderr goes to the logs
658d4afb5ceSopenharmony_ci	 */
659d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CGI:
660d4afb5ceSopenharmony_ci		args = (struct lws_cgi_args *)in;
661d4afb5ceSopenharmony_ci		switch (args->ch) { /* which of stdin/out/err ? */
662d4afb5ceSopenharmony_ci		case LWS_STDIN:
663d4afb5ceSopenharmony_ci			/* TBD stdin rx flow control */
664d4afb5ceSopenharmony_ci			break;
665d4afb5ceSopenharmony_ci		case LWS_STDOUT:
666d4afb5ceSopenharmony_ci			if (args->stdwsi[LWS_STDOUT])
667d4afb5ceSopenharmony_ci				/* quench POLLIN on STDOUT until MASTER got writeable */
668d4afb5ceSopenharmony_ci				lws_rx_flow_control(args->stdwsi[LWS_STDOUT], 0);
669d4afb5ceSopenharmony_ci			wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI;
670d4afb5ceSopenharmony_ci			/* when writing to MASTER would not block */
671d4afb5ceSopenharmony_ci			lws_callback_on_writable(wsi);
672d4afb5ceSopenharmony_ci			break;
673d4afb5ceSopenharmony_ci		case LWS_STDERR:
674d4afb5ceSopenharmony_ci			n = lws_get_socket_fd(args->stdwsi[LWS_STDERR]);
675d4afb5ceSopenharmony_ci			if (n < 0)
676d4afb5ceSopenharmony_ci				break;
677d4afb5ceSopenharmony_ci			n = (int)read(n, buf, sizeof(buf) - 2);
678d4afb5ceSopenharmony_ci			if (n > 0) {
679d4afb5ceSopenharmony_ci				if (buf[n - 1] != '\n')
680d4afb5ceSopenharmony_ci					buf[n++] = '\n';
681d4afb5ceSopenharmony_ci				buf[n] = '\0';
682d4afb5ceSopenharmony_ci				lwsl_wsi_notice(wsi, "CGI-stderr: %s", buf);
683d4afb5ceSopenharmony_ci			}
684d4afb5ceSopenharmony_ci			break;
685d4afb5ceSopenharmony_ci		}
686d4afb5ceSopenharmony_ci		break;
687d4afb5ceSopenharmony_ci
688d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CGI_TERMINATED:
689d4afb5ceSopenharmony_ci		if (wsi->http.cgi) {
690d4afb5ceSopenharmony_ci			lwsl_wsi_debug(wsi, "CGI_TERMINATED: %d %" PRIu64,
691d4afb5ceSopenharmony_ci				wsi->http.cgi->explicitly_chunked,
692d4afb5ceSopenharmony_ci				(uint64_t)wsi->http.cgi->content_length);
693d4afb5ceSopenharmony_ci			if (!(wsi->http.cgi->explicitly_chunked && wsi->mux_substream) &&
694d4afb5ceSopenharmony_ci			    !wsi->http.cgi->content_length) {
695d4afb5ceSopenharmony_ci				/* send terminating chunk */
696d4afb5ceSopenharmony_ci				lwsl_wsi_debug(wsi, "LWS_CALLBACK_CGI_TERMINATED: ending");
697d4afb5ceSopenharmony_ci				wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI_CHUNK_END;
698d4afb5ceSopenharmony_ci				lws_callback_on_writable(wsi);
699d4afb5ceSopenharmony_ci				lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, 3);
700d4afb5ceSopenharmony_ci				break;
701d4afb5ceSopenharmony_ci			}
702d4afb5ceSopenharmony_ci			if (wsi->mux_substream && !wsi->cgi_stdout_zero_length)
703d4afb5ceSopenharmony_ci				lws_write(wsi, (unsigned char *)buf + LWS_PRE, 0,
704d4afb5ceSopenharmony_ci						      LWS_WRITE_HTTP_FINAL);
705d4afb5ceSopenharmony_ci		}
706d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
707d4afb5ceSopenharmony_ci		if (lws_http_transaction_completed(wsi))
708d4afb5ceSopenharmony_ci			return -1;
709d4afb5ceSopenharmony_ci#endif
710d4afb5ceSopenharmony_ci		return 0;
711d4afb5ceSopenharmony_ci
712d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CGI_STDIN_DATA:  /* POST body for stdin */
713d4afb5ceSopenharmony_ci		args = (struct lws_cgi_args *)in;
714d4afb5ceSopenharmony_ci		args->data[args->len] = '\0';
715d4afb5ceSopenharmony_ci		if (!args->stdwsi[LWS_STDIN])
716d4afb5ceSopenharmony_ci			return -1;
717d4afb5ceSopenharmony_ci		n = lws_get_socket_fd(args->stdwsi[LWS_STDIN]);
718d4afb5ceSopenharmony_ci		if (n < 0)
719d4afb5ceSopenharmony_ci			return -1;
720d4afb5ceSopenharmony_ci
721d4afb5ceSopenharmony_ci#if defined(LWS_WITH_ZLIB)
722d4afb5ceSopenharmony_ci		if (wsi->http.cgi->gzip_inflate) {
723d4afb5ceSopenharmony_ci			/* gzip handling */
724d4afb5ceSopenharmony_ci
725d4afb5ceSopenharmony_ci			if (!wsi->http.cgi->gzip_init) {
726d4afb5ceSopenharmony_ci				lwsl_wsi_info(wsi, "inflating gzip");
727d4afb5ceSopenharmony_ci
728d4afb5ceSopenharmony_ci				memset(&wsi->http.cgi->inflate, 0,
729d4afb5ceSopenharmony_ci				       sizeof(wsi->http.cgi->inflate));
730d4afb5ceSopenharmony_ci
731d4afb5ceSopenharmony_ci				if (inflateInit2(&wsi->http.cgi->inflate,
732d4afb5ceSopenharmony_ci						 16 + 15) != Z_OK) {
733d4afb5ceSopenharmony_ci					lwsl_wsi_err(wsi, "iniflateInit fail");
734d4afb5ceSopenharmony_ci					return -1;
735d4afb5ceSopenharmony_ci				}
736d4afb5ceSopenharmony_ci
737d4afb5ceSopenharmony_ci				wsi->http.cgi->gzip_init = 1;
738d4afb5ceSopenharmony_ci			}
739d4afb5ceSopenharmony_ci
740d4afb5ceSopenharmony_ci			wsi->http.cgi->inflate.next_in = args->data;
741d4afb5ceSopenharmony_ci			wsi->http.cgi->inflate.avail_in = (unsigned int)args->len;
742d4afb5ceSopenharmony_ci
743d4afb5ceSopenharmony_ci			do {
744d4afb5ceSopenharmony_ci
745d4afb5ceSopenharmony_ci				wsi->http.cgi->inflate.next_out =
746d4afb5ceSopenharmony_ci						wsi->http.cgi->inflate_buf;
747d4afb5ceSopenharmony_ci				wsi->http.cgi->inflate.avail_out =
748d4afb5ceSopenharmony_ci					sizeof(wsi->http.cgi->inflate_buf);
749d4afb5ceSopenharmony_ci
750d4afb5ceSopenharmony_ci				n = inflate(&wsi->http.cgi->inflate,
751d4afb5ceSopenharmony_ci					    Z_SYNC_FLUSH);
752d4afb5ceSopenharmony_ci
753d4afb5ceSopenharmony_ci				switch (n) {
754d4afb5ceSopenharmony_ci				case Z_NEED_DICT:
755d4afb5ceSopenharmony_ci				case Z_STREAM_ERROR:
756d4afb5ceSopenharmony_ci				case Z_DATA_ERROR:
757d4afb5ceSopenharmony_ci				case Z_MEM_ERROR:
758d4afb5ceSopenharmony_ci					inflateEnd(&wsi->http.cgi->inflate);
759d4afb5ceSopenharmony_ci					wsi->http.cgi->gzip_init = 0;
760d4afb5ceSopenharmony_ci					lwsl_wsi_err(wsi, "zlib err inflate %d", n);
761d4afb5ceSopenharmony_ci					return -1;
762d4afb5ceSopenharmony_ci				}
763d4afb5ceSopenharmony_ci
764d4afb5ceSopenharmony_ci				if (wsi->http.cgi->inflate.avail_out !=
765d4afb5ceSopenharmony_ci					   sizeof(wsi->http.cgi->inflate_buf)) {
766d4afb5ceSopenharmony_ci					int written;
767d4afb5ceSopenharmony_ci
768d4afb5ceSopenharmony_ci					written = (int)write(args->stdwsi[LWS_STDIN]->desc.filefd,
769d4afb5ceSopenharmony_ci						wsi->http.cgi->inflate_buf,
770d4afb5ceSopenharmony_ci						sizeof(wsi->http.cgi->inflate_buf) -
771d4afb5ceSopenharmony_ci						wsi->http.cgi->inflate.avail_out);
772d4afb5ceSopenharmony_ci
773d4afb5ceSopenharmony_ci					if (written != (int)(
774d4afb5ceSopenharmony_ci						sizeof(wsi->http.cgi->inflate_buf) -
775d4afb5ceSopenharmony_ci						wsi->http.cgi->inflate.avail_out)) {
776d4afb5ceSopenharmony_ci						lwsl_wsi_notice(wsi,
777d4afb5ceSopenharmony_ci							"CGI_STDIN_DATA: "
778d4afb5ceSopenharmony_ci							"sent %d only %d went",
779d4afb5ceSopenharmony_ci							n, args->len);
780d4afb5ceSopenharmony_ci					}
781d4afb5ceSopenharmony_ci
782d4afb5ceSopenharmony_ci					if (n == Z_STREAM_END) {
783d4afb5ceSopenharmony_ci						lwsl_wsi_err(wsi,
784d4afb5ceSopenharmony_ci							    "gzip inflate end");
785d4afb5ceSopenharmony_ci						inflateEnd(&wsi->http.cgi->inflate);
786d4afb5ceSopenharmony_ci						wsi->http.cgi->gzip_init = 0;
787d4afb5ceSopenharmony_ci						break;
788d4afb5ceSopenharmony_ci					}
789d4afb5ceSopenharmony_ci
790d4afb5ceSopenharmony_ci				} else
791d4afb5ceSopenharmony_ci					break;
792d4afb5ceSopenharmony_ci
793d4afb5ceSopenharmony_ci				if (wsi->http.cgi->inflate.avail_out)
794d4afb5ceSopenharmony_ci					break;
795d4afb5ceSopenharmony_ci
796d4afb5ceSopenharmony_ci			} while (1);
797d4afb5ceSopenharmony_ci
798d4afb5ceSopenharmony_ci			return args->len;
799d4afb5ceSopenharmony_ci		}
800d4afb5ceSopenharmony_ci#endif /* WITH_ZLIB */
801d4afb5ceSopenharmony_ci
802d4afb5ceSopenharmony_ci		n = (int)write(n, args->data, (unsigned int)args->len);
803d4afb5ceSopenharmony_ci//		lwsl_hexdump_notice(args->data, args->len);
804d4afb5ceSopenharmony_ci		if (n < args->len)
805d4afb5ceSopenharmony_ci			lwsl_wsi_notice(wsi, "CGI_STDIN_DATA: "
806d4afb5ceSopenharmony_ci				    "sent %d only %d went", n, args->len);
807d4afb5ceSopenharmony_ci
808d4afb5ceSopenharmony_ci		lwsl_wsi_info(wsi, "proxied %d bytes", n);
809d4afb5ceSopenharmony_ci
810d4afb5ceSopenharmony_ci		if (wsi->http.cgi->post_in_expected && args->stdwsi[LWS_STDIN] &&
811d4afb5ceSopenharmony_ci		    args->stdwsi[LWS_STDIN]->desc.filefd > 0) {
812d4afb5ceSopenharmony_ci			wsi->http.cgi->post_in_expected -= (unsigned int)n;
813d4afb5ceSopenharmony_ci
814d4afb5ceSopenharmony_ci			if (!wsi->http.cgi->post_in_expected) {
815d4afb5ceSopenharmony_ci				struct lws *siwsi = args->stdwsi[LWS_STDIN];
816d4afb5ceSopenharmony_ci
817d4afb5ceSopenharmony_ci				/*
818d4afb5ceSopenharmony_ci				 * The situation here is that we finished
819d4afb5ceSopenharmony_ci				 * proxying the incoming body from the net to
820d4afb5ceSopenharmony_ci				 * the STDIN stdwsi... and we want to close it
821d4afb5ceSopenharmony_ci				 * so it can understand we are done (necessary
822d4afb5ceSopenharmony_ci				 * if no content-length)...
823d4afb5ceSopenharmony_ci				 */
824d4afb5ceSopenharmony_ci
825d4afb5ceSopenharmony_ci				lwsl_wsi_info(siwsi, "expected POST in end: "
826d4afb5ceSopenharmony_ci						     "closing stdin fd %d",
827d4afb5ceSopenharmony_ci						     siwsi->desc.sockfd);
828d4afb5ceSopenharmony_ci
829d4afb5ceSopenharmony_ci				/*
830d4afb5ceSopenharmony_ci				 * We don't want the child / parent relationship
831d4afb5ceSopenharmony_ci				 * to be handled in close, since we want the
832d4afb5ceSopenharmony_ci				 * rest of the cgi and children to stay up
833d4afb5ceSopenharmony_ci				 */
834d4afb5ceSopenharmony_ci
835d4afb5ceSopenharmony_ci				lws_remove_child_from_any_parent(siwsi);
836d4afb5ceSopenharmony_ci				lws_wsi_close(siwsi, LWS_TO_KILL_ASYNC);
837d4afb5ceSopenharmony_ci				wsi->http.cgi->lsp->stdwsi[LWS_STDIN] = NULL;
838d4afb5ceSopenharmony_ci				lws_spawn_stdwsi_closed(wsi->http.cgi->lsp, siwsi);
839d4afb5ceSopenharmony_ci			}
840d4afb5ceSopenharmony_ci		}
841d4afb5ceSopenharmony_ci
842d4afb5ceSopenharmony_ci		return n;
843d4afb5ceSopenharmony_ci#endif /* WITH_CGI */
844d4afb5ceSopenharmony_ci#endif /* ROLE_ H1 / H2 */
845d4afb5ceSopenharmony_ci	case LWS_CALLBACK_SSL_INFO:
846d4afb5ceSopenharmony_ci		si = in;
847d4afb5ceSopenharmony_ci
848d4afb5ceSopenharmony_ci		(void)si;
849d4afb5ceSopenharmony_ci		lwsl_wsi_notice(wsi, "SSL_INFO: where: 0x%x, ret: 0x%x",
850d4afb5ceSopenharmony_ci				si->where, si->ret);
851d4afb5ceSopenharmony_ci		break;
852d4afb5ceSopenharmony_ci
853d4afb5ceSopenharmony_ci#if LWS_MAX_SMP > 1
854d4afb5ceSopenharmony_ci	case LWS_CALLBACK_GET_THREAD_ID:
855d4afb5ceSopenharmony_ci#ifdef __PTW32_H
856d4afb5ceSopenharmony_ci		/* If we use implementation of PThreads for Win that is
857d4afb5ceSopenharmony_ci		 * distributed by VCPKG */
858d4afb5ceSopenharmony_ci		return (int)(lws_intptr_t)(pthread_self()).p;
859d4afb5ceSopenharmony_ci#else
860d4afb5ceSopenharmony_ci		return (int)(lws_intptr_t)pthread_self();
861d4afb5ceSopenharmony_ci#endif // __PTW32_H
862d4afb5ceSopenharmony_ci#endif
863d4afb5ceSopenharmony_ci
864d4afb5ceSopenharmony_ci	default:
865d4afb5ceSopenharmony_ci		break;
866d4afb5ceSopenharmony_ci	}
867d4afb5ceSopenharmony_ci
868d4afb5ceSopenharmony_ci	return 0;
869d4afb5ceSopenharmony_ci}
870