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