Coverage Report

Created: 2025-09-05 06:26

/src/libwebsockets/lib/roles/http/cookie.c
Line
Count
Source (jump to first uncovered line)
1
2
#include <libwebsockets.h>
3
#include "private-lib-core.h"
4
5
//#define LWS_COOKIE_DEBUG
6
7
#if defined(LWS_COOKIE_DEBUG)
8
  #define lwsl_cookie lwsl_notice
9
#else
10
0
  #define lwsl_cookie lwsl_debug
11
#endif
12
13
#define LWS_COOKIE_MAX_CACHE_NAME_LEN 128
14
15
0
#define lws_tolower(_c) (((_c) >= 'A' && (_c) <= 'Z') ? \
16
0
              (char)((_c) + 'a' - 'A') : \
17
0
              (char)(_c))
18
19
0
#define LWS_COOKIE_NSC_FORMAT     "%.*s\t"\
20
0
            "%s\t"\
21
0
            "%.*s\t"\
22
0
            "%s\t"\
23
0
            "%llu\t"\
24
0
            "%.*s\t"\
25
0
            "%.*s"
26
27
static const char *const mon = "janfebmaraprnayjunjulaugsepoctnovdec";
28
29
enum lws_cookie_nsc_f {
30
  LWSC_NSC_DOMAIN,
31
  LWSC_NSC_HOSTONLY,
32
  LWSC_NSC_PATH,
33
  LWSC_NSC_SECURE,
34
  LWSC_NSC_EXPIRES,
35
  LWSC_NSC_NAME,
36
  LWSC_NSC_VALUE,
37
38
  LWSC_NSC_COUNT,
39
};
40
41
enum lws_cookie_elements {
42
  CE_DOMAIN,
43
  CE_PATH,
44
  CE_EXPIRES,
45
  CE_MAXAGE,
46
  CE_NAME,
47
  CE_VALUE,
48
49
  CE_HOSTONLY, /* these are bool, NULL = 0, non-NULL = 1 */
50
  CE_SECURE,
51
52
  CE_COUNT
53
};
54
55
struct lws_cookie {
56
  const char  *f[CE_COUNT];
57
  size_t    l[CE_COUNT];
58
59
  unsigned int httponly:1;
60
};
61
62
static int
63
lws_cookie_parse_date(const char *d, size_t len, time_t *t)
64
0
{
65
0
  struct tm date;
66
0
  int offset = 0, i;
67
68
0
  memset(&date, 0, sizeof(date));
69
70
0
  while (len) {
71
0
    if (isalnum((int)*d)) {
72
0
      offset++;
73
0
      goto next;
74
0
    }
75
0
    switch (offset) {
76
0
    case 2:
77
0
      if (*d == ':' && len >= 6) {
78
0
        date.tm_hour = atoi(d - 2);
79
0
        if (date.tm_hour < 0 || date.tm_hour > 23)
80
0
          return -1;
81
0
        date.tm_min = atoi(d + 1);
82
0
        if (date.tm_min < 0 || date.tm_min > 60)
83
0
          return -1;
84
0
        date.tm_sec = atoi(d + 4);
85
0
        if (date.tm_sec < 0 || date.tm_sec > 61)
86
          /* leap second */
87
0
          return -1;
88
89
0
        d += 6;
90
0
        len -= 6;
91
0
        offset = 0;
92
0
        continue;
93
0
      }
94
95
0
      if (!date.tm_mday) {
96
0
        date.tm_mday = atoi(d - 2);
97
0
        if (date.tm_mday < 1 || date.tm_mday > 31)
98
0
          return -1;
99
0
        goto next2;
100
0
      }
101
102
0
      if (!date.tm_year) {
103
0
        date.tm_year = atoi(d - 2);
104
0
        if (date.tm_year < 0 || date.tm_year > 99)
105
0
          return -1;
106
0
        if (date.tm_year < 70)
107
0
          date.tm_year += 100;
108
0
      }
109
0
      goto next2;
110
111
0
    case 3:
112
0
      for (i = 0; i < 36; i += 3) {
113
0
        if (lws_tolower(*(d - 3)) == mon[i] &&
114
0
            lws_tolower(*(d - 2)) == mon[i + 1] &&
115
0
            lws_tolower(*(d - 1)) == mon[i + 2]) {
116
0
          date.tm_mon = i / 3;
117
0
          break;
118
0
        }
119
0
      }
120
0
      goto next2;
121
122
0
    case 4:
123
0
      if (!date.tm_year) {
124
0
        date.tm_year = atoi(d - 4);
125
0
        if (date.tm_year < 1601)
126
0
          return -1;
127
0
        date.tm_year -= 1900;
128
0
      }
129
0
      goto next2;
130
131
0
    default:
132
0
      goto next2;
133
0
    }
134
135
0
next2:
136
0
    offset = 0;
137
0
next:
138
0
    d++;
139
0
    len--;
140
0
  }
141
142
0
  *t = mktime(&date);
143
144
0
  if (*t < 0)
145
0
    return -1;
146
147
0
  return 0;
148
0
}
149
150
static void
151
lws_cookie_rm_sws(const char **buf_p, size_t *len_p)
152
0
{
153
0
  const char *buf;
154
0
  size_t len;
155
156
0
  if (!buf_p || !*buf_p || !len_p || !*len_p) {
157
0
    lwsl_err("%s: false parameter\n", __func__);
158
0
    return;
159
0
  }
160
161
0
  buf = *buf_p;
162
0
  len = *len_p;
163
164
0
  while (buf[0] == ' ' && len > 0) {
165
0
    buf++;
166
0
    len--;
167
0
  }
168
169
0
  while (len && buf[len - 1] == ' ')
170
0
    len--;
171
172
0
  *buf_p = buf;
173
0
  *len_p = len;
174
0
}
175
176
static int
177
is_iprefix(const char *h, size_t hl, const char *n, size_t nl)
178
0
{
179
0
  if (!h || !n || nl > hl)
180
0
    return 0;
181
182
0
  while (nl) {
183
0
    nl--;
184
0
    if (lws_tolower(h[nl]) != lws_tolower(n[nl]))
185
0
      return 0;
186
0
  }
187
0
  return 1;
188
0
}
189
190
static int
191
lws_cookie_compile_cache_name(char *buf, size_t buf_len, struct lws_cookie *c)
192
0
{
193
0
  if (!buf || !c->f[CE_DOMAIN] || !c->f[CE_PATH] || !c->f[CE_NAME] ||
194
0
      c->l[CE_DOMAIN] + c->l[CE_PATH] + c->l[CE_NAME] + 6 > buf_len)
195
0
    return -1;
196
197
0
  memcpy(buf, c->f[CE_DOMAIN], c->l[CE_DOMAIN]);
198
0
  buf += c->l[CE_DOMAIN];
199
0
  *buf++ = '|';
200
201
0
  memcpy(buf, c->f[CE_PATH], c->l[CE_PATH]);
202
0
  buf += c->l[CE_PATH];
203
0
  *buf++ = '|';
204
205
0
  memcpy(buf, c->f[CE_NAME], c->l[CE_NAME]);
206
0
  buf += c->l[CE_NAME];
207
0
  *buf = '\0';
208
209
0
  return 0;
210
0
}
211
212
static int
213
lws_cookie_parse_nsc(struct lws_cookie *c, const char *b, size_t l)
214
0
{
215
0
  enum lws_cookie_nsc_f state = LWSC_NSC_DOMAIN;
216
0
  size_t n = 0;
217
218
0
  if (!c || !b || l < 13)
219
0
    return -1;
220
221
0
  memset(c, 0, sizeof(*c));
222
0
  lwsl_cookie("%s: parsing (%.*s) \n", __func__, (int)l, b);
223
224
0
  while (l) {
225
0
    l--;
226
0
    if (b[n] != '\t' && l) {
227
0
      n++;
228
0
      continue;
229
0
    }
230
0
    switch (state) {
231
0
    case LWSC_NSC_DOMAIN:
232
0
      c->f[CE_DOMAIN] = b;
233
0
      c->l[CE_DOMAIN] = n;
234
0
      break;
235
0
    case LWSC_NSC_PATH:
236
0
      c->f[CE_PATH] = b;
237
0
      c->l[CE_PATH] = n;
238
0
      break;
239
0
    case LWSC_NSC_EXPIRES:
240
0
      c->f[CE_EXPIRES] = b;
241
0
      c->l[CE_EXPIRES] = n;
242
0
      break;
243
0
    case LWSC_NSC_NAME:
244
0
      c->f[CE_NAME] = b;
245
0
      c->l[CE_NAME] = n;
246
0
      break;
247
248
0
    case LWSC_NSC_HOSTONLY:
249
0
      if (b[0] == 'T') {
250
0
        c->f[CE_HOSTONLY] = b;
251
0
        c->l[CE_HOSTONLY] = 1;
252
0
      }
253
0
      break;
254
0
    case LWSC_NSC_SECURE:
255
0
      if (b[0] == 'T') {
256
0
        c->f[CE_SECURE] = b;
257
0
        c->l[CE_SECURE] = 1;
258
0
      }
259
0
      break;
260
261
0
    case LWSC_NSC_VALUE:
262
0
      c->f[CE_VALUE] = b;
263
0
      c->l[CE_VALUE] = n + 1;
264
265
0
      for (n = 0; n < LWS_ARRAY_SIZE(c->f); n++)
266
0
        lwsl_cookie("%s: %d: %.*s\n", __func__,
267
0
            (int)n, (int)c->l[n], c->f[n]);
268
269
0
      return 0;
270
0
    default:
271
0
      return -1;
272
0
    }
273
274
0
    b += n + 1;
275
0
    n = 0;
276
0
    state++;
277
0
  }
278
279
0
  return -1;
280
0
}
281
282
static int
283
lws_cookie_write_nsc(struct lws *wsi, struct lws_cookie *c)
284
0
{
285
0
  char cache_name[LWS_COOKIE_MAX_CACHE_NAME_LEN];
286
0
  const char *ads, *path;
287
0
  struct lws_cache_ttl_lru *l1;
288
0
  struct client_info_stash *stash;
289
0
  char *cookie_string = NULL, *dl;
290
   /* 6 tabs + 20 for max time_t + 2 * TRUE/FALSE + null */
291
0
  size_t size = 6 + 20 + 10 + 1;
292
0
  time_t expires = 0;
293
0
  int ret = 0;
294
295
0
  if (!wsi || !c)
296
0
    return -1;
297
298
0
  l1 = wsi->a.context->l1;
299
0
  if (!l1 || !wsi->a.context->nsc)
300
0
    return -1;
301
302
0
  stash = wsi->stash ? wsi->stash : lws_get_network_wsi(wsi)->stash;
303
0
  if (stash) {
304
0
    ads = stash->cis[CIS_ADDRESS];
305
0
    path = stash->cis[CIS_PATH];
306
0
  } else {
307
0
    ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
308
0
    path = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI);
309
0
  }
310
0
  if (!ads || !path)
311
0
    return -1;
312
313
0
  if (!c->f[CE_NAME] || !c->f[CE_VALUE]) {
314
0
    lwsl_err("%s: malformed c\n", __func__);
315
316
0
    return -1;
317
0
  }
318
319
0
  if (!c->f[CE_EXPIRES]) {
320
    /*
321
     * Currently we just take the approach to reject session cookies
322
     */
323
0
    lwsl_warn("%s: reject session cookies\n", __func__);
324
325
0
    return 0;
326
0
  }
327
328
0
  if (!c->f[CE_DOMAIN]) {
329
0
    c->f[CE_HOSTONLY] = "T";
330
0
    c->l[CE_HOSTONLY] = 1;
331
0
    c->f[CE_DOMAIN] = ads;
332
0
    c->l[CE_DOMAIN] = strlen(ads);
333
0
  }
334
335
0
  if (!c->f[CE_PATH]) {
336
0
    c->f[CE_PATH] = path;
337
0
    c->l[CE_PATH] = strlen(path);
338
0
    dl = memchr(c->f[CE_PATH], '?', c->l[CE_PATH]);
339
0
    if (dl)
340
0
      c->l[CE_PATH] = (size_t)(dl - c->f[CE_PATH]);
341
0
  }
342
343
0
  if (lws_cookie_compile_cache_name(cache_name, sizeof(cache_name), c))
344
0
    return -1;
345
346
0
  if (c->f[CE_EXPIRES] &&
347
0
      lws_cookie_parse_date(c->f[CE_EXPIRES], c->l[CE_EXPIRES], &expires)) {
348
0
    lwsl_err("%s: can't parse date %.*s\n", __func__,
349
0
       (int)c->l[CE_EXPIRES], c->f[CE_EXPIRES]);
350
0
    return -1;
351
0
  }
352
353
0
  size += c->l[CE_NAME] + c->l[CE_VALUE] + c->l[CE_DOMAIN] + c->l[CE_PATH];
354
0
  cookie_string = (char *)lws_malloc(size, __func__);
355
0
  if (!cookie_string) {
356
0
    lwsl_err("%s: OOM\n",__func__);
357
358
0
    return -1;  
359
0
  }
360
361
0
  lws_snprintf(cookie_string, size, LWS_COOKIE_NSC_FORMAT,
362
0
      (int)c->l[CE_DOMAIN], c->f[CE_DOMAIN],
363
0
      c->f[CE_HOSTONLY] ? "TRUE" : "FALSE",
364
0
      (int)c->l[CE_PATH], c->f[CE_PATH],
365
0
      c->f[CE_SECURE] ? "TRUE" : "FALSE",
366
0
      (unsigned long long)expires,
367
0
      (int)c->l[CE_NAME], c->f[CE_NAME],
368
0
      (int)c->l[CE_VALUE], c->f[CE_VALUE]);
369
370
0
  lwsl_cookie("%s: name %s\n", __func__, cache_name);
371
0
  lwsl_cookie("%s: c %s\n", __func__, cookie_string);
372
373
0
  if (lws_cache_write_through(l1, cache_name,
374
0
            (const uint8_t *)cookie_string,
375
0
            strlen(cookie_string),
376
0
            (lws_usec_t)((unsigned long long)expires *
377
0
             (lws_usec_t)LWS_US_PER_SEC), NULL)) {
378
0
    ret = -1;
379
0
    goto exit;
380
0
  }
381
382
#if defined(LWS_COOKIE_DEBUG)
383
  char *po;
384
  if (lws_cache_item_get(l1, cache_name, (const void **)&po, &size) ||
385
      size != strlen(cookie_string) || memcmp(po, cookie_string, size)) {
386
    lwsl_err("%s: L1 '%s' missing\n", __func__, cache_name);
387
  }
388
389
  if (lws_cache_item_get(wsi->a.context->nsc, cache_name,
390
             (const void **)&po, &size) ||
391
             size != strlen(cookie_string) ||
392
             memcmp(po, cookie_string, size)) {
393
    lwsl_err("%s: NSC '%s' missing, size %llu, po %s\n", __func__,
394
       cache_name, (unsigned long long)size, po);
395
  }
396
#endif
397
398
0
exit:
399
0
  lws_free(cookie_string);
400
401
0
  return ret;
402
0
}
403
404
static int
405
lws_cookie_attach_cookies(struct lws *wsi, char *buf, char *end)
406
0
{
407
0
  const char *domain, *path, *dl_domain, *dl_path, *po;
408
0
  char cache_name[LWS_COOKIE_MAX_CACHE_NAME_LEN];
409
0
  size_t domain_len, path_len, size, ret = 0;
410
0
  struct lws_cache_ttl_lru *l1;
411
0
  struct client_info_stash *stash;
412
0
  lws_cache_results_t cr;
413
0
  struct lws_cookie c;
414
0
  int hostdomain = 1;
415
0
  char *p, *p1;
416
417
0
  if (!wsi)
418
0
    return -1;
419
420
0
  stash = wsi->stash ? wsi->stash : lws_get_network_wsi(wsi)->stash;
421
0
  if (!stash || !stash->cis[CIS_ADDRESS] ||
422
0
         !stash->cis[CIS_PATH])
423
0
    return -1;
424
425
0
  l1 = wsi->a.context->l1;
426
0
  if (!l1 || !wsi->a.context->nsc){
427
0
    lwsl_err("%s:no cookiejar\n", __func__);
428
0
    return -1;
429
0
  }
430
431
0
  memset(&c, 0, sizeof(c));
432
433
0
  domain = stash->cis[CIS_ADDRESS];
434
0
  path = stash->cis[CIS_PATH];
435
436
0
  if (!domain || !path)
437
0
    return -1;
438
439
0
  path_len = strlen(path);
440
441
  /* remove query string if exist */
442
0
  dl_path = memchr(path, '?', path_len);
443
0
  if (dl_path)
444
0
    path_len = lws_ptr_diff_size_t(dl_path,  path);
445
446
  /* remove last slash if exist */
447
0
  if (path_len != 1 && path[path_len - 1] == '/')
448
0
    path_len--;
449
450
0
  if (!path_len)
451
0
    return -1;
452
453
0
  lwsl_cookie("%s: path %.*s len %d\n", __func__, (int)path_len, path, (int)path_len);
454
455
  /* when dest buf is not provided, we only return size of cookie string */
456
0
  if (!buf || !end)
457
0
    p = NULL;
458
0
  else
459
0
    p = buf;
460
461
  /* iterate through domain and path levels to find matching cookies */
462
0
  dl_domain = domain;
463
0
  while (dl_domain) {
464
0
    domain_len = strlen(domain);
465
0
    dl_domain = memchr(domain, '.', domain_len);
466
    /* don't match top level domain */
467
0
    if (!dl_domain)
468
0
      break;
469
470
0
    if (domain_len + path_len + 6 > sizeof(cache_name))
471
0
      return -1;
472
473
    /* compile key string "[domain]|[path]|*"" */
474
0
    p1 = cache_name;
475
0
    memcpy(p1, domain, domain_len);
476
0
    p1 += domain_len;
477
0
    *p1 = '|';
478
0
    p1++;
479
0
    memcpy(p1, path, path_len);
480
0
    p1 += path_len;
481
0
    *p1 = '|';
482
0
    p1++;
483
0
    *p1 = '*';
484
0
    p1++;
485
0
    *p1 = '\0';
486
487
0
    lwsl_cookie("%s: looking for %s\n", __func__, cache_name);
488
489
0
    if (!lws_cache_lookup(l1, cache_name,
490
0
              (const void **)&cr.ptr, &cr.size)) {
491
492
0
      while (!lws_cache_results_walk(&cr)) {
493
0
        lwsl_cookie(" %s (%d)\n", (const char *)cr.tag,
494
0
            (int)cr.payload_len);
495
496
0
        if (lws_cache_item_get(l1, (const char *)cr.tag,
497
0
               (const void **)&po, &size) ||
498
0
          lws_cookie_parse_nsc(&c, po, size)) {
499
0
          lwsl_err("%s: failed to get c '%s'\n",
500
0
              __func__, cr.tag);
501
0
          break;
502
0
        }
503
504
0
        if (c.f[CE_HOSTONLY] && !hostdomain){
505
0
          lwsl_cookie("%s: not sending this\n",
506
0
              __func__);
507
0
          continue;
508
0
        }
509
510
0
        if (p) {
511
0
          if (ret) {
512
0
            *p = ';';
513
0
            p++;
514
0
            *p = ' ';
515
0
            p++;
516
0
          }
517
518
0
          memcpy(p, c.f[CE_NAME], c.l[CE_NAME]);
519
0
          p += c.l[CE_NAME];
520
0
          *p = '=';
521
0
          p++;
522
0
          memcpy(p, c.f[CE_VALUE], c.l[CE_VALUE]);
523
0
          p += c.l[CE_VALUE];
524
0
        }
525
526
0
        if (ret)
527
0
          ret += 2;
528
0
        ret += c.l[CE_NAME] + 1 + c.l[CE_VALUE];
529
530
0
      }
531
0
    }
532
533
0
    domain = dl_domain + 1;
534
0
    hostdomain = 0;
535
0
  }
536
537
0
  lwsl_notice("%s: c len (%d)\n", __func__, (int)ret);
538
539
0
  return (int)ret;
540
0
}
541
542
static struct {
543
  const char    *const name;
544
  uint8_t     len;
545
} cft[] = {
546
  { "domain=",  7 },
547
  { "path=",    5 },
548
  { "expires=", 8 },
549
  { "max-age=", 8 },
550
  { "httponly", 8 },
551
  { "secure",   6 }
552
};
553
554
int
555
lws_parse_set_cookie(struct lws *wsi)
556
0
{
557
0
  char *tk_head, *tk_end, *buf_head, *buf_end, *cookiep, *dl;
558
0
  struct lws_cache_ttl_lru *l1;
559
0
  struct lws_cookie c;
560
0
  size_t fl;
561
0
  int f, n;
562
563
0
  if (!wsi)
564
0
    return -1;
565
566
0
  l1 = wsi->a.context->l1;
567
0
  if (!l1)
568
0
    return -1;
569
570
0
  f = wsi->http.ah->frag_index[WSI_TOKEN_HTTP_SET_COOKIE];
571
572
0
  while (f) {
573
0
    cookiep = wsi->http.ah->data + wsi->http.ah->frags[f].offset;
574
0
    fl = wsi->http.ah->frags[f].len;
575
0
    f = wsi->http.ah->frags[f].nfrag;
576
577
0
    if (!cookiep || !fl)
578
0
      continue;
579
580
#if defined(LWS_COOKIE_DEBUG)
581
    lwsl_notice("%s:parsing: %.*s\n", __func__, (int)fl, cookiep);
582
#endif
583
584
0
    buf_head = cookiep;
585
0
    buf_end = cookiep + fl - 1;
586
0
    memset(&c, 0, sizeof(struct lws_cookie));
587
588
0
    do {
589
0
      tk_head = buf_head;
590
0
      tk_end = memchr(buf_head, ';',
591
0
          (size_t)(buf_end - buf_head + 1));
592
0
      if (!tk_end) {
593
0
        tk_end = buf_end;
594
0
        buf_head = buf_end;
595
0
      } else {
596
0
        buf_head = tk_end + 1;
597
0
        tk_end--;
598
0
      }
599
600
0
      if (c.f[CE_NAME])
601
0
        goto parse_av;
602
603
      /*
604
       * find name value, remove leading trailing
605
       * WS and DQ for value
606
       */
607
608
0
      dl = memchr(tk_head, '=', lws_ptr_diff_size_t(tk_end,
609
0
              tk_head + 1));
610
0
      if (!dl || dl == tk_head)
611
0
        return -1;
612
613
0
      c.f[CE_NAME] = tk_head;
614
0
      c.l[CE_NAME] = lws_ptr_diff_size_t(dl, tk_head);
615
0
      lws_cookie_rm_sws(&c.f[CE_NAME], &c.l[CE_NAME]);
616
617
0
      if (!c.l[CE_NAME])
618
0
        return -1;
619
620
0
      lwsl_cookie("%s: c name l %d v:%.*s\n", __func__,
621
0
          (int)c.l[CE_NAME],
622
0
          (int)c.l[CE_NAME], c.f[CE_NAME]);
623
0
      c.f[CE_VALUE] = dl + 1;
624
0
      c.l[CE_VALUE] = lws_ptr_diff_size_t(tk_end,
625
0
               c.f[CE_VALUE]) + 1;
626
627
0
      lws_cookie_rm_sws(&c.f[CE_VALUE], &c.l[CE_VALUE]);
628
0
      if (c.l[CE_VALUE] >= 2 && c.f[CE_VALUE][0] == '\"') {
629
0
        c.f[CE_VALUE]++;
630
0
        c.l[CE_VALUE] -= 2;
631
0
      }
632
0
      lwsl_cookie("%s: c value l %d v:%.*s\n", __func__,
633
0
            (int)c.l[CE_VALUE], (int)c.l[CE_VALUE],
634
0
            c.f[CE_VALUE]);
635
0
      continue;
636
637
0
parse_av:
638
0
      while (*tk_head == ' ') {
639
0
        if (tk_head == tk_end)
640
0
          return -1;
641
642
0
        tk_head++;
643
0
      }
644
645
0
      for (n = 0; n < (int)LWS_ARRAY_SIZE(cft); n++) {
646
0
        if (lws_tolower(*tk_head) != cft[n].name[0])
647
0
          continue;
648
649
0
        if (!is_iprefix(tk_head,
650
0
            lws_ptr_diff_size_t(tk_end,
651
0
                   tk_head) + 1,
652
0
            cft[n].name, cft[n].len))
653
0
          continue;
654
655
0
        if (n == 4 || n == 5) {
656
0
          c.f[n] = "T";
657
0
          c.l[n] = 1;
658
0
          break;
659
0
        }
660
661
0
        c.f[n] = tk_head + cft[n].len;
662
0
        c.l[n] = lws_ptr_diff_size_t(tk_end, c.f[n]) + 1;
663
0
        lws_cookie_rm_sws(&c.f[n], &c.l[n]);
664
665
0
        if (n == CE_DOMAIN && c.l[0] &&
666
0
            c.f[n][0] == '.'){
667
0
          c.f[n]++;
668
0
          c.l[n]--;
669
0
        }
670
671
0
        lwsl_cookie("%s: %s l %d v:%.*s\n", __func__,
672
0
              cft[n].name, (int)c.l[n],
673
0
              (int)c.l[n], c.f[n]);
674
0
        break;
675
0
      }
676
677
0
    } while (tk_end != buf_end);
678
679
0
    if (lws_cookie_write_nsc(wsi, &c))
680
0
      lwsl_err("%s:failed to write nsc\n", __func__);
681
0
  }
682
683
0
  return 0;
684
0
}
685
686
int
687
lws_cookie_send_cookies(struct lws *wsi, char **pp, char *end)
688
0
{
689
0
  char *p;
690
0
  int size;
691
692
0
  if (!wsi || !pp || !(*pp) || !end)
693
0
    return -1;
694
695
0
  size = lws_cookie_attach_cookies(wsi, NULL, NULL);
696
697
0
  if (!size)
698
0
    return 0;
699
0
  if (size < 0) {
700
0
    lwsl_err("%s:failed to get cookie string size\n", __func__);
701
0
    return -1;
702
0
  }
703
704
0
  lwsl_notice("%s: size %d\n", __func__, size);
705
706
#if defined(LWS_COOKIE_DEBUG)
707
    char *p_dbg = *pp;
708
#endif
709
710
0
  if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_COOKIE, NULL, size,
711
0
                (unsigned char **)pp, (unsigned char *)end))
712
0
    return -1;
713
714
#if defined(LWS_COOKIE_DEBUG)
715
    lwsl_notice("%s: dummy copy (%.*s) \n", __func__, (int)(*pp - p_dbg), p_dbg);
716
#endif
717
718
719
0
#ifdef LWS_WITH_HTTP2
720
0
  if (lws_wsi_is_h2(wsi))
721
0
    p = *pp - size;
722
0
  else
723
0
#endif
724
0
    p = *pp - size - 2;
725
726
0
  if (lws_cookie_attach_cookies(wsi, p, p + size) <= 0) {
727
0
    lwsl_err("%s:failed to attach cookies\n", __func__);
728
0
    return -1;
729
0
  }
730
731
#if defined(LWS_COOKIE_DEBUG)
732
    lwsl_notice("%s: real copy (%.*s) total len %d\n", __func__, (int)(*pp - p_dbg), p_dbg, (int)(*pp - p_dbg));
733
    lwsl_hexdump_notice(p_dbg, (size_t)(*pp - p_dbg));
734
#endif
735
736
0
  return 0;
737
0
}