Coverage Report

Created: 2023-03-26 07:20

/src/libwebsockets/lib/core-net/dummy-callback.c
Line
Count
Source (jump to first uncovered line)
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
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
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
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
266
lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
267
      void *user, void *in, size_t len)
268
0
{
269
0
  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
0
  switch (reason) {
283
0
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
284
0
  case LWS_CALLBACK_HTTP:
285
0
#if defined(LWS_WITH_SERVER)
286
0
    if (lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL))
287
0
      return -1;
288
289
0
    if (lws_http_transaction_completed(wsi))
290
0
#endif
291
0
      return -1;
292
0
    break;
293
0
#if defined(LWS_WITH_SERVER)
294
0
  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
0
    if (lws_return_http_status(wsi, 200, NULL))
304
0
      return -1;
305
0
    break;
306
307
    /* fallthru */
308
0
  case LWS_CALLBACK_HTTP_FILE_COMPLETION:
309
0
    if (lws_http_transaction_completed(wsi))
310
0
      return -1;
311
0
    break;
312
0
#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
0
  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
0
    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
    if (wsi->http.cgi) {
690
      lwsl_wsi_debug(wsi, "CGI_TERMINATED: %d %" PRIu64,
691
        wsi->http.cgi->explicitly_chunked,
692
        (uint64_t)wsi->http.cgi->content_length);
693
      if (!(wsi->http.cgi->explicitly_chunked && wsi->mux_substream) &&
694
          !wsi->http.cgi->content_length) {
695
        /* send terminating chunk */
696
        lwsl_wsi_debug(wsi, "LWS_CALLBACK_CGI_TERMINATED: ending");
697
        wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI_CHUNK_END;
698
        lws_callback_on_writable(wsi);
699
        lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, 3);
700
        break;
701
      }
702
      if (wsi->mux_substream && !wsi->cgi_stdout_zero_length)
703
        lws_write(wsi, (unsigned char *)buf + LWS_PRE, 0,
704
                  LWS_WRITE_HTTP_FINAL);
705
    }
706
#if defined(LWS_WITH_SERVER)
707
    if (lws_http_transaction_completed(wsi))
708
      return -1;
709
#endif
710
    return 0;
711
712
  case LWS_CALLBACK_CGI_STDIN_DATA:  /* POST body for stdin */
713
    args = (struct lws_cgi_args *)in;
714
    args->data[args->len] = '\0';
715
    if (!args->stdwsi[LWS_STDIN])
716
      return -1;
717
    n = lws_get_socket_fd(args->stdwsi[LWS_STDIN]);
718
    if (n < 0)
719
      return -1;
720
721
#if defined(LWS_WITH_ZLIB)
722
    if (wsi->http.cgi->gzip_inflate) {
723
      /* gzip handling */
724
725
      if (!wsi->http.cgi->gzip_init) {
726
        lwsl_wsi_info(wsi, "inflating gzip");
727
728
        memset(&wsi->http.cgi->inflate, 0,
729
               sizeof(wsi->http.cgi->inflate));
730
731
        if (inflateInit2(&wsi->http.cgi->inflate,
732
             16 + 15) != Z_OK) {
733
          lwsl_wsi_err(wsi, "iniflateInit fail");
734
          return -1;
735
        }
736
737
        wsi->http.cgi->gzip_init = 1;
738
      }
739
740
      wsi->http.cgi->inflate.next_in = args->data;
741
      wsi->http.cgi->inflate.avail_in = (unsigned int)args->len;
742
743
      do {
744
745
        wsi->http.cgi->inflate.next_out =
746
            wsi->http.cgi->inflate_buf;
747
        wsi->http.cgi->inflate.avail_out =
748
          sizeof(wsi->http.cgi->inflate_buf);
749
750
        n = inflate(&wsi->http.cgi->inflate,
751
              Z_SYNC_FLUSH);
752
753
        switch (n) {
754
        case Z_NEED_DICT:
755
        case Z_STREAM_ERROR:
756
        case Z_DATA_ERROR:
757
        case Z_MEM_ERROR:
758
          inflateEnd(&wsi->http.cgi->inflate);
759
          wsi->http.cgi->gzip_init = 0;
760
          lwsl_wsi_err(wsi, "zlib err inflate %d", n);
761
          return -1;
762
        }
763
764
        if (wsi->http.cgi->inflate.avail_out !=
765
             sizeof(wsi->http.cgi->inflate_buf)) {
766
          int written;
767
768
          written = (int)write(args->stdwsi[LWS_STDIN]->desc.filefd,
769
            wsi->http.cgi->inflate_buf,
770
            sizeof(wsi->http.cgi->inflate_buf) -
771
            wsi->http.cgi->inflate.avail_out);
772
773
          if (written != (int)(
774
            sizeof(wsi->http.cgi->inflate_buf) -
775
            wsi->http.cgi->inflate.avail_out)) {
776
            lwsl_wsi_notice(wsi,
777
              "CGI_STDIN_DATA: "
778
              "sent %d only %d went",
779
              n, args->len);
780
          }
781
782
          if (n == Z_STREAM_END) {
783
            lwsl_wsi_err(wsi,
784
                  "gzip inflate end");
785
            inflateEnd(&wsi->http.cgi->inflate);
786
            wsi->http.cgi->gzip_init = 0;
787
            break;
788
          }
789
790
        } else
791
          break;
792
793
        if (wsi->http.cgi->inflate.avail_out)
794
          break;
795
796
      } while (1);
797
798
      return args->len;
799
    }
800
#endif /* WITH_ZLIB */
801
802
    n = (int)write(n, args->data, (unsigned int)args->len);
803
//    lwsl_hexdump_notice(args->data, args->len);
804
    if (n < args->len)
805
      lwsl_wsi_notice(wsi, "CGI_STDIN_DATA: "
806
            "sent %d only %d went", n, args->len);
807
808
    lwsl_wsi_info(wsi, "proxied %d bytes", n);
809
810
    if (wsi->http.cgi->post_in_expected && args->stdwsi[LWS_STDIN] &&
811
        args->stdwsi[LWS_STDIN]->desc.filefd > 0) {
812
      wsi->http.cgi->post_in_expected -= (unsigned int)n;
813
814
      if (!wsi->http.cgi->post_in_expected) {
815
        struct lws *siwsi = args->stdwsi[LWS_STDIN];
816
817
        /*
818
         * The situation here is that we finished
819
         * proxying the incoming body from the net to
820
         * the STDIN stdwsi... and we want to close it
821
         * so it can understand we are done (necessary
822
         * if no content-length)...
823
         */
824
825
        lwsl_wsi_info(siwsi, "expected POST in end: "
826
                 "closing stdin fd %d",
827
                 siwsi->desc.sockfd);
828
829
        /*
830
         * We don't want the child / parent relationship
831
         * to be handled in close, since we want the
832
         * rest of the cgi and children to stay up
833
         */
834
835
        lws_remove_child_from_any_parent(siwsi);
836
        lws_wsi_close(siwsi, LWS_TO_KILL_ASYNC);
837
        wsi->http.cgi->lsp->stdwsi[LWS_STDIN] = NULL;
838
        lws_spawn_stdwsi_closed(wsi->http.cgi->lsp, siwsi);
839
      }
840
    }
841
842
    return n;
843
#endif /* WITH_CGI */
844
0
#endif /* ROLE_ H1 / H2 */
845
0
  case LWS_CALLBACK_SSL_INFO:
846
0
    si = in;
847
848
0
    (void)si;
849
0
    lwsl_wsi_notice(wsi, "SSL_INFO: where: 0x%x, ret: 0x%x",
850
0
        si->where, si->ret);
851
0
    break;
852
853
#if LWS_MAX_SMP > 1
854
  case LWS_CALLBACK_GET_THREAD_ID:
855
#ifdef __PTW32_H
856
    /* If we use implementation of PThreads for Win that is
857
     * distributed by VCPKG */
858
    return (int)(lws_intptr_t)(pthread_self()).p;
859
#else
860
    return (int)(lws_intptr_t)pthread_self();
861
#endif // __PTW32_H
862
#endif
863
864
0
  default:
865
0
    break;
866
0
  }
867
868
0
  return 0;
869
0
}