Coverage Report

Created: 2025-08-03 06:52

/src/libwebsockets/lib/roles/h2/hpack.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
/*
28
 * Official static header table for HPACK
29
 *        +-------+-----------------------------+---------------+
30
          | 1     | :authority                  |               |
31
          | 2     | :method                     | GET           |
32
          | 3     | :method                     | POST          |
33
          | 4     | :path                       | /             |
34
          | 5     | :path                       | /index.html   |
35
          | 6     | :scheme                     | http          |
36
          | 7     | :scheme                     | https         |
37
          | 8     | :status                     | 200           |
38
          | 9     | :status                     | 204           |
39
          | 10    | :status                     | 206           |
40
          | 11    | :status                     | 304           |
41
          | 12    | :status                     | 400           |
42
          | 13    | :status                     | 404           |
43
          | 14    | :status                     | 500           |
44
          | 15    | accept-charset              |               |
45
          | 16    | accept-encoding             | gzip, deflate |
46
          | 17    | accept-language             |               |
47
          | 18    | accept-ranges               |               |
48
          | 19    | accept                      |               |
49
          | 20    | access-control-allow-origin |               |
50
          | 21    | age                         |               |
51
          | 22    | allow                       |               |
52
          | 23    | authorization               |               |
53
          | 24    | cache-control               |               |
54
          | 25    | content-disposition         |               |
55
          | 26    | content-encoding            |               |
56
          | 27    | content-language            |               |
57
          | 28    | content-length              |               |
58
          | 29    | content-location            |               |
59
          | 30    | content-range               |               |
60
          | 31    | content-type                |               |
61
          | 32    | cookie                      |               |
62
          | 33    | date                        |               |
63
          | 34    | etag                        |               |
64
          | 35    | expect                      |               |
65
          | 36    | expires                     |               |
66
          | 37    | from                        |               |
67
          | 38    | host                        |               |
68
          | 39    | if-match                    |               |
69
          | 40    | if-modified-since           |               |
70
          | 41    | if-none-match               |               |
71
          | 42    | if-range                    |               |
72
          | 43    | if-unmodified-since         |               |
73
          | 44    | last-modified               |               |
74
          | 45    | link                        |               |
75
          | 46    | location                    |               |
76
          | 47    | max-forwards                |               |
77
          | 48    | proxy-authenticate          |               |
78
          | 49    | proxy-authorization         |               |
79
          | 50    | range                       |               |
80
          | 51    | referer                     |               |
81
          | 52    | refresh                     |               |
82
          | 53    | retry-after                 |               |
83
          | 54    | server                      |               |
84
          | 55    | set-cookie                  |               |
85
          | 56    | strict-transport-security   |               |
86
          | 57    | transfer-encoding           |               |
87
          | 58    | user-agent                  |               |
88
          | 59    | vary                        |               |
89
          | 60    | via                         |               |
90
          | 61    | www-authenticate            |               |
91
          +-------+-----------------------------+---------------+
92
*/
93
94
static const uint8_t static_hdr_len[62] = {
95
    0, /* starts at 1 */
96
    10,  7,  7,  5,  5,    7,  7,  7,  7,  7,
97
     7,  7,  7,  7, 14,   15, 15, 13,  6, 27,
98
     3,  5, 13, 13, 19,   16, 16, 14, 16, 13,
99
    12,  6,  4,  4,  6,    7,  4,  4,  8, 17,
100
    13,  8, 19, 13,  4,    8, 12, 18, 19,  5,
101
     7,  7, 11,  6, 10,   25, 17, 10,  4,  3,
102
    16
103
};
104
105
static const unsigned char static_token[] = {
106
  0,
107
  WSI_TOKEN_HTTP_COLON_AUTHORITY,
108
  WSI_TOKEN_HTTP_COLON_METHOD,
109
  WSI_TOKEN_HTTP_COLON_METHOD,
110
  WSI_TOKEN_HTTP_COLON_PATH,
111
  WSI_TOKEN_HTTP_COLON_PATH,
112
  WSI_TOKEN_HTTP_COLON_SCHEME,
113
  WSI_TOKEN_HTTP_COLON_SCHEME,
114
  WSI_TOKEN_HTTP_COLON_STATUS,
115
  WSI_TOKEN_HTTP_COLON_STATUS,
116
  WSI_TOKEN_HTTP_COLON_STATUS,
117
  WSI_TOKEN_HTTP_COLON_STATUS,
118
  WSI_TOKEN_HTTP_COLON_STATUS,
119
  WSI_TOKEN_HTTP_COLON_STATUS,
120
  WSI_TOKEN_HTTP_COLON_STATUS,
121
  WSI_TOKEN_HTTP_ACCEPT_CHARSET,
122
  WSI_TOKEN_HTTP_ACCEPT_ENCODING,
123
  WSI_TOKEN_HTTP_ACCEPT_LANGUAGE,
124
  WSI_TOKEN_HTTP_ACCEPT_RANGES,
125
  WSI_TOKEN_HTTP_ACCEPT,
126
  WSI_TOKEN_HTTP_ACCESS_CONTROL_ALLOW_ORIGIN,
127
  WSI_TOKEN_HTTP_AGE,
128
  WSI_TOKEN_HTTP_ALLOW,
129
  WSI_TOKEN_HTTP_AUTHORIZATION,
130
  WSI_TOKEN_HTTP_CACHE_CONTROL,
131
  WSI_TOKEN_HTTP_CONTENT_DISPOSITION,
132
  WSI_TOKEN_HTTP_CONTENT_ENCODING,
133
  WSI_TOKEN_HTTP_CONTENT_LANGUAGE,
134
  WSI_TOKEN_HTTP_CONTENT_LENGTH,
135
  WSI_TOKEN_HTTP_CONTENT_LOCATION,
136
  WSI_TOKEN_HTTP_CONTENT_RANGE,
137
  WSI_TOKEN_HTTP_CONTENT_TYPE,
138
  WSI_TOKEN_HTTP_COOKIE,
139
  WSI_TOKEN_HTTP_DATE,
140
  WSI_TOKEN_HTTP_ETAG,
141
  WSI_TOKEN_HTTP_EXPECT,
142
  WSI_TOKEN_HTTP_EXPIRES,
143
  WSI_TOKEN_HTTP_FROM,
144
  WSI_TOKEN_HOST,
145
  WSI_TOKEN_HTTP_IF_MATCH,
146
  WSI_TOKEN_HTTP_IF_MODIFIED_SINCE,
147
  WSI_TOKEN_HTTP_IF_NONE_MATCH,
148
  WSI_TOKEN_HTTP_IF_RANGE,
149
  WSI_TOKEN_HTTP_IF_UNMODIFIED_SINCE,
150
  WSI_TOKEN_HTTP_LAST_MODIFIED,
151
  WSI_TOKEN_HTTP_LINK,
152
  WSI_TOKEN_HTTP_LOCATION,
153
  WSI_TOKEN_HTTP_MAX_FORWARDS,
154
  WSI_TOKEN_HTTP_PROXY_AUTHENTICATE,
155
  WSI_TOKEN_HTTP_PROXY_AUTHORIZATION,
156
  WSI_TOKEN_HTTP_RANGE,
157
  WSI_TOKEN_HTTP_REFERER,
158
  WSI_TOKEN_HTTP_REFRESH,
159
  WSI_TOKEN_HTTP_RETRY_AFTER,
160
  WSI_TOKEN_HTTP_SERVER,
161
  WSI_TOKEN_HTTP_SET_COOKIE,
162
  WSI_TOKEN_HTTP_STRICT_TRANSPORT_SECURITY,
163
  WSI_TOKEN_HTTP_TRANSFER_ENCODING,
164
  WSI_TOKEN_HTTP_USER_AGENT,
165
  WSI_TOKEN_HTTP_VARY,
166
  WSI_TOKEN_HTTP_VIA,
167
  WSI_TOKEN_HTTP_WWW_AUTHENTICATE,
168
};
169
170
/* some of the entries imply values as well as header names */
171
172
static const char * const http2_canned[] = {
173
  "",
174
  "",
175
  "GET",
176
  "POST",
177
  "/",
178
  "/index.html",
179
  "http",
180
  "https",
181
  "200",
182
  "204",
183
  "206",
184
  "304",
185
  "400",
186
  "404",
187
  "500",
188
  "",
189
  "gzip, deflate"
190
};
191
192
/* see minihuf.c */
193
194
#include "huftable.h"
195
196
static int huftable_decode(int pos, char c)
197
0
{
198
0
  int q = pos + !!c;
199
200
0
  if (lextable_terms[q >> 3] & (1 << (q & 7))) /* terminal */
201
0
    return lextable[q] | 0x8000;
202
203
0
  return pos + (lextable[q] << 1);
204
0
}
205
206
static int lws_frag_start(struct lws *wsi, int hdr_token_idx)
207
0
{
208
0
  struct allocated_headers *ah = wsi->http.ah;
209
210
0
  if (!ah) {
211
0
    lwsl_notice("%s: no ah\n", __func__);
212
0
    return 1;
213
0
  }
214
215
0
  ah->hdr_token_idx = -1;
216
217
0
  lwsl_header("%s: token %d ah->pos = %d, ah->nfrag = %d\n",
218
0
       __func__, hdr_token_idx, ah->pos, ah->nfrag);
219
220
0
  if (!hdr_token_idx) {
221
0
    lwsl_err("%s: zero hdr_token_idx\n", __func__);
222
0
    return 1;
223
0
  }
224
225
0
  if (ah->nfrag >= LWS_ARRAY_SIZE(ah->frag_index)) {
226
0
    lwsl_err("%s: frag index %d too big\n", __func__, ah->nfrag);
227
0
    return 1;
228
0
  }
229
230
0
  if ((hdr_token_idx == WSI_TOKEN_HTTP_COLON_AUTHORITY ||
231
0
       hdr_token_idx == WSI_TOKEN_HTTP_COLON_METHOD ||
232
0
       hdr_token_idx == WSI_TOKEN_HTTP_COLON_PATH ||
233
0
       hdr_token_idx == WSI_TOKEN_COLON_PROTOCOL ||
234
0
       hdr_token_idx == WSI_TOKEN_HTTP_COLON_SCHEME) &&
235
0
       ah->frag_index[hdr_token_idx]) {
236
0
    if (!(ah->frags[ah->frag_index[hdr_token_idx]].flags & 1)) {
237
0
      lws_h2_goaway(lws_get_network_wsi(wsi),
238
0
              H2_ERR_PROTOCOL_ERROR,
239
0
              "Duplicated pseudoheader");
240
0
      return 1;
241
0
    }
242
0
  }
243
244
0
  if (ah->nfrag == 0)
245
0
    ah->nfrag = 1;
246
247
0
  ah->frags[ah->nfrag].offset = ah->pos;
248
0
  ah->frags[ah->nfrag].len = 0;
249
0
  ah->frags[ah->nfrag].nfrag = 0;
250
0
  ah->frags[ah->nfrag].flags = 2; /* we had reason to set it */
251
252
0
  ah->hdr_token_idx = hdr_token_idx;
253
254
  /*
255
   * Okay, but we could be, eg, the second or subsequent cookie: header
256
   */
257
258
0
  if (ah->frag_index[hdr_token_idx]) {
259
0
    int n;
260
261
    /* find the last fragment for this header... */
262
0
    n = ah->frag_index[hdr_token_idx];
263
0
    while (ah->frags[n].nfrag)
264
0
      n = ah->frags[n].nfrag;
265
    /* and point it to continue in our continuation fragment */
266
0
    ah->frags[n].nfrag = ah->nfrag;
267
0
  } else
268
0
    ah->frag_index[hdr_token_idx] = ah->nfrag;
269
270
0
  return 0;
271
0
}
272
273
static int lws_frag_append(struct lws *wsi, unsigned char c)
274
0
{
275
0
  struct allocated_headers *ah = wsi->http.ah;
276
277
0
  ah->data[ah->pos++] = (char)c;
278
0
  ah->frags[ah->nfrag].len++;
279
280
0
  return (unsigned int)ah->pos >= wsi->a.context->max_http_header_data;
281
0
}
282
283
static int lws_frag_end(struct lws *wsi)
284
0
{
285
0
  lwsl_header("%s\n", __func__);
286
0
  if (lws_frag_append(wsi, 0))
287
0
    return 1;
288
289
  /* don't account for the terminating NUL in the logical length */
290
0
  wsi->http.ah->frags[wsi->http.ah->nfrag].len--;
291
292
0
  wsi->http.ah->nfrag++;
293
0
  return 0;
294
0
}
295
296
int
297
lws_hdr_extant(struct lws *wsi, enum lws_token_indexes h)
298
0
{
299
0
  struct allocated_headers *ah = wsi->http.ah;
300
0
  int n;
301
302
0
  if (!ah)
303
0
    return 0;
304
305
0
  n = ah->frag_index[h];
306
0
  if (!n)
307
0
    return 0;
308
309
0
  return !!(ah->frags[n].flags & 2);
310
0
}
311
312
static void lws_dump_header(struct lws *wsi, int hdr)
313
0
{
314
0
  char s[200];
315
0
  const unsigned char *p;
316
0
  int len;
317
318
0
  if (hdr == LWS_HPACK_IGNORE_ENTRY) {
319
0
    lwsl_notice("hdr tok ignored\n");
320
0
    return;
321
0
  }
322
323
0
  (void)p;
324
325
0
  len = lws_hdr_copy(wsi, s, sizeof(s) - 1, (enum lws_token_indexes)hdr);
326
0
  if (len < 0)
327
0
    strcpy(s, "(too big to show)");
328
0
  else
329
0
    s[len] = '\0';
330
0
#if defined(_DEBUG)
331
0
  p = lws_token_to_string((enum lws_token_indexes)hdr);
332
0
  lwsl_header("  hdr tok %d (%s) = '%s' (len %d)\n", hdr,
333
0
       p ? (char *)p : (char *)"null", s, len);
334
0
#endif
335
0
}
336
337
/*
338
 * dynamic table
339
 *
340
 *  [ 0 ....   num_entries - 1]
341
 *
342
 *  Starts filling at 0+
343
 *
344
 *  #62 is *most recently entered*
345
 *
346
 *  Number of entries is not restricted, but aggregated size of the entry
347
 *  payloads is.  Unfortunately the way HPACK does this is specific to an
348
 *  imagined implementation, and lws implementation is much more efficient
349
 *  (ignoring unknown headers and using the lws token index for the header
350
 *  name part).
351
 */
352
353
/*
354
 * returns 0 if dynamic entry (arg and len are filled)
355
 * returns -1 if failure
356
 * returns nonzero token index if actually static token
357
 */
358
static int
359
lws_token_from_index(struct lws *wsi, int index, const char **arg, int *len,
360
         uint32_t *hdr_len)
361
0
{
362
0
  struct hpack_dynamic_table *dyn;
363
364
0
  if (index == LWS_HPACK_IGNORE_ENTRY)
365
0
    return LWS_HPACK_IGNORE_ENTRY;
366
367
  /* dynamic table only belongs to network wsi */
368
0
  wsi = lws_get_network_wsi(wsi);
369
0
  if (!wsi->h2.h2n)
370
0
    return -1;
371
372
0
  dyn = &wsi->h2.h2n->hpack_dyn_table;
373
374
0
  if (index < 0)
375
0
    return -1;
376
377
0
  if (index < (int)LWS_ARRAY_SIZE(static_token)) {
378
0
    if (arg && index < (int)LWS_ARRAY_SIZE(http2_canned)) {
379
0
      *arg = http2_canned[index];
380
0
      *len = (int)strlen(http2_canned[index]);
381
0
    }
382
0
    if (hdr_len)
383
0
      *hdr_len = static_hdr_len[index];
384
385
0
    return static_token[index];
386
0
  }
387
388
0
  if (!dyn) {
389
0
    lwsl_notice("no dynamic table\n");
390
0
    return -1;
391
0
  }
392
393
0
  if (index >= (int)LWS_ARRAY_SIZE(static_token) + dyn->used_entries) {
394
0
    lwsl_info("  %s: adjusted index %d >= %d\n", __func__, index,
395
0
        (int)LWS_ARRAY_SIZE(static_token) + dyn->used_entries);
396
0
    lws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR,
397
0
            "index out of range");
398
0
    return -1;
399
0
  }
400
401
0
  index -= (int)LWS_ARRAY_SIZE(static_token);
402
0
  index = lws_safe_modulo(dyn->pos - 1 - index, dyn->num_entries);
403
0
  if (index < 0)
404
0
    index += dyn->num_entries;
405
406
0
  lwsl_header("%s: dyn index %d, tok %d\n", __func__, index,
407
0
        dyn->entries[index].lws_hdr_idx);
408
409
0
  if (arg && len) {
410
0
    *arg = dyn->entries[index].value;
411
0
    *len = dyn->entries[index].value_len;
412
0
  }
413
414
0
  if (hdr_len)
415
0
    *hdr_len = dyn->entries[index].hdr_len;
416
417
0
  return dyn->entries[index].lws_hdr_idx;
418
0
}
419
420
static int
421
lws_h2_dynamic_table_dump(struct lws *wsi)
422
0
{
423
#if 0
424
  struct lws *nwsi = lws_get_network_wsi(wsi);
425
  struct hpack_dynamic_table *dyn;
426
  int n, m;
427
  const char *p;
428
429
  if (!nwsi->h2.h2n)
430
    return 1;
431
  dyn = &nwsi->h2.h2n->hpack_dyn_table;
432
433
  lwsl_header("Dump dyn table for nwsi %s (%d / %d members, pos = %d, "
434
        "start index %d, virt used %d / %d)\n", lws_wsi_tag(nwsi),
435
        dyn->used_entries, dyn->num_entries, dyn->pos,
436
        (uint32_t)LWS_ARRAY_SIZE(static_token),
437
        dyn->virtual_payload_usage, dyn->virtual_payload_max);
438
439
  for (n = 0; n < dyn->used_entries; n++) {
440
    m = lws_safe_modulo(dyn->pos - 1 - n, dyn->num_entries);
441
    if (m < 0)
442
      m += dyn->num_entries;
443
    if (dyn->entries[m].lws_hdr_idx != LWS_HPACK_IGNORE_ENTRY)
444
      p = (const char *)lws_token_to_string(
445
          dyn->entries[m].lws_hdr_idx);
446
    else
447
      p = "(ignored)";
448
    lwsl_header("   %3d: tok %s: (len %d) val '%s'\n",
449
          (int)(n + LWS_ARRAY_SIZE(static_token)), p,
450
          dyn->entries[m].hdr_len, dyn->entries[m].value ?
451
          dyn->entries[m].value : "null");
452
  }
453
#endif
454
0
  return 0;
455
0
}
456
457
static void
458
lws_dynamic_free(struct hpack_dynamic_table *dyn, int idx)
459
0
{
460
0
  lwsl_header("freeing %d for reuse\n", idx);
461
0
  dyn->virtual_payload_usage = (uint32_t)((unsigned int)dyn->virtual_payload_usage - (unsigned int)(dyn->entries[idx].value_len +
462
0
        dyn->entries[idx].hdr_len));
463
0
  lws_free_set_NULL(dyn->entries[idx].value);
464
0
  dyn->entries[idx].value = NULL;
465
0
  dyn->entries[idx].value_len = 0;
466
0
  dyn->entries[idx].hdr_len = 0;
467
0
  dyn->entries[idx].lws_hdr_idx = LWS_HPACK_IGNORE_ENTRY;
468
0
  dyn->used_entries--;
469
0
}
470
471
/*
472
 * There are two address spaces, 1) internal ringbuffer and 2) HPACK indexes.
473
 *
474
 * Internal ringbuffer:
475
 *
476
 * The internal ringbuffer wraps as we keep filling it, dyn->pos points to
477
 * the next index to be written.
478
 *
479
 * HPACK indexes:
480
 *
481
 * The last-written entry becomes entry 0, the previously-last-written entry
482
 * becomes entry 1 etc.
483
 */
484
485
static int
486
lws_dynamic_token_insert(struct lws *wsi, int hdr_len,
487
       int lws_hdr_index, char *arg, size_t len)
488
0
{
489
0
  struct hpack_dynamic_table *dyn;
490
0
  int new_index;
491
492
  /* dynamic table only belongs to network wsi */
493
0
  wsi = lws_get_network_wsi(wsi);
494
0
  if (!wsi->h2.h2n)
495
0
    return 1;
496
0
  dyn = &wsi->h2.h2n->hpack_dyn_table;
497
498
0
  if (!dyn->entries) {
499
0
    lwsl_err("%s: unsized dyn table\n", __func__);
500
501
0
    return 1;
502
0
  }
503
0
  lws_h2_dynamic_table_dump(wsi);
504
505
0
  new_index = lws_safe_modulo(dyn->pos, dyn->num_entries);
506
0
  if (dyn->num_entries && dyn->used_entries == dyn->num_entries) {
507
0
    if (dyn->virtual_payload_usage < dyn->virtual_payload_max)
508
0
      lwsl_err("Dropping header content before limit!\n");
509
    /* we have to drop the oldest to make space */
510
0
    lws_dynamic_free(dyn, new_index);
511
0
  }
512
513
  /*
514
   * evict guys to make room, allowing for some overage.  We have to
515
   * take care about getting a single huge header, and evicting
516
   * everything
517
   */
518
519
0
  while (dyn->virtual_payload_usage &&
520
0
         dyn->used_entries &&
521
0
         dyn->virtual_payload_usage + (unsigned int)hdr_len + len >
522
0
        dyn->virtual_payload_max + 1024) {
523
0
    int n = lws_safe_modulo(dyn->pos - dyn->used_entries,
524
0
            dyn->num_entries);
525
0
    if (n < 0)
526
0
      n += dyn->num_entries;
527
0
    lws_dynamic_free(dyn, n);
528
0
  }
529
530
0
  if (dyn->used_entries < dyn->num_entries)
531
0
    dyn->used_entries++;
532
533
0
  dyn->entries[new_index].value_len = 0;
534
535
0
  if (lws_hdr_index != LWS_HPACK_IGNORE_ENTRY) {
536
0
    if (dyn->entries[new_index].value)
537
0
      lws_free_set_NULL(dyn->entries[new_index].value);
538
0
    dyn->entries[new_index].value =
539
0
        lws_malloc(len + 1, "hpack dyn");
540
0
    if (!dyn->entries[new_index].value)
541
0
      return 1;
542
543
0
    memcpy(dyn->entries[new_index].value, arg, len);
544
0
    dyn->entries[new_index].value[len] = '\0';
545
0
    dyn->entries[new_index].value_len = (uint16_t)len;
546
0
  } else
547
0
    dyn->entries[new_index].value = NULL;
548
549
0
  dyn->entries[new_index].lws_hdr_idx = (uint16_t)lws_hdr_index;
550
0
  dyn->entries[new_index].hdr_len = (uint16_t)hdr_len;
551
552
0
  dyn->virtual_payload_usage = (uint32_t)(dyn->virtual_payload_usage +
553
0
          (unsigned int)hdr_len + len);
554
555
0
  lwsl_info("%s: index %ld: lws_hdr_index 0x%x, hdr len %d, '%s' len %d\n",
556
0
      __func__, (long)LWS_ARRAY_SIZE(static_token),
557
0
      lws_hdr_index, hdr_len, dyn->entries[new_index].value ?
558
0
         dyn->entries[new_index].value : "null", (int)len);
559
560
0
  dyn->pos = (uint16_t)lws_safe_modulo(dyn->pos + 1, dyn->num_entries);
561
562
0
  lws_h2_dynamic_table_dump(wsi);
563
564
0
  return 0;
565
0
}
566
567
int
568
lws_hpack_dynamic_size(struct lws *wsi, int size)
569
0
{
570
0
  struct hpack_dynamic_table *dyn;
571
0
  struct hpack_dt_entry *dte;
572
0
  struct lws *nwsi;
573
0
  int min, n = 0, m;
574
575
  /*
576
   * "size" here is coming from the http/2 SETTING
577
   * SETTINGS_HEADER_TABLE_SIZE.  This is a (virtual, in our case)
578
   * linear buffer containing dynamic header names and values... when it
579
   * is full, old entries are evicted.
580
   *
581
   * We encode the header as an lws_hdr_idx, which is all the rest of
582
   * lws cares about; if there is no matching header we store an empty
583
   * entry in the dyn table as a placeholder.
584
   *
585
   * So to make the two systems work together we keep an accounting of
586
   * what we are using to decide when to evict... we must only evict
587
   * things when the remote peer's accounting also makes him feel he
588
   * should evict something.
589
   */
590
591
0
  nwsi = lws_get_network_wsi(wsi);
592
0
  if (!nwsi->h2.h2n)
593
0
    goto bail;
594
595
0
  dyn = &nwsi->h2.h2n->hpack_dyn_table;
596
0
  lwsl_info("%s: from %d to %d, lim %u\n", __func__,
597
0
      (int)dyn->num_entries, size,
598
0
      (unsigned int)nwsi->a.vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE]);
599
600
0
  if (!size) {
601
0
    size = dyn->num_entries * 8;
602
0
    lws_hpack_destroy_dynamic_header(wsi);
603
0
  }
604
605
0
  if (size > (int)nwsi->a.vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE]) {
606
0
    lwsl_info("rejecting hpack dyn size %u vs %u\n", size,
607
0
        (unsigned int)nwsi->a.vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE]);
608
609
    // this seems necessary to work with some browsers
610
611
0
    if (nwsi->a.vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE] == 65536 &&
612
0
        size == 65537) { /* h2spec */
613
0
      lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
614
0
          "Asked for header table bigger than we told");
615
0
      goto bail;
616
0
    }
617
618
0
    size = (int)nwsi->a.vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE];
619
0
  }
620
621
0
  dyn->virtual_payload_max = (uint32_t)size;
622
623
0
  size = size / 8;
624
0
  min = size;
625
0
  if (min > dyn->used_entries)
626
0
    min = dyn->used_entries;
627
628
0
  if (size == dyn->num_entries)
629
0
    return 0;
630
631
0
  if (dyn->num_entries < min)
632
0
    min = dyn->num_entries;
633
634
  // lwsl_notice("dte requested size %d\n", size);
635
636
0
  dte = lws_zalloc(sizeof(*dte) * (unsigned int)(size + 1), "dynamic table entries");
637
0
  if (!dte)
638
0
    goto bail;
639
640
0
  while (dyn->virtual_payload_usage && dyn->used_entries &&
641
0
         dyn->virtual_payload_usage > dyn->virtual_payload_max) {
642
0
    n = lws_safe_modulo(dyn->pos - dyn->used_entries, dyn->num_entries);
643
0
    if (n < 0)
644
0
      n += dyn->num_entries;
645
0
    lws_dynamic_free(dyn, n);
646
0
  }
647
648
0
  if (min > dyn->used_entries)
649
0
    min = dyn->used_entries;
650
651
0
  if (dyn->entries) {
652
0
    for (n = 0; n < min; n++) {
653
0
      m = (dyn->pos - dyn->used_entries + n) %
654
0
            dyn->num_entries;
655
0
      if (m < 0)
656
0
        m += dyn->num_entries;
657
0
      dte[n] = dyn->entries[m];
658
0
    }
659
660
0
    lws_free(dyn->entries);
661
0
  }
662
663
0
  dyn->entries = dte;
664
0
  dyn->num_entries = (uint16_t)size;
665
0
  dyn->used_entries = (uint16_t)min;
666
0
  if (size)
667
0
    dyn->pos = (uint16_t)lws_safe_modulo(min, size);
668
0
  else
669
0
    dyn->pos = 0;
670
671
0
  lws_h2_dynamic_table_dump(wsi);
672
673
0
  return 0;
674
675
0
bail:
676
0
  lwsl_info("%s: failed to resize to %d\n", __func__, size);
677
678
0
  return 1;
679
0
}
680
681
void
682
lws_hpack_destroy_dynamic_header(struct lws *wsi)
683
0
{
684
0
  struct hpack_dynamic_table *dyn;
685
0
  int n;
686
687
0
  if (!wsi->h2.h2n)
688
0
    return;
689
690
0
  dyn = &wsi->h2.h2n->hpack_dyn_table;
691
692
0
  if (!dyn->entries)
693
0
    return;
694
695
0
  for (n = 0; n < dyn->num_entries; n++)
696
0
    if (dyn->entries[n].value)
697
0
      lws_free_set_NULL(dyn->entries[n].value);
698
699
0
  lws_free_set_NULL(dyn->entries);
700
0
}
701
702
static int
703
lws_hpack_use_idx_hdr(struct lws *wsi, int idx, int known_token)
704
0
{
705
0
  const char *arg = NULL;
706
0
  int len = 0;
707
0
  const char *p = NULL;
708
0
  int tok = lws_token_from_index(wsi, idx, &arg, &len, NULL);
709
710
0
  if (tok == LWS_HPACK_IGNORE_ENTRY) {
711
0
    lwsl_header("%s: lws_token says ignore, returning\n", __func__);
712
0
    return 0;
713
0
  }
714
715
0
  if (tok == -1) {
716
0
    lwsl_info("%s: idx %d mapped to tok %d\n", __func__, idx, tok);
717
0
    return 1;
718
0
  }
719
720
0
  if (arg) {
721
    /* dynamic result */
722
0
    if (known_token > 0)
723
0
      tok = known_token;
724
0
    lwsl_header("%s: dyn: idx %d '%s' tok %d\n", __func__, idx, arg,
725
0
         tok);
726
0
  } else
727
0
    lwsl_header("writing indexed hdr %d (tok %d '%s')\n", idx, tok,
728
0
        lws_token_to_string((enum lws_token_indexes)tok));
729
730
0
  if (tok == LWS_HPACK_IGNORE_ENTRY)
731
0
    return 0;
732
733
0
  if (arg)
734
0
    p = arg;
735
736
0
  if (idx < (int)LWS_ARRAY_SIZE(http2_canned))
737
0
    p = http2_canned[idx];
738
739
0
  if (lws_frag_start(wsi, tok))
740
0
    return 1;
741
742
0
  if (p)
743
0
    while (*p && len--)
744
0
      if (lws_frag_append(wsi, (unsigned char)*p++))
745
0
        return 1;
746
747
0
  if (lws_frag_end(wsi))
748
0
    return 1;
749
750
0
  lws_dump_header(wsi, tok);
751
752
0
  return 0;
753
0
}
754
755
#if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
756
static uint8_t lws_header_implies_psuedoheader_map[] = {
757
  0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
758
};
759
#endif
760
#if !defined(LWS_HTTP_HEADERS_ALL) &&  defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
761
static uint8_t lws_header_implies_psuedoheader_map[] = {
762
  0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
763
};
764
#endif
765
#if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) &&  defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
766
static uint8_t lws_header_implies_psuedoheader_map[] = {
767
  0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
768
};
769
#endif
770
#if !defined(LWS_HTTP_HEADERS_ALL) &&  defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) &&  defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
771
static uint8_t lws_header_implies_psuedoheader_map[] = {
772
  0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
773
};
774
#endif
775
#if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) &&  defined(LWS_ROLE_H2)
776
static uint8_t lws_header_implies_psuedoheader_map[] = {
777
  0x03,0x00,0x80,0x0f,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
778
};
779
#endif
780
#if !defined(LWS_HTTP_HEADERS_ALL) &&  defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) &&  defined(LWS_ROLE_H2)
781
static uint8_t lws_header_implies_psuedoheader_map[] = {
782
  0x07,0x00,0x00,0x3e,0x00,0x00,0x00,0x80,0x03,0x09,0x00,0x00,0x00,0x00,0x00,0x00,
783
};
784
#endif
785
#if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) &&  defined(LWS_ROLE_WS) &&  defined(LWS_ROLE_H2)
786
static uint8_t lws_header_implies_psuedoheader_map[] = {
787
  0x03,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x00,0x00,
788
};
789
#endif
790
#if defined(LWS_HTTP_HEADERS_ALL) || ( defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) &&  defined(LWS_ROLE_WS) &&  defined(LWS_ROLE_H2))
791
static uint8_t lws_header_implies_psuedoheader_map[] = {
792
  0x07,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x00,0x0e,0x24,0x00,0x00,0x00,0x00,0x00,
793
};
794
#endif
795
796
797
static int
798
lws_hpack_handle_pseudo_rules(struct lws *nwsi, struct lws *wsi, int m)
799
0
{
800
0
  if (m == LWS_HPACK_IGNORE_ENTRY || m == -1)
801
0
    return 0;
802
803
0
  if (wsi->seen_nonpseudoheader &&
804
0
      (lws_header_implies_psuedoheader_map[m >> 3] & (1 << (m & 7)))) {
805
806
0
    lwsl_info("lws tok %d seems to be a pseudoheader\n", m);
807
808
    /*
809
     * it's not legal to see a
810
     * pseudoheader after normal
811
     * headers
812
     */
813
0
    lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,
814
0
      "Pseudoheader after normal hdrs");
815
0
    return 1;
816
0
  }
817
818
0
  if (!(lws_header_implies_psuedoheader_map[m >> 3] & (1 << (m & 7))))
819
0
    wsi->seen_nonpseudoheader = 1;
820
821
0
  return 0;
822
0
}
823
824
int lws_hpack_interpret(struct lws *wsi, unsigned char c)
825
0
{
826
0
  struct lws *nwsi = lws_get_network_wsi(wsi);
827
0
  struct lws_h2_netconn *h2n = nwsi->h2.h2n;
828
0
  struct allocated_headers *ah = wsi->http.ah;
829
0
  unsigned int prev;
830
0
  unsigned char c1;
831
0
  int n, m, plen;
832
833
0
  if (!h2n)
834
0
    return -1;
835
836
  /*
837
   * HPKT_INDEXED_HDR_7     1xxxxxxx: just "header field"
838
   * HPKT_INDEXED_HDR_6_VALUE_INCR  01xxxxxx: NEW indexed hdr + val
839
   * HPKT_LITERAL_HDR_VALUE_INCR    01000000: NEW literal hdr + val
840
   * HPKT_INDEXED_HDR_4_VALUE   0000xxxx: indexed hdr + val
841
   * HPKT_INDEXED_HDR_4_VALUE_NEVER 0001xxxx: NEVER NEW indexed hdr + val
842
   * HPKT_LITERAL_HDR_VALUE   00000000: literal hdr + val
843
   * HPKT_LITERAL_HDR_VALUE_NEVER   00010000: NEVER NEW literal hdr + val
844
   */
845
0
  switch (h2n->hpack) {
846
847
0
  case HPKS_TYPE:
848
0
    h2n->is_first_header_char = 1;
849
0
    h2n->huff_pad = 0;
850
0
    h2n->zero_huff_padding = 0;
851
0
    h2n->last_action_dyntable_resize = 0;
852
0
    h2n->ext_count = 0;
853
0
    h2n->hpack_hdr_len = 0;
854
0
    h2n->unknown_header = 0;
855
0
    ah->parser_state = 255;
856
857
0
    if (c & 0x80) { /* 1....  indexed header field only */
858
      /* just a possibly-extended integer */
859
0
      h2n->hpack_type = HPKT_INDEXED_HDR_7;
860
0
      lwsl_header("HPKT_INDEXED_HDR_7 hdr %d\n", c & 0x7f);
861
0
      lws_h2_dynamic_table_dump(wsi);
862
863
0
      h2n->hdr_idx = c & 0x7f;
864
0
      if ((c & 0x7f) == 0x7f) {
865
0
        h2n->hpack_len = 0;
866
0
        h2n->hpack_m = 0x7f;
867
0
        h2n->hpack = HPKS_IDX_EXT;
868
0
        break;
869
0
      }
870
0
      if (!h2n->hdr_idx) {
871
0
        lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
872
0
                "hdr index 0 seen");
873
0
          return 1;
874
0
      }
875
876
0
      m = lws_token_from_index(wsi, (int)h2n->hdr_idx,
877
0
             NULL, NULL, NULL);
878
0
      if (lws_hpack_handle_pseudo_rules(nwsi, wsi, m))
879
0
        return 1;
880
881
0
      lwsl_header("HPKT_INDEXED_HDR_7: hdr %d\n", c & 0x7f);
882
0
      if (lws_hpack_use_idx_hdr(wsi, c & 0x7f, -1)) {
883
0
        lwsl_header("%s: idx hdr wr fail\n", __func__);
884
0
        return 1;
885
0
      }
886
      /* stay at same state */
887
0
      break;
888
0
    }
889
0
    if (c & 0x40) { /* 01.... indexed or literal header incr idx */
890
      /*
891
       * [possibly-ext hdr idx (6) | new literal hdr name]
892
       * H + possibly-ext value length
893
       * literal value
894
       */
895
0
      h2n->hdr_idx = 0;
896
0
      if (c == 0x40) { /* literal header */
897
0
        lwsl_header("   HPKT_LITERAL_HDR_VALUE_INCR\n");
898
0
        h2n->hpack_type = HPKT_LITERAL_HDR_VALUE_INCR;
899
0
        h2n->value = 0;
900
0
        h2n->hpack_len = 0;
901
0
        h2n->hpack = HPKS_HLEN;
902
0
        break;
903
0
      }
904
      /* indexed header */
905
0
      h2n->hpack_type = HPKT_INDEXED_HDR_6_VALUE_INCR;
906
0
      lwsl_header(" HPKT_INDEXED_HDR_6_VALUE_INCR (hdr %d)\n",
907
0
           c & 0x3f);
908
0
      h2n->hdr_idx = c & 0x3f;
909
0
      if ((c & 0x3f) == 0x3f) {
910
0
        h2n->hpack_m = 0x3f;
911
0
        h2n->hpack_len = 0;
912
0
        h2n->hpack = HPKS_IDX_EXT;
913
0
        break;
914
0
      }
915
916
0
      h2n->value = 1;
917
0
      h2n->hpack = HPKS_HLEN;
918
0
      if (!h2n->hdr_idx) {
919
0
        lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
920
0
                "hdr index 0 seen");
921
0
          return 1;
922
0
      }
923
0
      break;
924
0
    }
925
0
    switch(c & 0xf0) {
926
0
    case 0x10: /* literal header never index */
927
0
    case 0:    /* literal header without indexing */
928
      /*
929
       * follows 0x40 except 4-bit hdr idx
930
       * and don't add to index
931
       */
932
0
      if (c == 0) { /* literal name */
933
0
        h2n->hpack_type = HPKT_LITERAL_HDR_VALUE;
934
0
        lwsl_header("   HPKT_LITERAL_HDR_VALUE\n");
935
0
        h2n->hpack = HPKS_HLEN;
936
0
        h2n->value = 0;
937
0
        break;
938
0
      }
939
0
      if (c == 0x10) { /* literal name NEVER */
940
0
        h2n->hpack_type = HPKT_LITERAL_HDR_VALUE_NEVER;
941
0
        lwsl_header("  HPKT_LITERAL_HDR_VALUE_NEVER\n");
942
0
        h2n->hpack = HPKS_HLEN;
943
0
        h2n->value = 0;
944
0
        break;
945
0
      }
946
0
      lwsl_header("indexed\n");
947
      /* indexed name */
948
0
      if (c & 0x10) {
949
0
        h2n->hpack_type = HPKT_INDEXED_HDR_4_VALUE_NEVER;
950
0
        lwsl_header("HPKT_LITERAL_HDR_4_VALUE_NEVER\n");
951
0
      } else {
952
0
        h2n->hpack_type = HPKT_INDEXED_HDR_4_VALUE;
953
0
        lwsl_header("   HPKT_INDEXED_HDR_4_VALUE\n");
954
0
      }
955
0
      h2n->hdr_idx = 0;
956
0
      if ((c & 0xf) == 0xf) {
957
0
        h2n->hpack_len = c & 0xf;
958
0
        h2n->hpack_m = 0xf;
959
0
        h2n->hpack_len = 0;
960
0
        h2n->hpack = HPKS_IDX_EXT;
961
0
        break;
962
0
      }
963
0
      h2n->hdr_idx = c & 0xf;
964
0
      h2n->value = 1;
965
0
      h2n->hpack = HPKS_HLEN;
966
0
      break;
967
968
0
    case 0x20:
969
0
    case 0x30: /* header table size update */
970
      /* possibly-extended size value (5) */
971
0
      lwsl_header("HPKT_SIZE_5 %x\n", c &0x1f);
972
0
      h2n->hpack_type = HPKT_SIZE_5;
973
0
      h2n->hpack_len = c & 0x1f;
974
0
      if (h2n->hpack_len == 0x1f) {
975
0
        h2n->hpack_m = 0x1f;
976
0
        h2n->hpack_len = 0;
977
0
        h2n->hpack = HPKS_IDX_EXT;
978
0
        break;
979
0
      }
980
0
      h2n->last_action_dyntable_resize = 1;
981
0
      if (lws_hpack_dynamic_size(wsi, (int)h2n->hpack_len))
982
0
        return 1;
983
0
      break;
984
0
    }
985
0
    break;
986
987
0
  case HPKS_IDX_EXT:
988
0
    h2n->hpack_len = (uint32_t)((unsigned int)h2n->hpack_len |
989
0
        (unsigned int)((c & 0x7f) << h2n->ext_count));
990
0
    h2n->ext_count = (uint8_t)(h2n->ext_count + 7);
991
0
    if (c & 0x80) /* extended int not complete yet */
992
0
      break;
993
994
    /* extended integer done */
995
0
    h2n->hpack_len += h2n->hpack_m;
996
0
    lwsl_header("HPKS_IDX_EXT: hpack_len %u\n", (unsigned int)h2n->hpack_len);
997
998
0
    switch (h2n->hpack_type) {
999
0
    case HPKT_INDEXED_HDR_7:
1000
0
      if (lws_hpack_use_idx_hdr(wsi, (int)h2n->hpack_len,
1001
0
              (int)h2n->hdr_idx)) {
1002
0
        lwsl_notice("%s: hd7 use fail\n", __func__);
1003
0
        return 1;
1004
0
      }
1005
0
      h2n->hpack = HPKS_TYPE;
1006
0
      break;
1007
1008
0
    case HPKT_SIZE_5:
1009
0
      h2n->last_action_dyntable_resize = 1;
1010
0
      if (lws_hpack_dynamic_size(wsi, (int)h2n->hpack_len))
1011
0
        return 1;
1012
0
      h2n->hpack = HPKS_TYPE;
1013
0
      break;
1014
1015
0
    default:
1016
0
      h2n->hdr_idx = h2n->hpack_len;
1017
0
      if (!h2n->hdr_idx) {
1018
0
        lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
1019
0
                "extended header index was 0");
1020
0
        return 1;
1021
0
      }
1022
0
      h2n->value = 1;
1023
0
      h2n->hpack = HPKS_HLEN;
1024
0
      break;
1025
0
    }
1026
0
    break;
1027
1028
0
  case HPKS_HLEN: /* [ H | 7+ ] */
1029
0
    h2n->huff = !!(c & 0x80);
1030
0
    h2n->hpack_pos = 0;
1031
0
    h2n->hpack_len = c & 0x7f;
1032
1033
0
    if (h2n->hpack_len == 0x7f) {
1034
0
      h2n->hpack_m = 0x7f;
1035
0
      h2n->hpack_len = 0;
1036
0
      h2n->ext_count = 0;
1037
0
      h2n->hpack = HPKS_HLEN_EXT;
1038
0
      break;
1039
0
    }
1040
1041
0
    if (h2n->value && !h2n->hpack_len) {
1042
0
      lwsl_debug("%s: zero-length header data\n", __func__);
1043
0
      h2n->hpack = HPKS_TYPE;
1044
0
      goto fin;
1045
0
    }
1046
1047
0
pre_data:
1048
0
    h2n->hpack = HPKS_DATA;
1049
0
    if (!h2n->value || !h2n->hdr_idx) {
1050
0
      ah->parser_state = WSI_TOKEN_NAME_PART;
1051
0
      ah->lextable_pos = 0;
1052
0
      h2n->unknown_header = 0;
1053
0
      break;
1054
0
    }
1055
1056
0
    if (h2n->hpack_type == HPKT_LITERAL_HDR_VALUE ||
1057
0
        h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_INCR ||
1058
0
        h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_NEVER) {
1059
0
      n = ah->parser_state;
1060
0
      if (n == 255) {
1061
0
        n = -1;
1062
0
        h2n->hdr_idx = (uint32_t)-1;
1063
0
      } else
1064
0
        h2n->hdr_idx = 1;
1065
0
    } else {
1066
0
      n = lws_token_from_index(wsi, (int)h2n->hdr_idx, NULL,
1067
0
             NULL, NULL);
1068
0
      lwsl_header("  lws_tok_from_idx(%u) says %d\n",
1069
0
           (unsigned int)h2n->hdr_idx, n);
1070
0
    }
1071
1072
0
    if (n == LWS_HPACK_IGNORE_ENTRY || n == -1)
1073
0
      h2n->hdr_idx = LWS_HPACK_IGNORE_ENTRY;
1074
1075
0
    switch (h2n->hpack_type) {
1076
    /*
1077
     * hpack types with literal headers were parsed by the lws
1078
     * header SM... on recognition of a known lws header, it does
1079
     * the correct lws_frag_start() for us already.  Other types
1080
     * (ie, indexed header) need us to do it here.
1081
     */
1082
0
    case HPKT_LITERAL_HDR_VALUE_INCR:
1083
0
    case HPKT_LITERAL_HDR_VALUE:
1084
0
    case HPKT_LITERAL_HDR_VALUE_NEVER:
1085
0
      break;
1086
0
    default:
1087
0
      if (n != -1 && n != LWS_HPACK_IGNORE_ENTRY &&
1088
0
          lws_frag_start(wsi, n)) {
1089
0
        lwsl_header("%s: frag start failed\n",
1090
0
              __func__);
1091
0
        return 1;
1092
0
      }
1093
0
      break;
1094
0
    }
1095
0
    break;
1096
1097
0
  case HPKS_HLEN_EXT:
1098
0
    h2n->hpack_len = (uint32_t)((unsigned int)h2n->hpack_len |
1099
0
        (unsigned int)((c & 0x7f) << h2n->ext_count));
1100
0
    h2n->ext_count = (uint8_t)(h2n->ext_count + 7);
1101
0
    if (c & 0x80) /* extended integer not complete yet */
1102
0
      break;
1103
1104
0
    h2n->hpack_len += h2n->hpack_m;
1105
0
    goto pre_data;
1106
1107
0
  case HPKS_DATA:
1108
    //lwsl_header(" 0x%02X huff %d\n", c, h2n->huff);
1109
0
      c1 = c;
1110
1111
0
    for (n = 0; n < 8; n++) {
1112
0
      if (h2n->huff) {
1113
0
        char b = (c >> 7) & 1;
1114
0
        prev = h2n->hpack_pos;
1115
0
        h2n->hpack_pos = (uint16_t)huftable_decode(
1116
0
            (int)h2n->hpack_pos, b);
1117
0
        c = (unsigned char)(c << 1);
1118
0
        if (h2n->hpack_pos == 0xffff) {
1119
0
          lwsl_notice("Huffman err\n");
1120
0
          return 1;
1121
0
        }
1122
0
        if (!(h2n->hpack_pos & 0x8000)) {
1123
0
          if (!b)
1124
0
            h2n->zero_huff_padding = 1;
1125
0
          h2n->huff_pad++;
1126
0
          continue;
1127
0
        }
1128
0
        c1 = (uint8_t)(h2n->hpack_pos & 0x7fff);
1129
0
        h2n->hpack_pos = 0;
1130
0
        h2n->huff_pad = 0;
1131
0
        h2n->zero_huff_padding = 0;
1132
1133
        /* EOS |11111111|11111111|11111111|111111 */
1134
0
        if (!c1 && prev == HUFTABLE_0x100_PREV) {
1135
0
          lws_h2_goaway(nwsi,
1136
0
            H2_ERR_COMPRESSION_ERROR,
1137
0
            "Huffman EOT seen");
1138
0
          return 1;
1139
0
        }
1140
0
      } else
1141
0
        n = 8;
1142
1143
0
      if (h2n->value) { /* value */
1144
1145
0
        if (h2n->hdr_idx &&
1146
0
            h2n->hdr_idx != LWS_HPACK_IGNORE_ENTRY) {
1147
1148
0
          if (ah->hdr_token_idx ==
1149
0
              WSI_TOKEN_HTTP_COLON_PATH) {
1150
1151
0
            switch (lws_parse_urldecode(
1152
0
                    wsi, &c1)) {
1153
0
            case LPUR_CONTINUE:
1154
0
              break;
1155
0
            case LPUR_SWALLOW:
1156
0
              goto swallow;
1157
0
            case LPUR_EXCESSIVE:
1158
0
            case LPUR_FORBID:
1159
0
              lws_h2_goaway(nwsi,
1160
0
                H2_ERR_PROTOCOL_ERROR,
1161
0
                "Evil URI");
1162
0
              return 1;
1163
1164
0
            default:
1165
0
              return -1;
1166
0
            }
1167
0
          }
1168
0
          if (lws_frag_append(wsi, c1)) {
1169
0
            lwsl_notice(
1170
0
              "%s: frag app fail\n",
1171
0
                  __func__);
1172
0
            return 1;
1173
0
          }
1174
0
        } //else
1175
          //lwsl_header("ignoring %c\n", c1);
1176
0
      } else {
1177
        /*
1178
         * Convert name using existing parser,
1179
         * If h2n->unknown_header == 0, result is
1180
         * in wsi->parser_state
1181
         * using WSI_TOKEN_GET_URI.
1182
         *
1183
         * If unknown header h2n->unknown_header
1184
         * will be set.
1185
         */
1186
0
        h2n->hpack_hdr_len++;
1187
0
        if (h2n->is_first_header_char) {
1188
0
          h2n->is_first_header_char = 0;
1189
0
          h2n->first_hdr_char = (char)c1;
1190
0
        }
1191
0
        lwsl_header("parser: %c\n", c1);
1192
        /* uppercase header names illegal */
1193
0
        if (c1 >= 'A' && c1 <= 'Z') {
1194
0
          lws_h2_goaway(nwsi,
1195
0
            H2_ERR_COMPRESSION_ERROR,
1196
0
            "Uppercase literal hpack hdr");
1197
0
          return 1;
1198
0
        }
1199
0
        plen = 1;
1200
0
        if (!h2n->unknown_header &&
1201
0
            lws_parse(wsi, &c1, &plen))
1202
0
          h2n->unknown_header = 1;
1203
0
      }
1204
0
swallow:
1205
0
      (void)n;
1206
0
    } // for n
1207
1208
0
    if (--h2n->hpack_len)
1209
0
      break;
1210
1211
    /*
1212
     * The header (h2n->value = 0) or the payload (h2n->value = 1)
1213
     * is complete.
1214
     */
1215
1216
0
    if (h2n->huff && (h2n->huff_pad > 7 ||
1217
0
        (h2n->zero_huff_padding && h2n->huff_pad))) {
1218
0
      lwsl_info("zero_huff_padding: %d huff_pad: %d\n",
1219
0
            h2n->zero_huff_padding, h2n->huff_pad);
1220
0
      lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
1221
0
              "Huffman padding excessive or wrong");
1222
0
      return 1;
1223
0
    }
1224
0
fin:
1225
0
    if (!h2n->value && (
1226
0
        h2n->hpack_type == HPKT_LITERAL_HDR_VALUE ||
1227
0
        h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_INCR ||
1228
0
        h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_NEVER)) {
1229
0
      h2n->hdr_idx = LWS_HPACK_IGNORE_ENTRY;
1230
0
      lwsl_header("wsi->parser_state: %d\n",
1231
0
          ah->parser_state);
1232
1233
0
      if (ah->parser_state == WSI_TOKEN_NAME_PART) {
1234
        /* h2 headers come without the colon */
1235
0
        c1 = ':';
1236
0
        plen = 1;
1237
0
        n = lws_parse(wsi, &c1, &plen);
1238
0
        (void)n;
1239
0
      }
1240
1241
0
      if (ah->parser_state == WSI_TOKEN_NAME_PART ||
1242
0
#if defined(LWS_WITH_CUSTOM_HEADERS)
1243
0
          ah->parser_state == WSI_TOKEN_UNKNOWN_VALUE_PART ||
1244
0
#endif
1245
0
          ah->parser_state == WSI_TOKEN_SKIPPING) {
1246
0
        h2n->unknown_header = 1;
1247
0
        ah->parser_state = 0xff;
1248
0
        wsi->seen_nonpseudoheader = 1;
1249
0
      }
1250
0
    }
1251
1252
    /* we have the header */
1253
0
    if (!h2n->value) {
1254
0
      h2n->value = 1;
1255
0
      h2n->hpack = HPKS_HLEN;
1256
0
      h2n->huff_pad = 0;
1257
0
      h2n->zero_huff_padding = 0;
1258
0
      h2n->ext_count = 0;
1259
0
      break;
1260
0
    }
1261
1262
    /*
1263
     * we have got both the header and value
1264
     */
1265
1266
0
    m = -1;
1267
0
    switch (h2n->hpack_type) {
1268
    /*
1269
     * These are the only two that insert to the dyntable
1270
     */
1271
    /* NEW indexed hdr with value */
1272
0
    case HPKT_INDEXED_HDR_6_VALUE_INCR:
1273
      /* header length is determined by known index */
1274
0
      m = lws_token_from_index(wsi, (int)h2n->hdr_idx, NULL, NULL,
1275
0
          &h2n->hpack_hdr_len);
1276
0
      if (m < 0)
1277
        /*
1278
         * The peer may only send known 6-bit indexes,
1279
         * there's still the possibility it sends an unset
1280
         * dynamic index that we can't succeed to look up
1281
         */
1282
0
        return 1;
1283
0
      goto add_it;
1284
    /* NEW literal hdr with value */
1285
0
    case HPKT_LITERAL_HDR_VALUE_INCR:
1286
      /*
1287
       * hdr is a new literal, so length is already in
1288
       * h2n->hpack_hdr_len
1289
       */
1290
0
      m = ah->parser_state;
1291
0
      if (h2n->unknown_header ||
1292
0
          ah->parser_state == WSI_TOKEN_NAME_PART ||
1293
0
          ah->parser_state == WSI_TOKEN_SKIPPING) {
1294
0
        if (h2n->first_hdr_char == ':') {
1295
0
          lwsl_info("HPKT_LITERAL_HDR_VALUE_INCR:"
1296
0
              " end state %d unk hdr %d\n",
1297
0
              ah->parser_state,
1298
0
            h2n->unknown_header);
1299
          /* unknown pseudoheaders are illegal */
1300
0
          lws_h2_goaway(nwsi,
1301
0
                  H2_ERR_PROTOCOL_ERROR,
1302
0
                  "Unknown pseudoheader");
1303
0
          return 1;
1304
0
        }
1305
0
        m = LWS_HPACK_IGNORE_ENTRY;
1306
0
      }
1307
0
add_it:
1308
      /*
1309
       * mark us as having been set at the time of dynamic
1310
       * token insertion.
1311
       */
1312
0
      ah->frags[ah->nfrag].flags |= 1;
1313
1314
0
      if (lws_dynamic_token_insert(wsi, (int)h2n->hpack_hdr_len, m,
1315
0
          &ah->data[ah->frags[ah->nfrag].offset],
1316
0
          ah->frags[ah->nfrag].len)) {
1317
0
        lwsl_notice("%s: tok_insert fail\n", __func__);
1318
0
        return 1;
1319
0
      }
1320
0
      break;
1321
1322
0
    default:
1323
0
      break;
1324
0
    }
1325
1326
0
    if (h2n->hdr_idx != LWS_HPACK_IGNORE_ENTRY && lws_frag_end(wsi))
1327
0
      return 1;
1328
1329
0
    if (h2n->hpack_type != HPKT_INDEXED_HDR_6_VALUE_INCR) {
1330
1331
0
      if (h2n->hpack_type == HPKT_LITERAL_HDR_VALUE ||
1332
0
          h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_INCR ||
1333
0
          h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_NEVER) {
1334
0
        m = ah->parser_state;
1335
0
        if (m == 255)
1336
0
          m = -1;
1337
0
      } else
1338
0
        m = lws_token_from_index(wsi, (int)h2n->hdr_idx,
1339
0
               NULL, NULL, NULL);
1340
0
    }
1341
1342
0
    if (m != -1 && m != LWS_HPACK_IGNORE_ENTRY)
1343
0
      lws_dump_header(wsi, m);
1344
1345
0
    if (lws_hpack_handle_pseudo_rules(nwsi, wsi, m))
1346
0
      return 1;
1347
1348
0
    h2n->is_first_header_char = 1;
1349
0
    h2n->hpack = HPKS_TYPE;
1350
0
    break;
1351
0
  }
1352
1353
0
  return 0;
1354
0
}
1355
1356
1357
1358
static unsigned int
1359
lws_h2_num_start(int starting_bits, unsigned long num)
1360
0
{
1361
0
  unsigned int mask = (unsigned int)((1 << starting_bits) - 1);
1362
1363
0
  if (num < mask)
1364
0
    return (unsigned int)num;
1365
1366
0
  return mask;
1367
0
}
1368
1369
static int
1370
lws_h2_num(int starting_bits, unsigned long num,
1371
       unsigned char **p, unsigned char *end)
1372
0
{
1373
0
  unsigned int mask = (unsigned int)((1 << starting_bits) - 1);
1374
1375
0
  if (num < mask)
1376
0
    return 0;
1377
1378
0
  num -= mask;
1379
0
  do {
1380
0
    if (num > 127)
1381
0
      *((*p)++) = (uint8_t)(0x80 | (num & 0x7f));
1382
0
    else
1383
0
      *((*p)++) = (uint8_t)(0x00 | (num & 0x7f));
1384
0
    if (*p >= end)
1385
0
      return 1;
1386
0
    num >>= 7;
1387
0
  } while (num);
1388
1389
0
  return 0;
1390
0
}
1391
1392
int lws_add_http2_header_by_name(struct lws *wsi, const unsigned char *name,
1393
         const unsigned char *value, int length,
1394
         unsigned char **p, unsigned char *end)
1395
0
{
1396
0
  int len;
1397
1398
0
#if defined(_DEBUG)
1399
  /* value does not have to be NUL-terminated... %.*s not available on
1400
   * all platforms */
1401
0
  if (value) {
1402
0
    lws_strnncpy((char *)*p, (const char *)value, length,
1403
0
        lws_ptr_diff(end, (*p)));
1404
1405
0
    lwsl_header("%s: %p  %s:%s (len %d)\n", __func__, *p, name,
1406
0
        (const char *)*p, length);
1407
0
  } else {
1408
0
    lwsl_err("%s: %p dummy copy %s (len %d)\n", __func__, *p, name, length);
1409
0
  }
1410
0
#endif
1411
1412
0
  len = (int)strlen((char *)name);
1413
0
  if (len)
1414
0
    if (name[len - 1] == ':')
1415
0
      len--;
1416
1417
0
  if (wsi->mux_substream && !strncmp((const char *)name,
1418
0
               "transfer-encoding", (unsigned int)len)) {
1419
0
    lwsl_header("rejecting %s\n", name);
1420
1421
0
    return 0;
1422
0
  }
1423
1424
0
  if (end - *p < len + length + 8)
1425
0
    return 1;
1426
1427
0
  *((*p)++) = 0; /* literal hdr, literal name,  */
1428
1429
0
  *((*p)++) = (uint8_t)(0 | (uint8_t)lws_h2_num_start(7, (unsigned long)len)); /* non-HUF */
1430
0
  if (lws_h2_num(7, (unsigned long)len, p, end))
1431
0
    return 1;
1432
1433
  /* upper-case header names are verboten in h2, but OK on h1, so
1434
   * they're not illegal per se.  Silently convert them for h2... */
1435
1436
0
  while(len--)
1437
0
    *((*p)++) = (uint8_t)tolower((int)*name++);
1438
1439
0
  *((*p)++) = (uint8_t)(0 | (uint8_t)lws_h2_num_start(7, (unsigned long)length)); /* non-HUF */
1440
0
  if (lws_h2_num(7, (unsigned long)length, p, end))
1441
0
    return 1;
1442
1443
0
  if (value)
1444
0
    memcpy(*p, value, (unsigned int)length);
1445
0
  *p += length;
1446
1447
0
  return 0;
1448
0
}
1449
1450
int lws_add_http2_header_by_token(struct lws *wsi, enum lws_token_indexes token,
1451
          const unsigned char *value, int length,
1452
          unsigned char **p, unsigned char *end)
1453
0
{
1454
0
  const unsigned char *name;
1455
1456
0
  name = lws_token_to_string(token);
1457
0
  if (!name)
1458
0
    return 1;
1459
1460
0
  return lws_add_http2_header_by_name(wsi, name, value, length, p, end);
1461
0
}
1462
1463
int lws_add_http2_header_status(struct lws *wsi, unsigned int code,
1464
        unsigned char **p, unsigned char *end)
1465
0
{
1466
0
  unsigned char status[12];
1467
0
  int n;
1468
1469
0
  wsi->h2.send_END_STREAM = 0; // !!(code >= 400);
1470
1471
0
  n = sprintf((char *)status, "%u", code);
1472
0
  if (lws_add_http2_header_by_token(wsi, WSI_TOKEN_HTTP_COLON_STATUS,
1473
0
            status, n, p, end))
1474
1475
0
    return 1;
1476
1477
0
  return 0;
1478
0
}