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