Coverage Report

Created: 2026-02-26 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwebsockets/lib/secure-streams/protocols/ss-h1.c
Line
Count
Source
1
/*
2
 * libwebsockets - small server side websockets and web server implementation
3
 *
4
 * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to
8
 * deal in the Software without restriction, including without limitation the
9
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10
 * sell copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22
 * IN THE SOFTWARE.
23
 *
24
 * This is the glue that wires up h1 to Secure Streams.
25
 */
26
27
#include <private-lib-core.h>
28
29
#if !defined(LWS_PLAT_FREERTOS) || defined(LWS_ROLE_H2)
30
#define LWS_WITH_SS_RIDESHARE
31
#endif
32
33
#if defined(LWS_WITH_SS_RIDESHARE)
34
static int
35
ss_http_multipart_parser(lws_ss_handle_t *h, void *in, size_t len)
36
0
{
37
0
  uint8_t *q = (uint8_t *)in;
38
0
  int pending_issue = 0, n = 0;
39
40
41
  /* let's stick it in the boundary state machine first */
42
0
  while (n < (int)len) {
43
0
    if (h->u.http.boundary_seq != h->u.http.boundary_len) {
44
0
      if (q[n] == h->u.http.boundary[h->u.http.boundary_seq])
45
0
        h->u.http.boundary_seq++;
46
0
      else {
47
0
        h->u.http.boundary_seq = 0;
48
0
        h->u.http.boundary_dashes = 0;
49
0
        h->u.http.boundary_post = 0;
50
0
      }
51
0
      goto around;
52
0
    }
53
54
    /*
55
     * We already matched the boundary string, now we're
56
     * looking if there's a -- afterwards
57
     */
58
0
    if (h->u.http.boundary_dashes < 2) {
59
0
      if (q[n] == '-') {
60
0
        h->u.http.boundary_dashes++;
61
0
        goto around;
62
0
      }
63
      /* there was no final -- ... */
64
0
    }
65
66
0
    if (h->u.http.boundary_dashes == 2) {
67
      /*
68
       * It's an EOM boundary: issue pending + multipart EOP
69
       */
70
0
      lwsl_debug("%s: seen EOP, n %d pi %d\n",
71
0
            __func__, n, pending_issue);
72
      /*
73
       * It's possible we already started the decode before
74
       * the end of the last packet.  Then there is no
75
       * remainder to send.
76
       */
77
0
      if (n >= pending_issue + h->u.http.boundary_len +
78
0
          (h->u.http.any ? 2 : 0) + 1) {
79
0
        h->info.rx(ss_to_userobj(h),
80
0
             &q[pending_issue],
81
0
             (unsigned int)(n - pending_issue -
82
0
             h->u.http.boundary_len - 1 -
83
0
             (h->u.http.any ? 2 : 0) /* crlf */),
84
0
           (!h->u.http.som ? LWSSS_FLAG_SOM : 0) |
85
0
           LWSSS_FLAG_EOM | LWSSS_FLAG_RELATED_END);
86
0
        h->u.http.eom = 1;
87
0
      }
88
89
      /*
90
       * Peer may not END_STREAM us
91
       */
92
0
      return 0;
93
      //return -1;
94
0
    }
95
96
    /* how about --boundaryCRLF */
97
98
0
    if (h->u.http.boundary_post < 2) {
99
0
      if ((!h->u.http.boundary_post && q[n] == '\x0d') ||
100
0
          (h->u.http.boundary_post && q[n] == '\x0a')) {
101
0
        h->u.http.boundary_post++;
102
0
        goto around;
103
0
      }
104
      /* there was no final CRLF ... it's wrong */
105
106
0
      return -1;
107
0
    }
108
0
    if (h->u.http.boundary_post != 2)
109
0
      goto around;
110
111
    /*
112
     * We have a starting "--boundaryCRLF" or intermediate
113
     * "CRLF--boundaryCRLF" boundary
114
     */
115
0
    lwsl_debug("%s: b_post = 2 (pi %d)\n", __func__, pending_issue);
116
0
    h->u.http.boundary_seq = 0;
117
0
    h->u.http.boundary_post = 0;
118
119
0
    if (n >= pending_issue && (h->u.http.any || !h->u.http.som)) {
120
      /* Intermediate... do the EOM */
121
0
      lwsl_debug("%s: seen interm EOP n %d pi %d\n", __func__,
122
0
           n, pending_issue);
123
      /*
124
       * It's possible we already started the decode before
125
       * the end of the last packet.  Then there is no
126
       * remainder to send.
127
       */
128
0
      if (n >= pending_issue + h->u.http.boundary_len +
129
0
          (h->u.http.any ? 2 : 0)) {
130
0
        h->info.rx(ss_to_userobj(h), &q[pending_issue],
131
0
             (unsigned int)(n - pending_issue -
132
0
                 h->u.http.boundary_len -
133
0
                 (h->u.http.any ? 2 /* crlf */ : 0)),
134
0
             (!h->u.http.som ? LWSSS_FLAG_SOM : 0) |
135
0
             LWSSS_FLAG_EOM);
136
0
        h->u.http.eom = 1;
137
0
      }
138
0
    }
139
140
    /* Next message starts after this boundary */
141
142
0
    pending_issue = n;
143
0
    if (h->u.http.eom) {
144
      /* reset only if we have sent eom */
145
0
      h->u.http.som = 0;
146
0
      h->u.http.eom = 0;
147
0
    }
148
149
0
around:
150
0
    n++;
151
0
  }
152
153
0
  if (pending_issue != n) {
154
0
    uint8_t oh = 0;
155
156
    /*
157
     * handle the first or last "--boundaryCRLF" case which is not captured in the
158
     * previous loop, on the Bob downchannel (/directive)
159
     *
160
     * probably does not cover the case that one boundary term is separated in multipile
161
     * one callbacks though never see such case
162
     */
163
164
0
    if ((n >= h->u.http.boundary_len) &&
165
0
      h->u.http.boundary_seq == h->u.http.boundary_len &&
166
0
      h->u.http.boundary_post == 2) {
167
168
0
      oh = 1;
169
0
    }
170
171
0
    h->info.rx(ss_to_userobj(h), &q[pending_issue],
172
0
        (unsigned int)(oh ?
173
0
        (n - pending_issue - h->u.http.boundary_len -
174
0
          (h->u.http.any ? 2 : 0)) :
175
0
        (n - pending_issue)),
176
0
         (!h->u.http.som ? LWSSS_FLAG_SOM : 0) |
177
0
           (oh && h->u.http.any ? LWSSS_FLAG_EOM : 0));
178
179
0
    if (oh && h->u.http.any)
180
0
      h->u.http.eom = 1;
181
182
0
    h->u.http.any = 1;
183
0
    h->u.http.som = 1;
184
0
  }
185
186
0
  return 0;
187
0
}
188
#endif
189
190
/*
191
 * Returns 0, or the ss state resp maps on to
192
 */
193
194
static int
195
lws_ss_http_resp_to_state(lws_ss_handle_t *h, int resp)
196
0
{
197
0
  const lws_ss_http_respmap_t *r = h->policy->u.http.respmap;
198
0
  int n = h->policy->u.http.count_respmap;
199
200
0
  while (n--)
201
0
    if (resp == r->resp)
202
0
      return r->state;
203
0
    else
204
0
      r++;
205
206
0
  return 0; /* no hit */
207
0
}
208
209
/*
210
 * This converts any set metadata items into outgoing http headers
211
 */
212
213
static int
214
lws_apply_metadata(lws_ss_handle_t *h, struct lws *wsi, uint8_t *buf,
215
       uint8_t **pp, uint8_t *end)
216
0
{
217
0
  lws_ss_metadata_t *polmd = h->policy->metadata;
218
0
  int m = 0;
219
220
0
  while (polmd) {
221
222
    /* has to have a non-empty header string */
223
224
0
    if (polmd->value__may_own_heap &&
225
0
        ((uint8_t *)polmd->value__may_own_heap)[0] &&
226
0
        h->metadata[m].value__may_own_heap) {
227
0
      if (lws_add_http_header_by_name(wsi,
228
0
          polmd->value__may_own_heap,
229
0
          h->metadata[m].value__may_own_heap,
230
0
          (int)h->metadata[m].length, pp, end))
231
0
      return -1;
232
233
      /*
234
       * Check for the case he's setting a non-zero
235
       * content-length "via the backdoor" metadata-
236
       * driven headers, and set the body_pending()
237
       * state if so...
238
       */
239
240
0
      if (!strncmp(polmd->value__may_own_heap,
241
0
             "content-length", 14) &&
242
0
          atoi(h->metadata[m].value__may_own_heap))
243
0
        lws_client_http_body_pending(wsi, 1);
244
0
    }
245
246
0
    m++;
247
0
    polmd = polmd->next;
248
0
  }
249
250
  /*
251
   * Content-length on POST / PUT / PATCH if we have the length information
252
   */
253
254
0
  if (h->policy->u.http.method && (
255
0
#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_HTTP_HEADERS_ALL)
256
0
     !strcmp(h->policy->u.http.method, "PATCH") ||
257
0
     !strcmp(h->policy->u.http.method, "PUT") ||
258
0
#endif
259
0
    (!strcmp(h->policy->u.http.method, "POST"))) &&
260
0
      wsi->http.writeable_len) {
261
0
    if (!(h->policy->flags &
262
0
      LWSSSPOLF_HTTP_NO_CONTENT_LENGTH)) {
263
0
      int n = lws_snprintf((char *)buf, 20, "%u",
264
0
        (unsigned int)wsi->http.writeable_len);
265
0
      if (lws_add_http_header_by_token(wsi,
266
0
          WSI_TOKEN_HTTP_CONTENT_LENGTH,
267
0
          buf, n, pp, end))
268
0
        return -1;
269
0
    }
270
0
    lws_client_http_body_pending(wsi, 1);
271
0
  }
272
273
0
  return 0;
274
0
}
275
276
277
#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
278
static int
279
lws_apply_instant_metadata(lws_ss_handle_t *h, struct lws *wsi, uint8_t *buf,
280
       uint8_t **pp, uint8_t *end)
281
{
282
  lws_ss_metadata_t *imd = h->instant_metadata;
283
284
  while (imd) {
285
    if (imd->name && imd->value__may_own_heap) {
286
      lwsl_debug("%s add header %s %s %d\n", __func__,
287
                     imd->name,
288
                                 (char *)imd->value__may_own_heap,
289
               (int)imd->length);
290
      if (lws_add_http_header_by_name(wsi,
291
          (const unsigned char *)imd->name,
292
          (const unsigned char *)imd->value__may_own_heap,
293
          (int)imd->length, pp, end))
294
      return -1;
295
296
      /* it's possible user set content-length directly */
297
      if (!strncmp(imd->name,
298
             "content-length", 14) &&
299
          atoi(imd->value__may_own_heap))
300
        lws_client_http_body_pending(wsi, 1);
301
302
    }
303
304
    imd = imd->next;
305
  }
306
307
  return 0;
308
}
309
#endif
310
/*
311
 * Check if any metadata headers present in the server headers, and record
312
 * them into the associated metadata item if so.
313
 */
314
315
static int
316
lws_extract_metadata(lws_ss_handle_t *h, struct lws *wsi)
317
0
{
318
0
  lws_ss_metadata_t *polmd = h->policy->metadata, *omd;
319
0
  int n;
320
321
0
  while (polmd) {
322
323
0
    if (polmd->value_is_http_token != LWS_HTTP_NO_KNOWN_HEADER) {
324
325
      /* it's a well-known header token */
326
327
0
      n = lws_hdr_total_length(wsi, polmd->value_is_http_token);
328
0
      if (n) {
329
0
        const char *cp = lws_hdr_simple_ptr(wsi,
330
0
            polmd->value_is_http_token);
331
0
        omd = lws_ss_get_handle_metadata(h, polmd->name);
332
0
        if (!omd || !cp)
333
0
          return 1;
334
335
0
        assert(!strcmp(omd->name, polmd->name));
336
337
        /*
338
         * it's present on the wsi, we want to
339
         * set the related metadata name to it then
340
         */
341
342
0
        _lws_ss_alloc_set_metadata(omd, polmd->name, cp,
343
0
                 (unsigned int)n);
344
345
#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
346
        /*
347
         * ...and because we are doing it from parsing
348
         * onward rx, we want to mark the metadata as
349
         * needing passing to the client
350
         */
351
        omd->pending_onward = 1;
352
#endif
353
0
      }
354
0
    }
355
356
0
#if defined(LWS_WITH_CUSTOM_HEADERS)
357
0
    else
358
359
      /* has to have a non-empty header string */
360
361
0
      if (polmd->value__may_own_heap &&
362
0
          ((uint8_t *)polmd->value__may_own_heap)[0]) {
363
0
        char *p;
364
365
        /*
366
         * Can it be a custom header?
367
         */
368
369
0
        n = lws_hdr_custom_length(wsi, (const char *)
370
0
                polmd->value__may_own_heap,
371
0
                polmd->value_length);
372
0
        if (n > 0) {
373
0
          int r;
374
375
0
          p = lws_malloc((unsigned int)n + 1, __func__);
376
0
          if (!p)
377
0
            return 1;
378
379
          /*
380
           * copy the named custom header value
381
           * into the malloc'd buffer
382
           */
383
384
0
          r = lws_hdr_custom_copy(wsi, p, n + 1,
385
0
                 (const char *)
386
0
                 polmd->value__may_own_heap,
387
0
                 polmd->value_length);
388
389
          /* if needed, free any previous value */
390
391
0
          if (polmd->value_on_lws_heap) {
392
0
            lws_free(
393
0
                polmd->value__may_own_heap);
394
0
            polmd->value_on_lws_heap = 0;
395
0
          }
396
397
0
          if (r < 0) {
398
0
            lws_free(p);
399
400
0
            return 1;
401
0
          }
402
403
0
          omd = lws_ss_get_handle_metadata(h,
404
0
                   polmd->name);
405
0
          if (omd) {
406
407
0
            _lws_ss_set_metadata(omd,
408
0
              polmd->name, p, (size_t)n);
409
0
            omd->value_on_lws_heap = 1;
410
411
#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
412
            omd->pending_onward = 1;
413
#endif
414
0
          }
415
0
        }
416
0
      }
417
0
#endif
418
419
0
    polmd = polmd->next;
420
0
  }
421
422
0
  return 0;
423
0
}
424
425
static const uint8_t blob_idx[] = {
426
  LWS_SYSBLOB_TYPE_AUTH,
427
  LWS_SYSBLOB_TYPE_DEVICE_SERIAL,
428
  LWS_SYSBLOB_TYPE_DEVICE_FW_VERSION,
429
  LWS_SYSBLOB_TYPE_DEVICE_TYPE,
430
};
431
432
int
433
secstream_h1(struct lws *wsi, enum lws_callback_reasons reason, void *user,
434
       void *in, size_t len)
435
0
{
436
0
#if defined(LWS_WITH_SERVER)
437
0
  struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
438
0
#endif
439
0
  lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi);
440
0
  uint8_t buf[LWS_PRE + 1520], *p = &buf[LWS_PRE],
441
0
#if defined(LWS_WITH_SERVER)
442
0
      *start = p,
443
0
#endif
444
0
    *end = &buf[sizeof(buf) - 1];
445
0
  lws_ss_state_return_t r;
446
0
  int f = 0, m, status;
447
0
  char conceal_eom = 0;
448
0
  lws_usec_t inter;
449
0
  size_t buflen;
450
451
0
  switch (reason) {
452
453
0
  case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
454
0
    if (!h) {
455
0
      lwsl_notice("%s: CCE with no ss handle %s\n", __func__, lws_wsi_tag(wsi));
456
0
      break;
457
0
    }
458
459
0
    lws_ss_assert_extant(wsi->a.context, wsi->tsi, h);
460
461
0
    assert(h->policy);
462
463
0
#if defined(LWS_WITH_CONMON)
464
0
    lws_conmon_ss_json(h);
465
0
#endif
466
467
0
    lws_metrics_caliper_report_hist(h->cal_txn, wsi);
468
0
    lwsl_info("%s: %s CLIENT_CONNECTION_ERROR: %s\n", __func__,
469
0
        h->lc.gutag, in ? (const char *)in : "none");
470
0
    if (h->ss_dangling_connected) {
471
      /* already disconnected, no action for DISCONNECT_ME */
472
0
      r = lws_ss_event_helper(h, LWSSSCS_DISCONNECTED);
473
0
      if (r != LWSSSSRET_OK)
474
0
        return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
475
0
    } else {
476
      /* already disconnected, no action for DISCONNECT_ME */
477
0
      r = lws_ss_event_helper(h, LWSSSCS_UNREACHABLE);
478
0
      if (r) {
479
0
        if (h->inside_connect) {
480
0
          h->pending_ret = r;
481
0
          break;
482
0
        }
483
484
0
        return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
485
0
      }
486
0
    }
487
488
0
    h->wsi = NULL;
489
0
    r = lws_ss_backoff(h);
490
0
    if (r != LWSSSSRET_OK) {
491
0
      if (h->inside_connect) {
492
0
        h->pending_ret = r;
493
0
        break;
494
0
      }
495
0
      return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
496
0
    }
497
0
    break;
498
499
0
  case LWS_CALLBACK_CLIENT_HTTP_REDIRECT:
500
501
0
    if (!h)
502
0
      return -1;
503
504
0
    if (h->policy->u.http.fail_redirect)
505
0
      lws_system_cpd_set(lws_get_context(wsi),
506
0
             LWS_CPD_CAPTIVE_PORTAL);
507
    /* unless it's explicitly allowed, reject to follow it */
508
0
    return !(h->policy->flags & LWSSSPOLF_ALLOW_REDIRECTS);
509
510
0
  case LWS_CALLBACK_CLOSED_HTTP: /* server */
511
0
  case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
512
0
    if (!h)
513
0
      break;
514
515
0
    h->txn_n_acked = 0;
516
    // lws_sul_cancel(&h->sul_timeout);
517
518
0
    lws_ss_assert_extant(wsi->a.context, wsi->tsi, h);
519
520
0
#if defined(LWS_WITH_CONMON)
521
0
    if (wsi->conmon.pcol == LWSCONMON_PCOL_NONE) {
522
0
      wsi->conmon.pcol = LWSCONMON_PCOL_HTTP;
523
0
      wsi->conmon.protocol_specific.http.response =
524
0
          (int)lws_http_client_http_response(wsi);
525
0
    }
526
527
0
    lws_conmon_ss_json(h);
528
0
#endif
529
530
0
    lws_metrics_caliper_report_hist(h->cal_txn, wsi);
531
    //lwsl_notice("%s: %s LWS_CALLBACK_CLOSED_CLIENT_HTTP\n",
532
    //    __func__, wsi->lc.gutag);
533
534
0
    h->wsi = NULL;
535
0
    h->hanging_som = 0;
536
0
    h->subseq = 0;
537
538
0
#if defined(LWS_WITH_SERVER)
539
0
    lws_pt_lock(pt, __func__);
540
0
    lws_dll2_remove(&h->cli_list);
541
0
    lws_pt_unlock(pt);
542
0
#endif
543
544
0
    if (h->policy && !(h->policy->flags & LWSSSPOLF_OPPORTUNISTIC) &&
545
0
#if defined(LWS_WITH_SERVER)
546
0
        !(h->info.flags & LWSSSINFLAGS_ACCEPTED) && /* not server */
547
0
#endif
548
0
        !h->txn_ok && !wsi->a.context->being_destroyed) {
549
0
      r = lws_ss_backoff(h);
550
0
      if (r != LWSSSSRET_OK)
551
0
        return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
552
0
      if (h->seqstate == SSSEQ_IDLE)
553
0
        lws_sul_cancel(&h->sul_timeout);
554
555
0
      break;
556
0
    } else {
557
0
      h->seqstate = SSSEQ_IDLE;
558
0
      lws_sul_cancel(&h->sul_timeout);
559
0
    }
560
561
0
    if (h->ss_dangling_connected) {
562
      /* already disconnected, no action for DISCONNECT_ME */
563
0
      r = lws_ss_event_helper(h, LWSSSCS_DISCONNECTED);
564
0
      if (r == LWSSSSRET_DESTROY_ME)
565
0
        return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
566
0
    }
567
0
    break;
568
569
0
  case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
570
571
0
    if (!h)
572
0
      return -1;
573
574
0
    lws_ss_assert_extant(wsi->a.context, wsi->tsi, h);
575
0
    h->wsi = wsi; /* since we accept the wsi is bound to the SS,
576
             * ensure the SS feels the same way about the wsi */
577
578
0
#if defined(LWS_WITH_CONMON)
579
0
    if (wsi->conmon.pcol == LWSCONMON_PCOL_NONE) {
580
0
      wsi->conmon.pcol = LWSCONMON_PCOL_HTTP;
581
0
      wsi->conmon.protocol_specific.http.response =
582
0
          (int)lws_http_client_http_response(wsi);
583
0
    }
584
585
0
    lws_conmon_ss_json(h);
586
0
#endif
587
588
0
    status = (int)lws_http_client_http_response(wsi);
589
0
    lwsl_info("%s: LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: %d\n", __func__, status);
590
  //  if (!status)
591
      /* it's just telling use we connected / joined the nwsi */
592
  //    break;
593
594
#if defined(LWS_WITH_SYS_METRICS)
595
    if (status) {
596
      lws_snprintf((char *)buf, 10, "%d", status);
597
      lws_metrics_tag_ss_add(h, "http_resp", (char *)buf);
598
    }
599
#endif
600
601
0
    if (status == HTTP_STATUS_SERVICE_UNAVAILABLE /* 503 */ ||
602
0
        status == 429 /* Too many requests */) {
603
      /*
604
       * We understand this attempt failed, and that we should
605
       * conceal this attempt.  If there's a specified
606
       * retry-after, we should use that if larger than our
607
       * computed backoff
608
       */
609
610
0
      inter = 0;
611
0
      lws_http_check_retry_after(wsi, &inter);
612
613
0
      r = _lws_ss_backoff(h, inter);
614
0
      if (r != LWSSSSRET_OK)
615
0
        return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
616
617
0
      return -1; /* end this stream */
618
0
    }
619
620
0
    if (h->policy->u.http.resp_expect)
621
0
      h->u.http.good_respcode =
622
0
          status == h->policy->u.http.resp_expect;
623
0
    else
624
0
      h->u.http.good_respcode = (status >= 200 && status < 300);
625
    // lwsl_err("%s: good resp %d %d\n", __func__, status, h->u.http.good_respcode);
626
627
0
    if (lws_extract_metadata(h, wsi)) {
628
0
      lwsl_info("%s: rx metadata extract failed\n", __func__);
629
630
0
      return -1;
631
0
    }
632
633
0
    if (status) {
634
      /*
635
       * Check and see if it's something from the response
636
       * map, if so, generate the requested status.  If we're
637
       * the proxy onward connection, metadata has priority
638
       * over state updates on the serialization, so the
639
       * state callback will see the right metadata.
640
       */
641
0
      int n = lws_ss_http_resp_to_state(h, status);
642
0
      if (n) {
643
0
        r = lws_ss_event_helper(h, (lws_ss_constate_t)n);
644
0
        if (r != LWSSSSRET_OK)
645
0
          return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi,
646
0
                  &h);
647
0
      }
648
0
    }
649
650
0
    if (h->u.http.good_respcode)
651
0
      lwsl_info("%s: Connected streamtype %s, %d\n", __func__,
652
0
        h->policy->streamtype, status);
653
0
    else
654
0
      lwsl_info("%s: Connected streamtype %s, BAD %d\n",
655
0
        __func__, h->policy->streamtype, status);
656
657
0
    h->hanging_som = 0;
658
659
0
    h->retry = 0;
660
0
    h->seqstate = SSSEQ_CONNECTED;
661
0
    lws_sul_cancel(&h->sul);
662
663
0
    if (h->prev_ss_state != LWSSSCS_CONNECTED) {
664
0
      wsi->client_suppress_CONNECTION_ERROR = 1;
665
      /*
666
       * back-to-back http transactions otherwise go
667
       * DISCONNECTED -> CONNECTED, we should insert
668
       * CONNECTING inbetween
669
       */
670
0
      if (h->prev_ss_state == LWSSSCS_DISCONNECTED) {
671
0
        r = lws_ss_event_helper(h, LWSSSCS_CONNECTING);
672
0
        if (r != LWSSSSRET_OK)
673
0
          return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
674
0
      }
675
0
                       if (h->prev_ss_state != LWSSSCS_CONNECTED &&
676
0
                           h->prev_ss_state != LWSSSCS_QOS_ACK_REMOTE &&
677
0
                           h->prev_ss_state != LWSSSCS_QOS_NACK_REMOTE) {
678
                               // lwsl_ss_notice(h, "HTTP_ESTABLISHED");
679
0
        r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
680
0
        if (r != LWSSSSRET_OK)
681
0
          return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
682
0
      }
683
0
    }
684
685
    /*
686
     * Since it's an http transaction we initiated... this is
687
     * proof of connection validity
688
     */
689
0
    lws_validity_confirmed(wsi);
690
691
0
#if defined(LWS_WITH_SS_RIDESHARE)
692
693
    /*
694
     * There are two ways we might want to deal with multipart,
695
     * one is pass it through raw (although the user code needs
696
     * a helping hand for learning the boundary), and the other
697
     * is to deframe it and provide basically submessages in the
698
     * different parts.
699
     */
700
701
0
    if (lws_hdr_copy(wsi, (char *)buf, sizeof(buf),
702
0
         WSI_TOKEN_HTTP_CONTENT_TYPE) > 0 &&
703
    /* multipart/form-data;
704
     * boundary=----WebKitFormBoundarycc7YgAPEIHvgE9Bf */
705
706
0
        (!strncmp((char *)buf, "multipart/form-data", 19) ||
707
0
         !strncmp((char *)buf, "multipart/related", 17))) {
708
0
      struct lws_tokenize ts;
709
0
      lws_tokenize_elem e;
710
711
      // puts((const char *)buf);
712
713
0
      memset(&ts, 0, sizeof(ts));
714
0
      ts.start = (char *)buf;
715
0
      ts.len = strlen(ts.start);
716
0
      ts.flags = LWS_TOKENIZE_F_RFC7230_DELIMS |
717
0
          LWS_TOKENIZE_F_SLASH_NONTERM |
718
0
          LWS_TOKENIZE_F_MINUS_NONTERM;
719
720
0
      h->u.http.boundary[0] = '\0';
721
0
      do {
722
0
        e = lws_tokenize(&ts);
723
0
        if (e == LWS_TOKZE_TOKEN_NAME_EQUALS &&
724
0
            !strncmp(ts.token, "boundary", 8) &&
725
0
            ts.token_len == 8) {
726
0
          e = lws_tokenize(&ts);
727
0
          if (e != LWS_TOKZE_TOKEN)
728
0
            goto malformed;
729
0
          h->u.http.boundary[0] = '\x0d';
730
0
          h->u.http.boundary[1] = '\x0a';
731
0
          h->u.http.boundary[2] = '-';
732
0
          h->u.http.boundary[3] = '-';
733
0
          lws_strnncpy(h->u.http.boundary + 4,
734
0
                 ts.token, ts.token_len,
735
0
                 sizeof(h->u.http.boundary) - 4);
736
0
          h->u.http.boundary_len =
737
0
            (uint8_t)(ts.token_len + 4);
738
0
          h->u.http.boundary_seq = 2;
739
0
          h->u.http.boundary_dashes = 0;
740
0
        }
741
0
      } while (e > 0);
742
0
      lwsl_info("%s: multipart boundary '%s' len %d\n", __func__,
743
0
          h->u.http.boundary, h->u.http.boundary_len);
744
745
      /* inform the ss that a related message group begins */
746
747
0
      if ((h->policy->flags & LWSSSPOLF_HTTP_MULTIPART_IN) &&
748
0
          h->u.http.boundary[0])
749
0
        h->info.rx(ss_to_userobj(h), NULL, 0,
750
0
             LWSSS_FLAG_RELATED_START);
751
752
      // lws_header_table_detach(wsi, 0);
753
0
    }
754
0
    break;
755
0
malformed:
756
0
    lwsl_notice("%s: malformed multipart header\n", __func__);
757
0
    return -1;
758
#else
759
    break;
760
#endif
761
762
0
  case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
763
0
    if (!h)
764
0
      return -1;
765
0
    if (h->writeable_len)
766
0
      wsi->http.writeable_len = h->writeable_len;
767
768
0
    {
769
0
      uint8_t **p = (uint8_t **)in, *end = (*p) + len,
770
0
        *oin = *(uint8_t **)in;
771
772
    /*
773
     * blob-based headers
774
     */
775
776
0
    for (m = 0; m < _LWSSS_HBI_COUNT; m++) {
777
0
      lws_system_blob_t *ab;
778
0
      int o = 0, n;
779
780
0
      if (!h->policy->u.http.blob_header[m])
781
0
        continue;
782
783
      /*
784
       * To be backward compatible, default is system-wide LWA auth,
785
       * and "http_auth_header" is for default LWA auth, current users do not
786
       * need any change in their policy.
787
       * If user wants different auth/token, need to specify the "use_auth"
788
       * and will be handled after metadata headers are applied.
789
       */
790
791
0
      if (m == LWSSS_HBI_AUTH &&
792
0
          h->policy->u.http.auth_preamble)
793
0
        o = lws_snprintf((char *)buf, sizeof(buf), "%s",
794
0
          h->policy->u.http.auth_preamble);
795
796
0
      if (o > (int)sizeof(buf) - 2)
797
0
        return -1;
798
799
0
      ab = lws_system_get_blob(wsi->a.context, blob_idx[m], 0);
800
0
      if (!ab)
801
0
        return -1;
802
803
0
      buflen = sizeof(buf) - (unsigned int)o - 2u;
804
0
      n = lws_system_blob_get(ab, buf + o, &buflen, 0);
805
0
      if (n < 0)
806
0
        return -1;
807
808
0
      buf[(unsigned int)o + buflen] = '\0';
809
0
      lwsl_debug("%s: adding blob %d: %s\n", __func__, m, buf);
810
811
0
      if (lws_add_http_header_by_name(wsi,
812
0
         (uint8_t *)h->policy->u.http.blob_header[m],
813
0
         buf, (int)((int)buflen + o), p, end))
814
0
        return -1;
815
0
    }
816
817
    /*
818
     * metadata-based headers
819
     */
820
821
0
    if (lws_apply_metadata(h, wsi, buf, p, end))
822
0
      return -1;
823
824
#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
825
    if (h->policy->flags & LWSSSPOLF_DIRECT_PROTO_STR) {
826
      if (lws_apply_instant_metadata(h, wsi, buf, p, end))
827
        return -1;
828
    }
829
#endif
830
831
#if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
832
    if (h->policy->auth && h->policy->auth->type &&
833
        !strcmp(h->policy->auth->type, "sigv4")) {
834
835
      if (lws_ss_apply_sigv4(wsi, h, p, end))
836
        return -1;
837
    }
838
#endif
839
840
841
0
    (void)oin;
842
    //if (*p != oin)
843
    //  lwsl_hexdump_notice(oin, lws_ptr_diff_size_t(*p, oin));
844
845
0
    }
846
847
    /*
848
     * So when proxied, for POST we have to synthesize a CONNECTED
849
     * state, so it can request a writeable and deliver the POST
850
     * body
851
     */
852
0
    if ((h->policy->protocol == LWSSSP_H1 ||
853
0
         h->policy->protocol == LWSSSP_H2) &&
854
0
         h->being_serialized && (
855
0
#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_HTTP_HEADERS_ALL)
856
0
        !strcmp(h->policy->u.http.method, "PUT") ||
857
0
        !strcmp(h->policy->u.http.method, "PATCH") ||
858
0
#endif
859
0
        !strcmp(h->policy->u.http.method, "POST"))) {
860
861
0
      wsi->client_suppress_CONNECTION_ERROR = 1;
862
0
      if (h->prev_ss_state != LWSSSCS_CONNECTED) {
863
0
        r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
864
0
        if (r)
865
0
          return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
866
0
      }
867
0
    }
868
869
0
    break;
870
871
  /* chunks of chunked content, with header removed */
872
0
  case LWS_CALLBACK_HTTP_BODY:
873
0
  case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
874
0
    lwsl_debug("%s: RECEIVE_CLIENT_HTTP_READ: read %d\n",
875
0
        __func__, (int)len);
876
0
    if (!h || !h->info.rx)
877
0
      return 0;
878
879
0
#if defined(LWS_WITH_SS_RIDESHARE)
880
0
    if ((h->policy->flags & LWSSSPOLF_HTTP_MULTIPART_IN) &&
881
0
        h->u.http.boundary[0])
882
0
      return ss_http_multipart_parser(h, in, len);
883
0
#endif
884
885
0
    if (!h->subseq) {
886
0
      f |= LWSSS_FLAG_SOM;
887
0
      h->hanging_som = 1;
888
0
      h->subseq = 1;
889
0
    }
890
891
  //  lwsl_notice("%s: HTTP_READ: client side sent len %d fl 0x%x\n",
892
  //        __func__, (int)len, (int)f);
893
894
0
    h->wsi = wsi; /* since we accept the wsi is bound to the SS,
895
             * ensure the SS feels the same way about the wsi */
896
0
    r = h->info.rx(ss_to_userobj(h), (const uint8_t *)in, len, f);
897
0
    if (r != LWSSSSRET_OK)
898
0
      return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
899
900
0
    return 0; /* don't passthru */
901
902
  /* uninterpreted http content */
903
0
  case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
904
0
    {
905
0
      char *px = (char *)buf + LWS_PRE; /* guarantees LWS_PRE */
906
0
      int lenx = sizeof(buf) - LWS_PRE;
907
908
0
      m = lws_http_client_read(wsi, &px, &lenx);
909
0
      if (m < 0)
910
0
        return m;
911
0
    }
912
0
    lws_set_timeout(wsi, 99, 30);
913
914
0
    return 0; /* don't passthru */
915
916
0
  case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
917
    // lwsl_debug("%s: LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n", __func__);
918
919
0
    if (!h)
920
0
      return -1;
921
922
0
    if (h->hanging_som) {
923
0
      h->info.rx(ss_to_userobj(h), NULL, 0, LWSSS_FLAG_EOM);
924
0
      h->hanging_som = 0;
925
0
      h->subseq = 0;
926
0
    }
927
928
0
    wsi->http.writeable_len = h->writeable_len = 0;
929
0
    lws_sul_cancel(&h->sul_timeout);
930
931
0
    h->txn_ok = 1;
932
933
#if defined(LWS_WITH_SYS_METRICS)
934
    lws_metrics_tag_ss_add(h, "result",
935
               h->u.http.good_respcode ?
936
               "SS_ACK_REMOTE" : "SS_NACK_REMOTE");
937
#endif
938
939
0
    if (!h->ss_dangling_connected) {
940
0
      r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
941
0
      if (r != LWSSSSRET_OK)
942
0
        return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
943
0
    }
944
945
0
    if (!h->txn_n_acked) {
946
0
      h->txn_n_acked = 1;
947
0
      r = lws_ss_event_helper(h, h->u.http.good_respcode ?
948
0
            LWSSSCS_QOS_ACK_REMOTE :
949
0
            LWSSSCS_QOS_NACK_REMOTE);
950
0
      if (r != LWSSSSRET_OK)
951
0
        return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
952
0
    }
953
0
    lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
954
0
    break;
955
956
0
  case LWS_CALLBACK_HTTP_WRITEABLE:
957
0
  case LWS_CALLBACK_CLIENT_HTTP_WRITEABLE:
958
959
0
    if (!h || !h->info.tx) {
960
0
      lwsl_debug("%s: no handle / tx\n", __func__);
961
0
      return 0;
962
0
    }
963
964
0
#if defined(LWS_WITH_SERVER)
965
0
    if (h->txn_resp_pending) {
966
      /*
967
       * If we're going to start sending something, we need to
968
       * to take care of the http response header for it first
969
       */
970
0
      h->txn_resp_pending = 0;
971
972
0
      if (lws_add_http_common_headers(wsi,
973
0
          (unsigned int)(h->txn_resp_set ?
974
0
            (h->txn_resp ? h->txn_resp : 200) :
975
0
            HTTP_STATUS_NOT_FOUND),
976
0
          NULL,
977
0
          h->policy->flags & LWSSSPOLF_HTTP_NO_CONTENT_LENGTH ?
978
0
            LWS_ILLEGAL_HTTP_CONTENT_LEN :
979
0
            h->wsi->http.writeable_len,
980
0
          &p, end))
981
0
        return 1;
982
983
      /*
984
       * metadata-based headers
985
       */
986
987
0
      if (lws_apply_metadata(h, wsi, buf, &p, end))
988
0
        return -1;
989
990
0
      if (lws_finalize_write_http_header(wsi, start, &p, end))
991
0
        return 1;
992
993
      /* write the body separately */
994
0
      lws_callback_on_writable(wsi);
995
996
0
      return 0;
997
0
    }
998
0
#endif
999
1000
0
    if (
1001
0
#if defined(LWS_WITH_SERVER)
1002
0
        !(h->info.flags & LWSSSINFLAGS_ACCEPTED) && /* not accepted */
1003
0
#endif
1004
0
        !h->rideshare)
1005
1006
0
      h->rideshare = h->policy;
1007
1008
0
#if defined(LWS_WITH_SS_RIDESHARE)
1009
0
    if (
1010
0
#if defined(LWS_WITH_SERVER)
1011
0
        !(h->info.flags & LWSSSINFLAGS_ACCEPTED) && /* not accepted */
1012
0
#endif
1013
0
        !h->inside_msg && h->rideshare->u.http.multipart_name)
1014
0
      lws_client_http_multipart(wsi,
1015
0
        h->rideshare->u.http.multipart_name,
1016
0
        h->rideshare->u.http.multipart_filename,
1017
0
        h->rideshare->u.http.multipart_content_type,
1018
0
        (char **)&p, (char *)end);
1019
1020
0
    buflen = lws_ptr_diff_size_t(end, p);
1021
0
    if (h->policy->u.http.multipart_name)
1022
0
      buflen -= 24; /* allow space for end of multipart */
1023
#else
1024
    buflen = lws_ptr_diff_size_t(end, p);
1025
#endif
1026
0
    r = h->info.tx(ss_to_userobj(h), h->txord++, p, &buflen, &f);
1027
0
    if (r == LWSSSSRET_TX_DONT_SEND)
1028
0
      return 0;
1029
0
    if (r < 0)
1030
0
      return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
1031
1032
    // lwsl_notice("%s: WRITEABLE: user tx says len %d fl 0x%x\n",
1033
    //      __func__, (int)buflen, (int)f);
1034
1035
0
    p += buflen;
1036
1037
0
    if (f & LWSSS_FLAG_EOM) {
1038
0
#if defined(LWS_WITH_SERVER)
1039
0
        if (!(h->info.flags & LWSSSINFLAGS_ACCEPTED)) {
1040
0
#endif
1041
0
      conceal_eom = 1;
1042
      /* end of rideshares */
1043
0
      if (!h->rideshare->rideshare_streamtype) {
1044
0
        lws_client_http_body_pending(wsi, 0);
1045
0
#if defined(LWS_WITH_SS_RIDESHARE)
1046
0
        if (h->rideshare->u.http.multipart_name)
1047
0
          lws_client_http_multipart(wsi, NULL, NULL, NULL,
1048
0
            (char **)&p, (char *)end);
1049
0
        conceal_eom = 0;
1050
0
#endif
1051
0
      } else {
1052
0
        h->rideshare = lws_ss_policy_lookup(wsi->a.context,
1053
0
            h->rideshare->rideshare_streamtype);
1054
0
        lws_callback_on_writable(wsi);
1055
0
      }
1056
0
#if defined(LWS_WITH_SERVER)
1057
0
        }
1058
0
#endif
1059
1060
0
      h->inside_msg = 0;
1061
0
    } else {
1062
      /* otherwise we can spin with zero length writes */
1063
0
      if (!f && !lws_ptr_diff(p, buf + LWS_PRE))
1064
0
        break;
1065
0
      h->inside_msg = 1;
1066
0
      lws_callback_on_writable(wsi);
1067
0
    }
1068
1069
0
    lwsl_info("%s: lws_write %d %d\n", __func__,
1070
0
        lws_ptr_diff(p, buf + LWS_PRE), f);
1071
1072
0
    if (lws_write(wsi, buf + LWS_PRE, lws_ptr_diff_size_t(p, buf + LWS_PRE),
1073
0
       (!conceal_eom && (f & LWSSS_FLAG_EOM)) ?
1074
0
            LWS_WRITE_HTTP_FINAL : LWS_WRITE_HTTP) !=
1075
0
        (int)lws_ptr_diff(p, buf + LWS_PRE)) {
1076
0
      lwsl_err("%s: write failed\n", __func__);
1077
0
      return -1;
1078
0
    }
1079
1080
0
#if defined(LWS_WITH_SERVER)
1081
0
    if ((h->info.flags & LWSSSINFLAGS_ACCEPTED) /* server */ &&
1082
0
        (f & LWSSS_FLAG_EOM) &&
1083
0
         lws_http_transaction_completed(wsi))
1084
0
      return -1;
1085
#else
1086
    lws_set_timeout(wsi, 0, 0);
1087
#endif
1088
0
    break;
1089
1090
0
#if defined(LWS_WITH_SERVER)
1091
0
  case LWS_CALLBACK_HTTP:
1092
1093
0
    if (!h)
1094
0
      return -1;
1095
1096
0
    if (h->wsi && h->wsi->mount_hit)
1097
0
      break;
1098
1099
0
    lwsl_info("%s: LWS_CALLBACK_HTTP\n", __func__);
1100
0
    {
1101
1102
0
      h->txn_resp_set = 0;
1103
0
      h->txn_resp_pending = 1;
1104
0
      h->writeable_len = 0;
1105
1106
0
#if defined(LWS_ROLE_H2)
1107
0
      m = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_METHOD);
1108
0
      if (m) {
1109
0
        if (lws_ss_alloc_set_metadata(h, "method",
1110
0
                lws_hdr_simple_ptr(wsi,
1111
0
                 WSI_TOKEN_HTTP_COLON_METHOD), (unsigned int)m))
1112
0
          return -1;
1113
0
        m = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH);
1114
0
        if (m && lws_ss_alloc_set_metadata(h, "path",
1115
0
                lws_hdr_simple_ptr(wsi,
1116
0
                 WSI_TOKEN_HTTP_COLON_PATH), (unsigned int)m))
1117
0
          return -1;
1118
0
      } else
1119
0
#endif
1120
0
      {
1121
0
        m = lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI);
1122
0
        if (m) {
1123
0
          if (lws_ss_alloc_set_metadata(h, "path",
1124
0
              lws_hdr_simple_ptr(wsi,
1125
0
                WSI_TOKEN_GET_URI), (unsigned int)m))
1126
0
            return -1;
1127
0
          if (lws_ss_alloc_set_metadata(h, "method", "GET", 3))
1128
0
            return -1;
1129
0
          m = lws_hdr_fragment_length(wsi, WSI_TOKEN_HTTP_AUTHORIZATION, 0);
1130
0
          if (m && lws_ss_alloc_set_metadata(h, "auth",
1131
0
              lws_hdr_simple_ptr(wsi,
1132
0
                WSI_TOKEN_HTTP_AUTHORIZATION), (unsigned int)m))
1133
0
            return -1;
1134
0
        } else {
1135
0
          m = lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI);
1136
0
          if (m) {
1137
0
            if (lws_ss_alloc_set_metadata(h, "path",
1138
0
                lws_hdr_simple_ptr(wsi,
1139
0
                  WSI_TOKEN_POST_URI), (unsigned int)m))
1140
0
              return -1;
1141
0
            if (lws_ss_alloc_set_metadata(h, "method", "POST", 4))
1142
0
              return -1;
1143
0
            m = lws_hdr_fragment_length(wsi, WSI_TOKEN_HTTP_AUTHORIZATION, 0);
1144
0
            if (m && lws_ss_alloc_set_metadata(h, "auth",
1145
0
              lws_hdr_simple_ptr(wsi,
1146
0
                WSI_TOKEN_HTTP_AUTHORIZATION), (unsigned int)m))
1147
0
              return -1;
1148
0
          } else {
1149
0
#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_HTTP_HEADERS_ALL)
1150
0
            m = lws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI);
1151
0
            if (m) {
1152
0
              if (lws_ss_alloc_set_metadata(h, "path",
1153
0
                  lws_hdr_simple_ptr(wsi,
1154
0
                    WSI_TOKEN_PATCH_URI), (unsigned int)m))
1155
0
                return -1;
1156
0
              if (lws_ss_alloc_set_metadata(h, "method", "PATCH", 5))
1157
0
                return -1;
1158
0
              m = lws_hdr_fragment_length(wsi, WSI_TOKEN_HTTP_AUTHORIZATION, 0);
1159
0
              if (m && lws_ss_alloc_set_metadata(h, "auth",
1160
0
                lws_hdr_simple_ptr(wsi,
1161
0
                  WSI_TOKEN_HTTP_AUTHORIZATION), (unsigned int)m))
1162
0
                return -1;
1163
0
            }
1164
0
#endif
1165
0
          }
1166
0
        }
1167
0
      }
1168
0
    }
1169
1170
0
    if (!h->ss_dangling_connected) {
1171
#if defined(LWS_WITH_SYS_METRICS)
1172
      /*
1173
       * If any hanging caliper measurement, dump it, and free any tags
1174
       */
1175
      lws_metrics_caliper_report_hist(h->cal_txn, (struct lws *)NULL);
1176
#endif
1177
0
      wsi->client_suppress_CONNECTION_ERROR = 1;
1178
0
      if (h->prev_ss_state != LWSSSCS_CONNECTED) {
1179
0
        r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
1180
0
        if (r)
1181
0
          return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
1182
0
      }
1183
0
    }
1184
1185
    /*
1186
     * Check if any of the metadata defined in the policy correspond
1187
     * to urlargs that we can see... if so, adopt them as the
1188
     * metadata values
1189
     */
1190
0
    {
1191
0
      lws_ss_metadata_t *polmd;
1192
1193
0
      if (h->policy) {
1194
0
        polmd = h->policy->metadata;
1195
0
        while (polmd) {
1196
0
          char buf[1024];
1197
0
          int n = lws_get_urlarg_by_name_safe(wsi,
1198
0
              polmd->name, buf,
1199
0
              sizeof(buf));
1200
0
          if (n >= 0)
1201
0
            if (lws_ss_alloc_set_metadata(h,
1202
0
              polmd->name, buf,
1203
0
              (unsigned int)n))
1204
0
              return -1;
1205
1206
0
          polmd = polmd->next;
1207
0
        }
1208
0
      }
1209
0
    }
1210
1211
0
    r = lws_ss_event_helper(h, LWSSSCS_SERVER_TXN);
1212
0
    if (r)
1213
0
      return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r,
1214
0
                wsi, &h);
1215
1216
0
    return 0;
1217
0
#endif
1218
1219
0
  default:
1220
0
    break;
1221
0
  }
1222
1223
0
  return lws_callback_http_dummy(wsi, reason, user, in, len);
1224
0
}
1225
1226
const struct lws_protocols protocol_secstream_h1 = {
1227
  "lws-secstream-h1",
1228
  secstream_h1,
1229
  0, 0, 0, NULL, 0
1230
};
1231
1232
/*
1233
 * Munge connect info according to protocol-specific considerations... this
1234
 * usually means interpreting aux in a protocol-specific way and using the
1235
 * pieces at connection setup time, eg, http url pieces.
1236
 *
1237
 * len bytes of buf can be used for things with scope until after the actual
1238
 * connect.
1239
 */
1240
1241
static int
1242
secstream_connect_munge_h1(lws_ss_handle_t *h, char *buf, size_t len,
1243
         struct lws_client_connect_info *i,
1244
         union lws_ss_contemp *ct)
1245
0
{
1246
0
  const char *pbasis = h->policy->u.http.url;
1247
0
  size_t used_in, used_out;
1248
0
  lws_strexp_t exp;
1249
1250
  /* i.path on entry is used to override the policy urlpath if not "" */
1251
1252
0
  if (i->path[0])
1253
0
    pbasis = i->path;
1254
1255
0
  if (!pbasis)
1256
0
    return 0;
1257
1258
  /* uncomment to force h1 */
1259
  // i->alpn = "http/1.1";
1260
1261
0
#if defined(LWS_WITH_SS_RIDESHARE)
1262
0
  if (h->policy->flags & LWSSSPOLF_HTTP_MULTIPART)
1263
0
    i->ssl_connection |= LCCSCF_HTTP_MULTIPART_MIME;
1264
1265
0
  if (h->policy->flags & LWSSSPOLF_HTTP_X_WWW_FORM_URLENCODED)
1266
0
    i->ssl_connection |= LCCSCF_HTTP_X_WWW_FORM_URLENCODED;
1267
0
#endif
1268
1269
0
  if (h->policy->flags & LWSSSPOLF_HTTP_CACHE_COOKIES)
1270
0
    i->ssl_connection |= LCCSCF_CACHE_COOKIES;
1271
1272
  /* protocol aux is the path part */
1273
1274
0
  i->path = buf;
1275
1276
  /* skip the unnessary '/' */
1277
0
  if (*pbasis == '/')
1278
0
    pbasis = pbasis + 1;
1279
1280
0
  buf[0] = '/';
1281
1282
0
  lws_strexp_init(&exp, (void *)h, lws_ss_exp_cb_metadata, buf + 1, len - 1);
1283
1284
0
  if (lws_strexp_expand(&exp, pbasis, strlen(pbasis),
1285
0
            &used_in, &used_out) != LSTRX_DONE)
1286
0
    return 1;
1287
1288
0
  if (used_out + 1 < len - 1)
1289
0
    buf[used_out + 1] = '\0';
1290
1291
0
  __lws_lc_tag_append(&h->lc, buf);
1292
1293
0
  return 0;
1294
0
}
1295
1296
1297
const struct ss_pcols ss_pcol_h1 = {
1298
  "h1",
1299
  "http/1.1",
1300
  &protocol_secstream_h1,
1301
  secstream_connect_munge_h1,
1302
  NULL, NULL
1303
};