Coverage Report

Created: 2026-02-09 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Utilities/cmnghttp2/lib/nghttp2_hd.c
Line
Count
Source
1
/*
2
 * nghttp2 - HTTP/2 C Library
3
 *
4
 * Copyright (c) 2013 Tatsuhiro Tsujikawa
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining
7
 * a copy of this software and associated documentation files (the
8
 * "Software"), to deal in the Software without restriction, including
9
 * without limitation the rights to use, copy, modify, merge, publish,
10
 * distribute, sublicense, and/or sell copies of the Software, and to
11
 * permit persons to whom the Software is furnished to do so, subject to
12
 * the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be
15
 * included in all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
 */
25
#include "nghttp2_hd.h"
26
27
#include <string.h>
28
#include <assert.h>
29
#include <stdio.h>
30
31
#include "nghttp2_helper.h"
32
#include "nghttp2_int.h"
33
#include "nghttp2_debug.h"
34
35
/* Make scalar initialization form of nghttp2_hd_entry */
36
#define MAKE_STATIC_ENT(N, V, T, H)                                            \
37
  {                                                                            \
38
    {NULL, NULL, (uint8_t *)(N), sizeof((N)) - 1, -1},                         \
39
        {NULL, NULL, (uint8_t *)(V), sizeof((V)) - 1, -1},                     \
40
        {(uint8_t *)(N), (uint8_t *)(V), sizeof((N)) - 1, sizeof((V)) - 1, 0}, \
41
        T, H                                                                   \
42
  }
43
44
/* Generated by mkstatictbl.py */
45
/* 3rd parameter is nghttp2_token value for header field name.  We use
46
   first enum value if same header names are repeated (e.g.,
47
   :status). */
48
static const nghttp2_hd_static_entry static_table[] = {
49
    MAKE_STATIC_ENT(":authority", "", 0, 3153725150u),
50
    MAKE_STATIC_ENT(":method", "GET", 1, 695666056u),
51
    MAKE_STATIC_ENT(":method", "POST", 1, 695666056u),
52
    MAKE_STATIC_ENT(":path", "/", 3, 3292848686u),
53
    MAKE_STATIC_ENT(":path", "/index.html", 3, 3292848686u),
54
    MAKE_STATIC_ENT(":scheme", "http", 5, 2510477674u),
55
    MAKE_STATIC_ENT(":scheme", "https", 5, 2510477674u),
56
    MAKE_STATIC_ENT(":status", "200", 7, 4000288983u),
57
    MAKE_STATIC_ENT(":status", "204", 7, 4000288983u),
58
    MAKE_STATIC_ENT(":status", "206", 7, 4000288983u),
59
    MAKE_STATIC_ENT(":status", "304", 7, 4000288983u),
60
    MAKE_STATIC_ENT(":status", "400", 7, 4000288983u),
61
    MAKE_STATIC_ENT(":status", "404", 7, 4000288983u),
62
    MAKE_STATIC_ENT(":status", "500", 7, 4000288983u),
63
    MAKE_STATIC_ENT("accept-charset", "", 14, 3664010344u),
64
    MAKE_STATIC_ENT("accept-encoding", "gzip, deflate", 15, 3379649177u),
65
    MAKE_STATIC_ENT("accept-language", "", 16, 1979086614u),
66
    MAKE_STATIC_ENT("accept-ranges", "", 17, 1713753958u),
67
    MAKE_STATIC_ENT("accept", "", 18, 136609321u),
68
    MAKE_STATIC_ENT("access-control-allow-origin", "", 19, 2710797292u),
69
    MAKE_STATIC_ENT("age", "", 20, 742476188u),
70
    MAKE_STATIC_ENT("allow", "", 21, 2930878514u),
71
    MAKE_STATIC_ENT("authorization", "", 22, 2436257726u),
72
    MAKE_STATIC_ENT("cache-control", "", 23, 1355326669u),
73
    MAKE_STATIC_ENT("content-disposition", "", 24, 3889184348u),
74
    MAKE_STATIC_ENT("content-encoding", "", 25, 65203592u),
75
    MAKE_STATIC_ENT("content-language", "", 26, 24973587u),
76
    MAKE_STATIC_ENT("content-length", "", 27, 1308181789u),
77
    MAKE_STATIC_ENT("content-location", "", 28, 2302364718u),
78
    MAKE_STATIC_ENT("content-range", "", 29, 3555523146u),
79
    MAKE_STATIC_ENT("content-type", "", 30, 4244048277u),
80
    MAKE_STATIC_ENT("cookie", "", 31, 2007449791u),
81
    MAKE_STATIC_ENT("date", "", 32, 3564297305u),
82
    MAKE_STATIC_ENT("etag", "", 33, 113792960u),
83
    MAKE_STATIC_ENT("expect", "", 34, 2530896728u),
84
    MAKE_STATIC_ENT("expires", "", 35, 1049544579u),
85
    MAKE_STATIC_ENT("from", "", 36, 2513272949u),
86
    MAKE_STATIC_ENT("host", "", 37, 2952701295u),
87
    MAKE_STATIC_ENT("if-match", "", 38, 3597694698u),
88
    MAKE_STATIC_ENT("if-modified-since", "", 39, 2213050793u),
89
    MAKE_STATIC_ENT("if-none-match", "", 40, 2536202615u),
90
    MAKE_STATIC_ENT("if-range", "", 41, 2340978238u),
91
    MAKE_STATIC_ENT("if-unmodified-since", "", 42, 3794814858u),
92
    MAKE_STATIC_ENT("last-modified", "", 43, 3226950251u),
93
    MAKE_STATIC_ENT("link", "", 44, 232457833u),
94
    MAKE_STATIC_ENT("location", "", 45, 200649126u),
95
    MAKE_STATIC_ENT("max-forwards", "", 46, 1826162134u),
96
    MAKE_STATIC_ENT("proxy-authenticate", "", 47, 2709445359u),
97
    MAKE_STATIC_ENT("proxy-authorization", "", 48, 2686392507u),
98
    MAKE_STATIC_ENT("range", "", 49, 4208725202u),
99
    MAKE_STATIC_ENT("referer", "", 50, 3969579366u),
100
    MAKE_STATIC_ENT("refresh", "", 51, 3572655668u),
101
    MAKE_STATIC_ENT("retry-after", "", 52, 3336180598u),
102
    MAKE_STATIC_ENT("server", "", 53, 1085029842u),
103
    MAKE_STATIC_ENT("set-cookie", "", 54, 1848371000u),
104
    MAKE_STATIC_ENT("strict-transport-security", "", 55, 4138147361u),
105
    MAKE_STATIC_ENT("transfer-encoding", "", 56, 3719590988u),
106
    MAKE_STATIC_ENT("user-agent", "", 57, 606444526u),
107
    MAKE_STATIC_ENT("vary", "", 58, 1085005381u),
108
    MAKE_STATIC_ENT("via", "", 59, 1762798611u),
109
    MAKE_STATIC_ENT("www-authenticate", "", 60, 779865858u),
110
};
111
112
0
static int memeq(const void *s1, const void *s2, size_t n) {
113
0
  return memcmp(s1, s2, n) == 0;
114
0
}
115
116
/*
117
 * This function was generated by genlibtokenlookup.py.  Inspired by
118
 * h2o header lookup.  https://github.com/h2o/h2o
119
 */
120
0
static int32_t lookup_token(const uint8_t *name, size_t namelen) {
121
0
  switch (namelen) {
122
0
  case 2:
123
0
    switch (name[1]) {
124
0
    case 'e':
125
0
      if (memeq("t", name, 1)) {
126
0
        return NGHTTP2_TOKEN_TE;
127
0
      }
128
0
      break;
129
0
    }
130
0
    break;
131
0
  case 3:
132
0
    switch (name[2]) {
133
0
    case 'a':
134
0
      if (memeq("vi", name, 2)) {
135
0
        return NGHTTP2_TOKEN_VIA;
136
0
      }
137
0
      break;
138
0
    case 'e':
139
0
      if (memeq("ag", name, 2)) {
140
0
        return NGHTTP2_TOKEN_AGE;
141
0
      }
142
0
      break;
143
0
    }
144
0
    break;
145
0
  case 4:
146
0
    switch (name[3]) {
147
0
    case 'e':
148
0
      if (memeq("dat", name, 3)) {
149
0
        return NGHTTP2_TOKEN_DATE;
150
0
      }
151
0
      break;
152
0
    case 'g':
153
0
      if (memeq("eta", name, 3)) {
154
0
        return NGHTTP2_TOKEN_ETAG;
155
0
      }
156
0
      break;
157
0
    case 'k':
158
0
      if (memeq("lin", name, 3)) {
159
0
        return NGHTTP2_TOKEN_LINK;
160
0
      }
161
0
      break;
162
0
    case 'm':
163
0
      if (memeq("fro", name, 3)) {
164
0
        return NGHTTP2_TOKEN_FROM;
165
0
      }
166
0
      break;
167
0
    case 't':
168
0
      if (memeq("hos", name, 3)) {
169
0
        return NGHTTP2_TOKEN_HOST;
170
0
      }
171
0
      break;
172
0
    case 'y':
173
0
      if (memeq("var", name, 3)) {
174
0
        return NGHTTP2_TOKEN_VARY;
175
0
      }
176
0
      break;
177
0
    }
178
0
    break;
179
0
  case 5:
180
0
    switch (name[4]) {
181
0
    case 'e':
182
0
      if (memeq("rang", name, 4)) {
183
0
        return NGHTTP2_TOKEN_RANGE;
184
0
      }
185
0
      break;
186
0
    case 'h':
187
0
      if (memeq(":pat", name, 4)) {
188
0
        return NGHTTP2_TOKEN__PATH;
189
0
      }
190
0
      break;
191
0
    case 'w':
192
0
      if (memeq("allo", name, 4)) {
193
0
        return NGHTTP2_TOKEN_ALLOW;
194
0
      }
195
0
      break;
196
0
    }
197
0
    break;
198
0
  case 6:
199
0
    switch (name[5]) {
200
0
    case 'e':
201
0
      if (memeq("cooki", name, 5)) {
202
0
        return NGHTTP2_TOKEN_COOKIE;
203
0
      }
204
0
      break;
205
0
    case 'r':
206
0
      if (memeq("serve", name, 5)) {
207
0
        return NGHTTP2_TOKEN_SERVER;
208
0
      }
209
0
      break;
210
0
    case 't':
211
0
      if (memeq("accep", name, 5)) {
212
0
        return NGHTTP2_TOKEN_ACCEPT;
213
0
      }
214
0
      if (memeq("expec", name, 5)) {
215
0
        return NGHTTP2_TOKEN_EXPECT;
216
0
      }
217
0
      break;
218
0
    }
219
0
    break;
220
0
  case 7:
221
0
    switch (name[6]) {
222
0
    case 'd':
223
0
      if (memeq(":metho", name, 6)) {
224
0
        return NGHTTP2_TOKEN__METHOD;
225
0
      }
226
0
      break;
227
0
    case 'e':
228
0
      if (memeq(":schem", name, 6)) {
229
0
        return NGHTTP2_TOKEN__SCHEME;
230
0
      }
231
0
      if (memeq("upgrad", name, 6)) {
232
0
        return NGHTTP2_TOKEN_UPGRADE;
233
0
      }
234
0
      break;
235
0
    case 'h':
236
0
      if (memeq("refres", name, 6)) {
237
0
        return NGHTTP2_TOKEN_REFRESH;
238
0
      }
239
0
      break;
240
0
    case 'r':
241
0
      if (memeq("refere", name, 6)) {
242
0
        return NGHTTP2_TOKEN_REFERER;
243
0
      }
244
0
      break;
245
0
    case 's':
246
0
      if (memeq(":statu", name, 6)) {
247
0
        return NGHTTP2_TOKEN__STATUS;
248
0
      }
249
0
      if (memeq("expire", name, 6)) {
250
0
        return NGHTTP2_TOKEN_EXPIRES;
251
0
      }
252
0
      break;
253
0
    }
254
0
    break;
255
0
  case 8:
256
0
    switch (name[7]) {
257
0
    case 'e':
258
0
      if (memeq("if-rang", name, 7)) {
259
0
        return NGHTTP2_TOKEN_IF_RANGE;
260
0
      }
261
0
      break;
262
0
    case 'h':
263
0
      if (memeq("if-matc", name, 7)) {
264
0
        return NGHTTP2_TOKEN_IF_MATCH;
265
0
      }
266
0
      break;
267
0
    case 'n':
268
0
      if (memeq("locatio", name, 7)) {
269
0
        return NGHTTP2_TOKEN_LOCATION;
270
0
      }
271
0
      break;
272
0
    case 'y':
273
0
      if (memeq("priorit", name, 7)) {
274
0
        return NGHTTP2_TOKEN_PRIORITY;
275
0
      }
276
0
      break;
277
0
    }
278
0
    break;
279
0
  case 9:
280
0
    switch (name[8]) {
281
0
    case 'l':
282
0
      if (memeq(":protoco", name, 8)) {
283
0
        return NGHTTP2_TOKEN__PROTOCOL;
284
0
      }
285
0
      break;
286
0
    }
287
0
    break;
288
0
  case 10:
289
0
    switch (name[9]) {
290
0
    case 'e':
291
0
      if (memeq("keep-aliv", name, 9)) {
292
0
        return NGHTTP2_TOKEN_KEEP_ALIVE;
293
0
      }
294
0
      if (memeq("set-cooki", name, 9)) {
295
0
        return NGHTTP2_TOKEN_SET_COOKIE;
296
0
      }
297
0
      break;
298
0
    case 'n':
299
0
      if (memeq("connectio", name, 9)) {
300
0
        return NGHTTP2_TOKEN_CONNECTION;
301
0
      }
302
0
      break;
303
0
    case 't':
304
0
      if (memeq("user-agen", name, 9)) {
305
0
        return NGHTTP2_TOKEN_USER_AGENT;
306
0
      }
307
0
      break;
308
0
    case 'y':
309
0
      if (memeq(":authorit", name, 9)) {
310
0
        return NGHTTP2_TOKEN__AUTHORITY;
311
0
      }
312
0
      break;
313
0
    }
314
0
    break;
315
0
  case 11:
316
0
    switch (name[10]) {
317
0
    case 'r':
318
0
      if (memeq("retry-afte", name, 10)) {
319
0
        return NGHTTP2_TOKEN_RETRY_AFTER;
320
0
      }
321
0
      break;
322
0
    }
323
0
    break;
324
0
  case 12:
325
0
    switch (name[11]) {
326
0
    case 'e':
327
0
      if (memeq("content-typ", name, 11)) {
328
0
        return NGHTTP2_TOKEN_CONTENT_TYPE;
329
0
      }
330
0
      break;
331
0
    case 's':
332
0
      if (memeq("max-forward", name, 11)) {
333
0
        return NGHTTP2_TOKEN_MAX_FORWARDS;
334
0
      }
335
0
      break;
336
0
    }
337
0
    break;
338
0
  case 13:
339
0
    switch (name[12]) {
340
0
    case 'd':
341
0
      if (memeq("last-modifie", name, 12)) {
342
0
        return NGHTTP2_TOKEN_LAST_MODIFIED;
343
0
      }
344
0
      break;
345
0
    case 'e':
346
0
      if (memeq("content-rang", name, 12)) {
347
0
        return NGHTTP2_TOKEN_CONTENT_RANGE;
348
0
      }
349
0
      break;
350
0
    case 'h':
351
0
      if (memeq("if-none-matc", name, 12)) {
352
0
        return NGHTTP2_TOKEN_IF_NONE_MATCH;
353
0
      }
354
0
      break;
355
0
    case 'l':
356
0
      if (memeq("cache-contro", name, 12)) {
357
0
        return NGHTTP2_TOKEN_CACHE_CONTROL;
358
0
      }
359
0
      break;
360
0
    case 'n':
361
0
      if (memeq("authorizatio", name, 12)) {
362
0
        return NGHTTP2_TOKEN_AUTHORIZATION;
363
0
      }
364
0
      break;
365
0
    case 's':
366
0
      if (memeq("accept-range", name, 12)) {
367
0
        return NGHTTP2_TOKEN_ACCEPT_RANGES;
368
0
      }
369
0
      break;
370
0
    }
371
0
    break;
372
0
  case 14:
373
0
    switch (name[13]) {
374
0
    case 'h':
375
0
      if (memeq("content-lengt", name, 13)) {
376
0
        return NGHTTP2_TOKEN_CONTENT_LENGTH;
377
0
      }
378
0
      break;
379
0
    case 't':
380
0
      if (memeq("accept-charse", name, 13)) {
381
0
        return NGHTTP2_TOKEN_ACCEPT_CHARSET;
382
0
      }
383
0
      break;
384
0
    }
385
0
    break;
386
0
  case 15:
387
0
    switch (name[14]) {
388
0
    case 'e':
389
0
      if (memeq("accept-languag", name, 14)) {
390
0
        return NGHTTP2_TOKEN_ACCEPT_LANGUAGE;
391
0
      }
392
0
      break;
393
0
    case 'g':
394
0
      if (memeq("accept-encodin", name, 14)) {
395
0
        return NGHTTP2_TOKEN_ACCEPT_ENCODING;
396
0
      }
397
0
      break;
398
0
    }
399
0
    break;
400
0
  case 16:
401
0
    switch (name[15]) {
402
0
    case 'e':
403
0
      if (memeq("content-languag", name, 15)) {
404
0
        return NGHTTP2_TOKEN_CONTENT_LANGUAGE;
405
0
      }
406
0
      if (memeq("www-authenticat", name, 15)) {
407
0
        return NGHTTP2_TOKEN_WWW_AUTHENTICATE;
408
0
      }
409
0
      break;
410
0
    case 'g':
411
0
      if (memeq("content-encodin", name, 15)) {
412
0
        return NGHTTP2_TOKEN_CONTENT_ENCODING;
413
0
      }
414
0
      break;
415
0
    case 'n':
416
0
      if (memeq("content-locatio", name, 15)) {
417
0
        return NGHTTP2_TOKEN_CONTENT_LOCATION;
418
0
      }
419
0
      if (memeq("proxy-connectio", name, 15)) {
420
0
        return NGHTTP2_TOKEN_PROXY_CONNECTION;
421
0
      }
422
0
      break;
423
0
    }
424
0
    break;
425
0
  case 17:
426
0
    switch (name[16]) {
427
0
    case 'e':
428
0
      if (memeq("if-modified-sinc", name, 16)) {
429
0
        return NGHTTP2_TOKEN_IF_MODIFIED_SINCE;
430
0
      }
431
0
      break;
432
0
    case 'g':
433
0
      if (memeq("transfer-encodin", name, 16)) {
434
0
        return NGHTTP2_TOKEN_TRANSFER_ENCODING;
435
0
      }
436
0
      break;
437
0
    }
438
0
    break;
439
0
  case 18:
440
0
    switch (name[17]) {
441
0
    case 'e':
442
0
      if (memeq("proxy-authenticat", name, 17)) {
443
0
        return NGHTTP2_TOKEN_PROXY_AUTHENTICATE;
444
0
      }
445
0
      break;
446
0
    }
447
0
    break;
448
0
  case 19:
449
0
    switch (name[18]) {
450
0
    case 'e':
451
0
      if (memeq("if-unmodified-sinc", name, 18)) {
452
0
        return NGHTTP2_TOKEN_IF_UNMODIFIED_SINCE;
453
0
      }
454
0
      break;
455
0
    case 'n':
456
0
      if (memeq("content-dispositio", name, 18)) {
457
0
        return NGHTTP2_TOKEN_CONTENT_DISPOSITION;
458
0
      }
459
0
      if (memeq("proxy-authorizatio", name, 18)) {
460
0
        return NGHTTP2_TOKEN_PROXY_AUTHORIZATION;
461
0
      }
462
0
      break;
463
0
    }
464
0
    break;
465
0
  case 25:
466
0
    switch (name[24]) {
467
0
    case 'y':
468
0
      if (memeq("strict-transport-securit", name, 24)) {
469
0
        return NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY;
470
0
      }
471
0
      break;
472
0
    }
473
0
    break;
474
0
  case 27:
475
0
    switch (name[26]) {
476
0
    case 'n':
477
0
      if (memeq("access-control-allow-origi", name, 26)) {
478
0
        return NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN;
479
0
      }
480
0
      break;
481
0
    }
482
0
    break;
483
0
  }
484
0
  return -1;
485
0
}
486
487
0
void nghttp2_hd_entry_init(nghttp2_hd_entry *ent, nghttp2_hd_nv *nv) {
488
0
  ent->nv = *nv;
489
0
  ent->cnv.name = nv->name->base;
490
0
  ent->cnv.namelen = nv->name->len;
491
0
  ent->cnv.value = nv->value->base;
492
0
  ent->cnv.valuelen = nv->value->len;
493
0
  ent->cnv.flags = nv->flags;
494
0
  ent->next = NULL;
495
0
  ent->hash = 0;
496
497
0
  nghttp2_rcbuf_incref(ent->nv.name);
498
0
  nghttp2_rcbuf_incref(ent->nv.value);
499
0
}
500
501
0
void nghttp2_hd_entry_free(nghttp2_hd_entry *ent) {
502
0
  nghttp2_rcbuf_decref(ent->nv.value);
503
0
  nghttp2_rcbuf_decref(ent->nv.name);
504
0
}
505
506
0
static int name_eq(const nghttp2_hd_nv *a, const nghttp2_nv *b) {
507
0
  return a->name->len == b->namelen &&
508
0
         memeq(a->name->base, b->name, b->namelen);
509
0
}
510
511
0
static int value_eq(const nghttp2_hd_nv *a, const nghttp2_nv *b) {
512
0
  return a->value->len == b->valuelen &&
513
0
         memeq(a->value->base, b->value, b->valuelen);
514
0
}
515
516
0
static uint32_t name_hash(const nghttp2_nv *nv) {
517
  /* 32 bit FNV-1a: http://isthe.com/chongo/tech/comp/fnv/ */
518
0
  uint32_t h = 2166136261u;
519
0
  size_t i;
520
521
0
  for (i = 0; i < nv->namelen; ++i) {
522
0
    h ^= nv->name[i];
523
0
    h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24);
524
0
  }
525
526
0
  return h;
527
0
}
528
529
0
static void hd_map_init(nghttp2_hd_map *map) {
530
0
  memset(map, 0, sizeof(nghttp2_hd_map));
531
0
}
532
533
0
static void hd_map_insert(nghttp2_hd_map *map, nghttp2_hd_entry *ent) {
534
0
  nghttp2_hd_entry **bucket;
535
536
0
  bucket = &map->table[ent->hash & (HD_MAP_SIZE - 1)];
537
538
0
  if (*bucket == NULL) {
539
0
    *bucket = ent;
540
0
    return;
541
0
  }
542
543
  /* lower index is linked near the root */
544
0
  ent->next = *bucket;
545
0
  *bucket = ent;
546
0
}
547
548
static nghttp2_hd_entry *hd_map_find(nghttp2_hd_map *map, int *exact_match,
549
                                     const nghttp2_nv *nv, int32_t token,
550
0
                                     uint32_t hash, int name_only) {
551
0
  nghttp2_hd_entry *p;
552
0
  nghttp2_hd_entry *res = NULL;
553
554
0
  *exact_match = 0;
555
556
0
  for (p = map->table[hash & (HD_MAP_SIZE - 1)]; p; p = p->next) {
557
0
    if (token != p->nv.token ||
558
0
        (token == -1 && (hash != p->hash || !name_eq(&p->nv, nv)))) {
559
0
      continue;
560
0
    }
561
0
    if (!res) {
562
0
      res = p;
563
0
      if (name_only) {
564
0
        break;
565
0
      }
566
0
    }
567
0
    if (value_eq(&p->nv, nv)) {
568
0
      res = p;
569
0
      *exact_match = 1;
570
0
      break;
571
0
    }
572
0
  }
573
574
0
  return res;
575
0
}
576
577
0
static void hd_map_remove(nghttp2_hd_map *map, nghttp2_hd_entry *ent) {
578
0
  nghttp2_hd_entry **dst;
579
580
0
  dst = &map->table[ent->hash & (HD_MAP_SIZE - 1)];
581
582
0
  for (; *dst; dst = &(*dst)->next) {
583
0
    if (*dst != ent) {
584
0
      continue;
585
0
    }
586
587
0
    *dst = ent->next;
588
0
    ent->next = NULL;
589
0
    return;
590
0
  }
591
0
}
592
593
static int hd_ringbuf_init(nghttp2_hd_ringbuf *ringbuf, size_t bufsize,
594
0
                           nghttp2_mem *mem) {
595
0
  size_t size;
596
0
  for (size = 1; size < bufsize; size <<= 1)
597
0
    ;
598
0
  ringbuf->buffer = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_entry *) * size);
599
0
  if (ringbuf->buffer == NULL) {
600
0
    return NGHTTP2_ERR_NOMEM;
601
0
  }
602
0
  ringbuf->mask = size - 1;
603
0
  ringbuf->first = 0;
604
0
  ringbuf->len = 0;
605
0
  return 0;
606
0
}
607
608
static nghttp2_hd_entry *hd_ringbuf_get(nghttp2_hd_ringbuf *ringbuf,
609
0
                                        size_t idx) {
610
0
  assert(idx < ringbuf->len);
611
0
  return ringbuf->buffer[(ringbuf->first + idx) & ringbuf->mask];
612
0
}
613
614
static int hd_ringbuf_reserve(nghttp2_hd_ringbuf *ringbuf, size_t bufsize,
615
0
                              nghttp2_mem *mem) {
616
0
  size_t i;
617
0
  size_t size;
618
0
  nghttp2_hd_entry **buffer;
619
620
0
  if (ringbuf->mask + 1 >= bufsize) {
621
0
    return 0;
622
0
  }
623
0
  for (size = 1; size < bufsize; size <<= 1)
624
0
    ;
625
0
  buffer = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_entry *) * size);
626
0
  if (buffer == NULL) {
627
0
    return NGHTTP2_ERR_NOMEM;
628
0
  }
629
0
  for (i = 0; i < ringbuf->len; ++i) {
630
0
    buffer[i] = hd_ringbuf_get(ringbuf, i);
631
0
  }
632
0
  nghttp2_mem_free(mem, ringbuf->buffer);
633
0
  ringbuf->buffer = buffer;
634
0
  ringbuf->mask = size - 1;
635
0
  ringbuf->first = 0;
636
0
  return 0;
637
0
}
638
639
0
static void hd_ringbuf_free(nghttp2_hd_ringbuf *ringbuf, nghttp2_mem *mem) {
640
0
  size_t i;
641
0
  if (ringbuf == NULL) {
642
0
    return;
643
0
  }
644
0
  for (i = 0; i < ringbuf->len; ++i) {
645
0
    nghttp2_hd_entry *ent = hd_ringbuf_get(ringbuf, i);
646
647
0
    nghttp2_hd_entry_free(ent);
648
0
    nghttp2_mem_free(mem, ent);
649
0
  }
650
0
  nghttp2_mem_free(mem, ringbuf->buffer);
651
0
}
652
653
static int hd_ringbuf_push_front(nghttp2_hd_ringbuf *ringbuf,
654
0
                                 nghttp2_hd_entry *ent, nghttp2_mem *mem) {
655
0
  int rv;
656
657
0
  rv = hd_ringbuf_reserve(ringbuf, ringbuf->len + 1, mem);
658
659
0
  if (rv != 0) {
660
0
    return rv;
661
0
  }
662
663
0
  ringbuf->buffer[--ringbuf->first & ringbuf->mask] = ent;
664
0
  ++ringbuf->len;
665
666
0
  return 0;
667
0
}
668
669
0
static void hd_ringbuf_pop_back(nghttp2_hd_ringbuf *ringbuf) {
670
0
  assert(ringbuf->len > 0);
671
0
  --ringbuf->len;
672
0
}
673
674
0
static int hd_context_init(nghttp2_hd_context *context, nghttp2_mem *mem) {
675
0
  int rv;
676
0
  context->mem = mem;
677
0
  context->bad = 0;
678
0
  context->hd_table_bufsize_max = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
679
0
  rv = hd_ringbuf_init(
680
0
      &context->hd_table,
681
0
      context->hd_table_bufsize_max / NGHTTP2_HD_ENTRY_OVERHEAD, mem);
682
0
  if (rv != 0) {
683
0
    return rv;
684
0
  }
685
686
0
  context->hd_table_bufsize = 0;
687
0
  context->next_seq = 0;
688
689
0
  return 0;
690
0
}
691
692
0
static void hd_context_free(nghttp2_hd_context *context) {
693
0
  hd_ringbuf_free(&context->hd_table, context->mem);
694
0
}
695
696
0
int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_mem *mem) {
697
0
  return nghttp2_hd_deflate_init2(
698
0
      deflater, NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE, mem);
699
0
}
700
701
int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater,
702
                             size_t max_deflate_dynamic_table_size,
703
0
                             nghttp2_mem *mem) {
704
0
  int rv;
705
0
  rv = hd_context_init(&deflater->ctx, mem);
706
0
  if (rv != 0) {
707
0
    return rv;
708
0
  }
709
710
0
  hd_map_init(&deflater->map);
711
712
0
  if (max_deflate_dynamic_table_size < NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE) {
713
0
    deflater->notify_table_size_change = 1;
714
0
    deflater->ctx.hd_table_bufsize_max = max_deflate_dynamic_table_size;
715
0
  } else {
716
0
    deflater->notify_table_size_change = 0;
717
0
  }
718
719
0
  deflater->deflate_hd_table_bufsize_max = max_deflate_dynamic_table_size;
720
0
  deflater->min_hd_table_bufsize_max = UINT32_MAX;
721
722
0
  return 0;
723
0
}
724
725
0
int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem) {
726
0
  int rv;
727
728
0
  rv = hd_context_init(&inflater->ctx, mem);
729
0
  if (rv != 0) {
730
0
    goto fail;
731
0
  }
732
733
0
  inflater->settings_hd_table_bufsize_max = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
734
0
  inflater->min_hd_table_bufsize_max = UINT32_MAX;
735
736
0
  inflater->nv_name_keep = NULL;
737
0
  inflater->nv_value_keep = NULL;
738
739
0
  inflater->opcode = NGHTTP2_HD_OPCODE_NONE;
740
0
  inflater->state = NGHTTP2_HD_STATE_INFLATE_START;
741
742
0
  nghttp2_buf_init(&inflater->namebuf);
743
0
  nghttp2_buf_init(&inflater->valuebuf);
744
745
0
  inflater->namercbuf = NULL;
746
0
  inflater->valuercbuf = NULL;
747
748
0
  inflater->huffman_encoded = 0;
749
0
  inflater->index = 0;
750
0
  inflater->left = 0;
751
0
  inflater->shift = 0;
752
0
  inflater->index_required = 0;
753
0
  inflater->no_index = 0;
754
755
0
  return 0;
756
757
0
fail:
758
0
  return rv;
759
0
}
760
761
0
static void hd_inflate_keep_free(nghttp2_hd_inflater *inflater) {
762
0
  nghttp2_rcbuf_decref(inflater->nv_value_keep);
763
0
  nghttp2_rcbuf_decref(inflater->nv_name_keep);
764
765
0
  inflater->nv_value_keep = NULL;
766
0
  inflater->nv_name_keep = NULL;
767
0
}
768
769
0
void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater) {
770
0
  hd_context_free(&deflater->ctx);
771
0
}
772
773
0
void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater) {
774
0
  hd_inflate_keep_free(inflater);
775
776
0
  nghttp2_rcbuf_decref(inflater->valuercbuf);
777
0
  nghttp2_rcbuf_decref(inflater->namercbuf);
778
779
0
  hd_context_free(&inflater->ctx);
780
0
}
781
782
0
static size_t entry_room(size_t namelen, size_t valuelen) {
783
0
  return NGHTTP2_HD_ENTRY_OVERHEAD + namelen + valuelen;
784
0
}
785
786
0
static void emit_header(nghttp2_hd_nv *nv_out, nghttp2_hd_nv *nv) {
787
0
  DEBUGF("inflatehd: header emission: %s: %s\n", nv->name->base,
788
0
         nv->value->base);
789
  /* ent->ref may be 0. This happens if the encoder emits literal
790
     block larger than header table capacity with indexing. */
791
0
  *nv_out = *nv;
792
0
}
793
794
0
static size_t count_encoded_length(size_t n, size_t prefix) {
795
0
  size_t k = (size_t)((1 << prefix) - 1);
796
0
  size_t len = 0;
797
798
0
  if (n < k) {
799
0
    return 1;
800
0
  }
801
802
0
  n -= k;
803
0
  ++len;
804
805
0
  for (; n >= 128; n >>= 7, ++len)
806
0
    ;
807
808
0
  return len + 1;
809
0
}
810
811
0
static size_t encode_length(uint8_t *buf, size_t n, size_t prefix) {
812
0
  size_t k = (size_t)((1 << prefix) - 1);
813
0
  uint8_t *begin = buf;
814
815
0
  *buf = (uint8_t)(*buf & ~k);
816
817
0
  if (n < k) {
818
0
    *buf = (uint8_t)(*buf | n);
819
0
    return 1;
820
0
  }
821
822
0
  *buf = (uint8_t)(*buf | k);
823
0
  ++buf;
824
825
0
  n -= k;
826
827
0
  for (; n >= 128; n >>= 7) {
828
0
    *buf++ = (uint8_t)((1 << 7) | (n & 0x7f));
829
0
  }
830
831
0
  *buf++ = (uint8_t)n;
832
833
0
  return (size_t)(buf - begin);
834
0
}
835
836
/*
837
 * Decodes |prefix| prefixed integer stored from |in|.  The |last|
838
 * represents the 1 beyond the last of the valid contiguous memory
839
 * region from |in|.  The decoded integer must be less than or equal
840
 * to UINT32_MAX.
841
 *
842
 * If the |initial| is nonzero, it is used as a initial value, this
843
 * function assumes the |in| starts with intermediate data.
844
 *
845
 * An entire integer is decoded successfully, decoded, the |*fin| is
846
 * set to nonzero.
847
 *
848
 * This function stores the decoded integer in |*res| if it succeed,
849
 * including partial decoding (in this case, number of shift to make
850
 * in the next call will be stored in |*shift_ptr|) and returns number
851
 * of bytes processed, or returns -1, indicating decoding error.
852
 */
853
static ssize_t decode_length(uint32_t *res, size_t *shift_ptr, int *fin,
854
                             uint32_t initial, size_t shift, const uint8_t *in,
855
0
                             const uint8_t *last, size_t prefix) {
856
0
  uint32_t k = (uint8_t)((1 << prefix) - 1);
857
0
  uint32_t n = initial;
858
0
  const uint8_t *start = in;
859
860
0
  *shift_ptr = 0;
861
0
  *fin = 0;
862
863
0
  if (n == 0) {
864
0
    if ((*in & k) != k) {
865
0
      *res = (*in) & k;
866
0
      *fin = 1;
867
0
      return 1;
868
0
    }
869
870
0
    n = k;
871
872
0
    if (++in == last) {
873
0
      *res = n;
874
0
      return (ssize_t)(in - start);
875
0
    }
876
0
  }
877
878
0
  for (; in != last; ++in, shift += 7) {
879
0
    uint32_t add = *in & 0x7f;
880
881
0
    if (shift >= 32) {
882
0
      DEBUGF("inflate: shift exponent overflow\n");
883
0
      return -1;
884
0
    }
885
886
0
    if ((UINT32_MAX >> shift) < add) {
887
0
      DEBUGF("inflate: integer overflow on shift\n");
888
0
      return -1;
889
0
    }
890
891
0
    add <<= shift;
892
893
0
    if (UINT32_MAX - add < n) {
894
0
      DEBUGF("inflate: integer overflow on addition\n");
895
0
      return -1;
896
0
    }
897
898
0
    n += add;
899
900
0
    if ((*in & (1 << 7)) == 0) {
901
0
      break;
902
0
    }
903
0
  }
904
905
0
  *shift_ptr = shift;
906
907
0
  if (in == last) {
908
0
    *res = n;
909
0
    return (ssize_t)(in - start);
910
0
  }
911
912
0
  *res = n;
913
0
  *fin = 1;
914
0
  return (ssize_t)(in + 1 - start);
915
0
}
916
917
0
static int emit_table_size(nghttp2_bufs *bufs, size_t table_size) {
918
0
  int rv;
919
0
  uint8_t *bufp;
920
0
  size_t blocklen;
921
0
  uint8_t sb[16];
922
923
0
  DEBUGF("deflatehd: emit table_size=%zu\n", table_size);
924
925
0
  blocklen = count_encoded_length(table_size, 5);
926
927
0
  if (sizeof(sb) < blocklen) {
928
0
    return NGHTTP2_ERR_HEADER_COMP;
929
0
  }
930
931
0
  bufp = sb;
932
933
0
  *bufp = 0x20u;
934
935
0
  encode_length(bufp, table_size, 5);
936
937
0
  rv = nghttp2_bufs_add(bufs, sb, blocklen);
938
0
  if (rv != 0) {
939
0
    return rv;
940
0
  }
941
942
0
  return 0;
943
0
}
944
945
0
static int emit_indexed_block(nghttp2_bufs *bufs, size_t idx) {
946
0
  int rv;
947
0
  size_t blocklen;
948
0
  uint8_t sb[16];
949
0
  uint8_t *bufp;
950
951
0
  blocklen = count_encoded_length(idx + 1, 7);
952
953
0
  DEBUGF("deflatehd: emit indexed index=%zu, %zu bytes\n", idx, blocklen);
954
955
0
  if (sizeof(sb) < blocklen) {
956
0
    return NGHTTP2_ERR_HEADER_COMP;
957
0
  }
958
959
0
  bufp = sb;
960
0
  *bufp = 0x80u;
961
0
  encode_length(bufp, idx + 1, 7);
962
963
0
  rv = nghttp2_bufs_add(bufs, sb, blocklen);
964
0
  if (rv != 0) {
965
0
    return rv;
966
0
  }
967
968
0
  return 0;
969
0
}
970
971
0
static int emit_string(nghttp2_bufs *bufs, const uint8_t *str, size_t len) {
972
0
  int rv;
973
0
  uint8_t sb[16];
974
0
  uint8_t *bufp;
975
0
  size_t blocklen;
976
0
  size_t enclen;
977
0
  int huffman = 0;
978
979
0
  enclen = nghttp2_hd_huff_encode_count(str, len);
980
981
0
  if (enclen < len) {
982
0
    huffman = 1;
983
0
  } else {
984
0
    enclen = len;
985
0
  }
986
987
0
  blocklen = count_encoded_length(enclen, 7);
988
989
0
  DEBUGF("deflatehd: emit string str=%.*s, length=%zu, huffman=%d, "
990
0
         "encoded_length=%zu\n",
991
0
         (int)len, (const char *)str, len, huffman, enclen);
992
993
0
  if (sizeof(sb) < blocklen) {
994
0
    return NGHTTP2_ERR_HEADER_COMP;
995
0
  }
996
997
0
  bufp = sb;
998
0
  *bufp = huffman ? 1 << 7 : 0;
999
0
  encode_length(bufp, enclen, 7);
1000
1001
0
  rv = nghttp2_bufs_add(bufs, sb, blocklen);
1002
0
  if (rv != 0) {
1003
0
    return rv;
1004
0
  }
1005
1006
0
  if (huffman) {
1007
0
    rv = nghttp2_hd_huff_encode(bufs, str, len);
1008
0
  } else {
1009
0
    assert(enclen == len);
1010
0
    rv = nghttp2_bufs_add(bufs, str, len);
1011
0
  }
1012
1013
0
  return rv;
1014
0
}
1015
1016
0
static uint8_t pack_first_byte(int indexing_mode) {
1017
0
  switch (indexing_mode) {
1018
0
  case NGHTTP2_HD_WITH_INDEXING:
1019
0
    return 0x40u;
1020
0
  case NGHTTP2_HD_WITHOUT_INDEXING:
1021
0
    return 0;
1022
0
  case NGHTTP2_HD_NEVER_INDEXING:
1023
0
    return 0x10u;
1024
0
  default:
1025
0
    assert(0);
1026
0
  }
1027
  /* This is required to compile with android NDK r10d +
1028
     --enable-werror */
1029
0
  return 0;
1030
0
}
1031
1032
static int emit_indname_block(nghttp2_bufs *bufs, size_t idx,
1033
0
                              const nghttp2_nv *nv, int indexing_mode) {
1034
0
  int rv;
1035
0
  uint8_t *bufp;
1036
0
  size_t blocklen;
1037
0
  uint8_t sb[16];
1038
0
  size_t prefixlen;
1039
1040
0
  if (indexing_mode == NGHTTP2_HD_WITH_INDEXING) {
1041
0
    prefixlen = 6;
1042
0
  } else {
1043
0
    prefixlen = 4;
1044
0
  }
1045
1046
0
  DEBUGF("deflatehd: emit indname index=%zu, valuelen=%zu, indexing_mode=%d\n",
1047
0
         idx, nv->valuelen, indexing_mode);
1048
1049
0
  blocklen = count_encoded_length(idx + 1, prefixlen);
1050
1051
0
  if (sizeof(sb) < blocklen) {
1052
0
    return NGHTTP2_ERR_HEADER_COMP;
1053
0
  }
1054
1055
0
  bufp = sb;
1056
1057
0
  *bufp = pack_first_byte(indexing_mode);
1058
1059
0
  encode_length(bufp, idx + 1, prefixlen);
1060
1061
0
  rv = nghttp2_bufs_add(bufs, sb, blocklen);
1062
0
  if (rv != 0) {
1063
0
    return rv;
1064
0
  }
1065
1066
0
  rv = emit_string(bufs, nv->value, nv->valuelen);
1067
0
  if (rv != 0) {
1068
0
    return rv;
1069
0
  }
1070
1071
0
  return 0;
1072
0
}
1073
1074
static int emit_newname_block(nghttp2_bufs *bufs, const nghttp2_nv *nv,
1075
0
                              int indexing_mode) {
1076
0
  int rv;
1077
1078
0
  DEBUGF(
1079
0
      "deflatehd: emit newname namelen=%zu, valuelen=%zu, indexing_mode=%d\n",
1080
0
      nv->namelen, nv->valuelen, indexing_mode);
1081
1082
0
  rv = nghttp2_bufs_addb(bufs, pack_first_byte(indexing_mode));
1083
0
  if (rv != 0) {
1084
0
    return rv;
1085
0
  }
1086
1087
0
  rv = emit_string(bufs, nv->name, nv->namelen);
1088
0
  if (rv != 0) {
1089
0
    return rv;
1090
0
  }
1091
1092
0
  rv = emit_string(bufs, nv->value, nv->valuelen);
1093
0
  if (rv != 0) {
1094
0
    return rv;
1095
0
  }
1096
1097
0
  return 0;
1098
0
}
1099
1100
static int add_hd_table_incremental(nghttp2_hd_context *context,
1101
                                    nghttp2_hd_nv *nv, nghttp2_hd_map *map,
1102
0
                                    uint32_t hash) {
1103
0
  int rv;
1104
0
  nghttp2_hd_entry *new_ent;
1105
0
  size_t room;
1106
0
  nghttp2_mem *mem;
1107
1108
0
  mem = context->mem;
1109
0
  room = entry_room(nv->name->len, nv->value->len);
1110
1111
0
  while (context->hd_table_bufsize + room > context->hd_table_bufsize_max &&
1112
0
         context->hd_table.len > 0) {
1113
1114
0
    size_t idx = context->hd_table.len - 1;
1115
0
    nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, idx);
1116
1117
0
    context->hd_table_bufsize -=
1118
0
        entry_room(ent->nv.name->len, ent->nv.value->len);
1119
1120
0
    DEBUGF("hpack: remove item from header table: %s: %s\n",
1121
0
           (char *)ent->nv.name->base, (char *)ent->nv.value->base);
1122
1123
0
    hd_ringbuf_pop_back(&context->hd_table);
1124
0
    if (map) {
1125
0
      hd_map_remove(map, ent);
1126
0
    }
1127
1128
0
    nghttp2_hd_entry_free(ent);
1129
0
    nghttp2_mem_free(mem, ent);
1130
0
  }
1131
1132
0
  if (room > context->hd_table_bufsize_max) {
1133
    /* The entry taking more than NGHTTP2_HD_MAX_BUFFER_SIZE is
1134
       immediately evicted.  So we don't allocate memory for it. */
1135
0
    return 0;
1136
0
  }
1137
1138
0
  new_ent = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_entry));
1139
0
  if (new_ent == NULL) {
1140
0
    return NGHTTP2_ERR_NOMEM;
1141
0
  }
1142
1143
0
  nghttp2_hd_entry_init(new_ent, nv);
1144
1145
0
  rv = hd_ringbuf_push_front(&context->hd_table, new_ent, mem);
1146
1147
0
  if (rv != 0) {
1148
0
    nghttp2_hd_entry_free(new_ent);
1149
0
    nghttp2_mem_free(mem, new_ent);
1150
1151
0
    return rv;
1152
0
  }
1153
1154
0
  new_ent->seq = context->next_seq++;
1155
0
  new_ent->hash = hash;
1156
1157
0
  if (map) {
1158
0
    hd_map_insert(map, new_ent);
1159
0
  }
1160
1161
0
  context->hd_table_bufsize += room;
1162
1163
0
  return 0;
1164
0
}
1165
1166
typedef struct {
1167
  ssize_t index;
1168
  /* Nonzero if both name and value are matched. */
1169
  int name_value_match;
1170
} search_result;
1171
1172
static search_result search_static_table(const nghttp2_nv *nv, int32_t token,
1173
0
                                         int name_only) {
1174
0
  search_result res = {token, 0};
1175
0
  int i;
1176
0
  const nghttp2_hd_static_entry *ent;
1177
1178
0
  if (name_only) {
1179
0
    return res;
1180
0
  }
1181
1182
0
  for (i = token;
1183
0
       i <= NGHTTP2_TOKEN_WWW_AUTHENTICATE && static_table[i].token == token;
1184
0
       ++i) {
1185
0
    ent = &static_table[i];
1186
0
    if (ent->value.len == nv->valuelen &&
1187
0
        memcmp(ent->value.base, nv->value, nv->valuelen) == 0) {
1188
0
      res.index = i;
1189
0
      res.name_value_match = 1;
1190
0
      return res;
1191
0
    }
1192
0
  }
1193
0
  return res;
1194
0
}
1195
1196
static search_result search_hd_table(nghttp2_hd_context *context,
1197
                                     const nghttp2_nv *nv, int32_t token,
1198
                                     int indexing_mode, nghttp2_hd_map *map,
1199
0
                                     uint32_t hash) {
1200
0
  search_result res = {-1, 0};
1201
0
  const nghttp2_hd_entry *ent;
1202
0
  int exact_match;
1203
0
  int name_only = indexing_mode == NGHTTP2_HD_NEVER_INDEXING;
1204
1205
0
  exact_match = 0;
1206
0
  ent = hd_map_find(map, &exact_match, nv, token, hash, name_only);
1207
1208
0
  if (!exact_match && token >= 0 && token <= NGHTTP2_TOKEN_WWW_AUTHENTICATE) {
1209
0
    return search_static_table(nv, token, name_only);
1210
0
  }
1211
1212
0
  if (ent == NULL) {
1213
0
    return res;
1214
0
  }
1215
1216
0
  res.index =
1217
0
      (ssize_t)(context->next_seq - 1 - ent->seq + NGHTTP2_STATIC_TABLE_LENGTH);
1218
0
  res.name_value_match = exact_match;
1219
1220
0
  return res;
1221
0
}
1222
1223
static void hd_context_shrink_table_size(nghttp2_hd_context *context,
1224
0
                                         nghttp2_hd_map *map) {
1225
0
  nghttp2_mem *mem;
1226
1227
0
  mem = context->mem;
1228
1229
0
  while (context->hd_table_bufsize > context->hd_table_bufsize_max &&
1230
0
         context->hd_table.len > 0) {
1231
0
    size_t idx = context->hd_table.len - 1;
1232
0
    nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, idx);
1233
0
    context->hd_table_bufsize -=
1234
0
        entry_room(ent->nv.name->len, ent->nv.value->len);
1235
0
    hd_ringbuf_pop_back(&context->hd_table);
1236
0
    if (map) {
1237
0
      hd_map_remove(map, ent);
1238
0
    }
1239
1240
0
    nghttp2_hd_entry_free(ent);
1241
0
    nghttp2_mem_free(mem, ent);
1242
0
  }
1243
0
}
1244
1245
int nghttp2_hd_deflate_change_table_size(
1246
0
    nghttp2_hd_deflater *deflater, size_t settings_max_dynamic_table_size) {
1247
0
  size_t next_bufsize = nghttp2_min(settings_max_dynamic_table_size,
1248
0
                                    deflater->deflate_hd_table_bufsize_max);
1249
1250
0
  deflater->ctx.hd_table_bufsize_max = next_bufsize;
1251
1252
0
  deflater->min_hd_table_bufsize_max =
1253
0
      nghttp2_min(deflater->min_hd_table_bufsize_max, next_bufsize);
1254
1255
0
  deflater->notify_table_size_change = 1;
1256
1257
0
  hd_context_shrink_table_size(&deflater->ctx, &deflater->map);
1258
0
  return 0;
1259
0
}
1260
1261
int nghttp2_hd_inflate_change_table_size(
1262
0
    nghttp2_hd_inflater *inflater, size_t settings_max_dynamic_table_size) {
1263
0
  switch (inflater->state) {
1264
0
  case NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE:
1265
0
  case NGHTTP2_HD_STATE_INFLATE_START:
1266
0
    break;
1267
0
  default:
1268
0
    return NGHTTP2_ERR_INVALID_STATE;
1269
0
  }
1270
1271
0
  inflater->settings_hd_table_bufsize_max = settings_max_dynamic_table_size;
1272
1273
  /* It seems that encoder is not required to send dynamic table size
1274
     update if the table size is not changed after applying
1275
     SETTINGS_HEADER_TABLE_SIZE.  RFC 7541 is ambiguous here, but this
1276
     is the intention of the editor.  If new maximum table size is
1277
     strictly smaller than the current negotiated maximum size,
1278
     encoder must send dynamic table size update.  In other cases, we
1279
     cannot expect it to do so. */
1280
0
  if (inflater->ctx.hd_table_bufsize_max > settings_max_dynamic_table_size) {
1281
0
    inflater->state = NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE;
1282
    /* Remember minimum value, and validate that encoder sends the
1283
       value less than or equal to this. */
1284
0
    inflater->min_hd_table_bufsize_max = settings_max_dynamic_table_size;
1285
1286
0
    inflater->ctx.hd_table_bufsize_max = settings_max_dynamic_table_size;
1287
1288
0
    hd_context_shrink_table_size(&inflater->ctx, NULL);
1289
0
  }
1290
1291
0
  return 0;
1292
0
}
1293
1294
#define INDEX_RANGE_VALID(context, idx)                                        \
1295
0
  ((idx) < (context)->hd_table.len + NGHTTP2_STATIC_TABLE_LENGTH)
1296
1297
0
static size_t get_max_index(nghttp2_hd_context *context) {
1298
0
  return context->hd_table.len + NGHTTP2_STATIC_TABLE_LENGTH;
1299
0
}
1300
1301
0
nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t idx) {
1302
0
  assert(INDEX_RANGE_VALID(context, idx));
1303
0
  if (idx >= NGHTTP2_STATIC_TABLE_LENGTH) {
1304
0
    return hd_ringbuf_get(&context->hd_table, idx - NGHTTP2_STATIC_TABLE_LENGTH)
1305
0
        ->nv;
1306
0
  } else {
1307
0
    const nghttp2_hd_static_entry *ent = &static_table[idx];
1308
0
    nghttp2_hd_nv nv = {(nghttp2_rcbuf *)&ent->name,
1309
0
                        (nghttp2_rcbuf *)&ent->value, ent->token,
1310
0
                        NGHTTP2_NV_FLAG_NONE};
1311
0
    return nv;
1312
0
  }
1313
0
}
1314
1315
static const nghttp2_nv *nghttp2_hd_table_get2(nghttp2_hd_context *context,
1316
0
                                               size_t idx) {
1317
0
  assert(INDEX_RANGE_VALID(context, idx));
1318
0
  if (idx >= NGHTTP2_STATIC_TABLE_LENGTH) {
1319
0
    return &hd_ringbuf_get(&context->hd_table,
1320
0
                           idx - NGHTTP2_STATIC_TABLE_LENGTH)
1321
0
                ->cnv;
1322
0
  }
1323
1324
0
  return &static_table[idx].cnv;
1325
0
}
1326
1327
static int hd_deflate_decide_indexing(nghttp2_hd_deflater *deflater,
1328
0
                                      const nghttp2_nv *nv, int32_t token) {
1329
0
  if (token == NGHTTP2_TOKEN__PATH || token == NGHTTP2_TOKEN_AGE ||
1330
0
      token == NGHTTP2_TOKEN_CONTENT_LENGTH || token == NGHTTP2_TOKEN_ETAG ||
1331
0
      token == NGHTTP2_TOKEN_IF_MODIFIED_SINCE ||
1332
0
      token == NGHTTP2_TOKEN_IF_NONE_MATCH || token == NGHTTP2_TOKEN_LOCATION ||
1333
0
      token == NGHTTP2_TOKEN_SET_COOKIE ||
1334
0
      entry_room(nv->namelen, nv->valuelen) >
1335
0
          deflater->ctx.hd_table_bufsize_max * 3 / 4) {
1336
0
    return NGHTTP2_HD_WITHOUT_INDEXING;
1337
0
  }
1338
1339
0
  return NGHTTP2_HD_WITH_INDEXING;
1340
0
}
1341
1342
static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
1343
0
                      const nghttp2_nv *nv) {
1344
0
  int rv;
1345
0
  search_result res;
1346
0
  ssize_t idx;
1347
0
  int indexing_mode;
1348
0
  int32_t token;
1349
0
  nghttp2_mem *mem;
1350
0
  uint32_t hash = 0;
1351
1352
0
  DEBUGF("deflatehd: deflating %.*s: %.*s\n", (int)nv->namelen, nv->name,
1353
0
         (int)nv->valuelen, nv->value);
1354
1355
0
  mem = deflater->ctx.mem;
1356
1357
0
  token = lookup_token(nv->name, nv->namelen);
1358
0
  if (token == -1) {
1359
0
    hash = name_hash(nv);
1360
0
  } else if (token <= NGHTTP2_TOKEN_WWW_AUTHENTICATE) {
1361
0
    hash = static_table[token].hash;
1362
0
  }
1363
1364
  /* Don't index authorization header field since it may contain low
1365
     entropy secret data (e.g., id/password).  Also cookie header
1366
     field with less than 20 bytes value is also never indexed.  This
1367
     is the same criteria used in Firefox codebase. */
1368
0
  indexing_mode =
1369
0
      token == NGHTTP2_TOKEN_AUTHORIZATION ||
1370
0
              (token == NGHTTP2_TOKEN_COOKIE && nv->valuelen < 20) ||
1371
0
              (nv->flags & NGHTTP2_NV_FLAG_NO_INDEX)
1372
0
          ? NGHTTP2_HD_NEVER_INDEXING
1373
0
          : hd_deflate_decide_indexing(deflater, nv, token);
1374
1375
0
  res = search_hd_table(&deflater->ctx, nv, token, indexing_mode,
1376
0
                        &deflater->map, hash);
1377
1378
0
  idx = res.index;
1379
1380
0
  if (res.name_value_match) {
1381
1382
0
    DEBUGF("deflatehd: name/value match index=%zd\n", idx);
1383
1384
0
    rv = emit_indexed_block(bufs, (size_t)idx);
1385
0
    if (rv != 0) {
1386
0
      return rv;
1387
0
    }
1388
1389
0
    return 0;
1390
0
  }
1391
1392
0
  if (res.index != -1) {
1393
0
    DEBUGF("deflatehd: name match index=%zd\n", res.index);
1394
0
  }
1395
1396
0
  if (indexing_mode == NGHTTP2_HD_WITH_INDEXING) {
1397
0
    nghttp2_hd_nv hd_nv;
1398
1399
0
    if (idx != -1) {
1400
0
      hd_nv.name = nghttp2_hd_table_get(&deflater->ctx, (size_t)idx).name;
1401
0
      nghttp2_rcbuf_incref(hd_nv.name);
1402
0
    } else {
1403
0
      rv = nghttp2_rcbuf_new2(&hd_nv.name, nv->name, nv->namelen, mem);
1404
0
      if (rv != 0) {
1405
0
        return rv;
1406
0
      }
1407
0
    }
1408
1409
0
    rv = nghttp2_rcbuf_new2(&hd_nv.value, nv->value, nv->valuelen, mem);
1410
1411
0
    if (rv != 0) {
1412
0
      nghttp2_rcbuf_decref(hd_nv.name);
1413
0
      return rv;
1414
0
    }
1415
1416
0
    hd_nv.token = token;
1417
0
    hd_nv.flags = NGHTTP2_NV_FLAG_NONE;
1418
1419
0
    rv = add_hd_table_incremental(&deflater->ctx, &hd_nv, &deflater->map, hash);
1420
1421
0
    nghttp2_rcbuf_decref(hd_nv.value);
1422
0
    nghttp2_rcbuf_decref(hd_nv.name);
1423
1424
0
    if (rv != 0) {
1425
0
      return NGHTTP2_ERR_HEADER_COMP;
1426
0
    }
1427
0
  }
1428
0
  if (idx == -1) {
1429
0
    rv = emit_newname_block(bufs, nv, indexing_mode);
1430
0
  } else {
1431
0
    rv = emit_indname_block(bufs, (size_t)idx, nv, indexing_mode);
1432
0
  }
1433
0
  if (rv != 0) {
1434
0
    return rv;
1435
0
  }
1436
1437
0
  return 0;
1438
0
}
1439
1440
int nghttp2_hd_deflate_hd_bufs(nghttp2_hd_deflater *deflater,
1441
                               nghttp2_bufs *bufs, const nghttp2_nv *nv,
1442
0
                               size_t nvlen) {
1443
0
  size_t i;
1444
0
  int rv = 0;
1445
1446
0
  if (deflater->ctx.bad) {
1447
0
    return NGHTTP2_ERR_HEADER_COMP;
1448
0
  }
1449
1450
0
  if (deflater->notify_table_size_change) {
1451
0
    size_t min_hd_table_bufsize_max;
1452
1453
0
    min_hd_table_bufsize_max = deflater->min_hd_table_bufsize_max;
1454
1455
0
    deflater->notify_table_size_change = 0;
1456
0
    deflater->min_hd_table_bufsize_max = UINT32_MAX;
1457
1458
0
    if (deflater->ctx.hd_table_bufsize_max > min_hd_table_bufsize_max) {
1459
1460
0
      rv = emit_table_size(bufs, min_hd_table_bufsize_max);
1461
1462
0
      if (rv != 0) {
1463
0
        goto fail;
1464
0
      }
1465
0
    }
1466
1467
0
    rv = emit_table_size(bufs, deflater->ctx.hd_table_bufsize_max);
1468
1469
0
    if (rv != 0) {
1470
0
      goto fail;
1471
0
    }
1472
0
  }
1473
1474
0
  for (i = 0; i < nvlen; ++i) {
1475
0
    rv = deflate_nv(deflater, bufs, &nv[i]);
1476
0
    if (rv != 0) {
1477
0
      goto fail;
1478
0
    }
1479
0
  }
1480
1481
0
  DEBUGF("deflatehd: all input name/value pairs were deflated\n");
1482
1483
0
  return 0;
1484
0
fail:
1485
0
  DEBUGF("deflatehd: error return %d\n", rv);
1486
1487
0
  deflater->ctx.bad = 1;
1488
0
  return rv;
1489
0
}
1490
1491
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, uint8_t *buf,
1492
                              size_t buflen, const nghttp2_nv *nv,
1493
0
                              size_t nvlen) {
1494
0
  nghttp2_bufs bufs;
1495
0
  int rv;
1496
0
  nghttp2_mem *mem;
1497
1498
0
  mem = deflater->ctx.mem;
1499
1500
0
  rv = nghttp2_bufs_wrap_init(&bufs, buf, buflen, mem);
1501
1502
0
  if (rv != 0) {
1503
0
    return rv;
1504
0
  }
1505
1506
0
  rv = nghttp2_hd_deflate_hd_bufs(deflater, &bufs, nv, nvlen);
1507
1508
0
  buflen = nghttp2_bufs_len(&bufs);
1509
1510
0
  nghttp2_bufs_wrap_free(&bufs);
1511
1512
0
  if (rv == NGHTTP2_ERR_BUFFER_ERROR) {
1513
0
    return NGHTTP2_ERR_INSUFF_BUFSIZE;
1514
0
  }
1515
1516
0
  if (rv != 0) {
1517
0
    return rv;
1518
0
  }
1519
1520
0
  return (ssize_t)buflen;
1521
0
}
1522
1523
ssize_t nghttp2_hd_deflate_hd_vec(nghttp2_hd_deflater *deflater,
1524
                                  const nghttp2_vec *vec, size_t veclen,
1525
0
                                  const nghttp2_nv *nv, size_t nvlen) {
1526
0
  nghttp2_bufs bufs;
1527
0
  int rv;
1528
0
  nghttp2_mem *mem;
1529
0
  size_t buflen;
1530
1531
0
  mem = deflater->ctx.mem;
1532
1533
0
  rv = nghttp2_bufs_wrap_init2(&bufs, vec, veclen, mem);
1534
1535
0
  if (rv != 0) {
1536
0
    return rv;
1537
0
  }
1538
1539
0
  rv = nghttp2_hd_deflate_hd_bufs(deflater, &bufs, nv, nvlen);
1540
1541
0
  buflen = nghttp2_bufs_len(&bufs);
1542
1543
0
  nghttp2_bufs_wrap_free(&bufs);
1544
1545
0
  if (rv == NGHTTP2_ERR_BUFFER_ERROR) {
1546
0
    return NGHTTP2_ERR_INSUFF_BUFSIZE;
1547
0
  }
1548
1549
0
  if (rv != 0) {
1550
0
    return rv;
1551
0
  }
1552
1553
0
  return (ssize_t)buflen;
1554
0
}
1555
1556
size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater,
1557
0
                                const nghttp2_nv *nva, size_t nvlen) {
1558
0
  size_t n = 0;
1559
0
  size_t i;
1560
0
  (void)deflater;
1561
1562
  /* Possible Maximum Header Table Size Change.  Encoding (1u << 31) -
1563
     1 using 4 bit prefix requires 6 bytes.  We may emit this at most
1564
     twice. */
1565
0
  n += 12;
1566
1567
  /* Use Literal Header Field without indexing - New Name, since it is
1568
     most space consuming format.  Also we choose the less one between
1569
     non-huffman and huffman, so using literal byte count is
1570
     sufficient for upper bound.
1571
1572
     Encoding (1u << 31) - 1 using 7 bit prefix requires 6 bytes.  We
1573
     need 2 of this for |nvlen| header fields. */
1574
0
  n += 6 * 2 * nvlen;
1575
1576
0
  for (i = 0; i < nvlen; ++i) {
1577
0
    n += nva[i].namelen + nva[i].valuelen;
1578
0
  }
1579
1580
0
  return n;
1581
0
}
1582
1583
int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr,
1584
0
                           size_t deflate_hd_table_bufsize_max) {
1585
0
  return nghttp2_hd_deflate_new2(deflater_ptr, deflate_hd_table_bufsize_max,
1586
0
                                 NULL);
1587
0
}
1588
1589
int nghttp2_hd_deflate_new2(nghttp2_hd_deflater **deflater_ptr,
1590
                            size_t deflate_hd_table_bufsize_max,
1591
0
                            nghttp2_mem *mem) {
1592
0
  int rv;
1593
0
  nghttp2_hd_deflater *deflater;
1594
1595
0
  if (mem == NULL) {
1596
0
    mem = nghttp2_mem_default();
1597
0
  }
1598
1599
0
  deflater = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_deflater));
1600
1601
0
  if (deflater == NULL) {
1602
0
    return NGHTTP2_ERR_NOMEM;
1603
0
  }
1604
1605
0
  rv = nghttp2_hd_deflate_init2(deflater, deflate_hd_table_bufsize_max, mem);
1606
1607
0
  if (rv != 0) {
1608
0
    nghttp2_mem_free(mem, deflater);
1609
1610
0
    return rv;
1611
0
  }
1612
1613
0
  *deflater_ptr = deflater;
1614
1615
0
  return 0;
1616
0
}
1617
1618
0
void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater) {
1619
0
  nghttp2_mem *mem;
1620
1621
0
  mem = deflater->ctx.mem;
1622
1623
0
  nghttp2_hd_deflate_free(deflater);
1624
1625
0
  nghttp2_mem_free(mem, deflater);
1626
0
}
1627
1628
static void hd_inflate_set_huffman_encoded(nghttp2_hd_inflater *inflater,
1629
0
                                           const uint8_t *in) {
1630
0
  inflater->huffman_encoded = (*in & (1 << 7)) != 0;
1631
0
}
1632
1633
/*
1634
 * Decodes the integer from the range [in, last).  The result is
1635
 * assigned to |inflater->left|.  If the |inflater->left| is 0, then
1636
 * it performs variable integer decoding from scratch. Otherwise, it
1637
 * uses the |inflater->left| as the initial value and continues to
1638
 * decode assuming that [in, last) begins with intermediary sequence.
1639
 *
1640
 * This function returns the number of bytes read if it succeeds, or
1641
 * one of the following negative error codes:
1642
 *
1643
 * NGHTTP2_ERR_HEADER_COMP
1644
 *   Integer decoding failed
1645
 */
1646
static ssize_t hd_inflate_read_len(nghttp2_hd_inflater *inflater, int *rfin,
1647
                                   const uint8_t *in, const uint8_t *last,
1648
0
                                   size_t prefix, size_t maxlen) {
1649
0
  ssize_t rv;
1650
0
  uint32_t out;
1651
1652
0
  *rfin = 0;
1653
1654
0
  rv = decode_length(&out, &inflater->shift, rfin, (uint32_t)inflater->left,
1655
0
                     inflater->shift, in, last, prefix);
1656
1657
0
  if (rv == -1) {
1658
0
    DEBUGF("inflatehd: integer decoding failed\n");
1659
0
    return NGHTTP2_ERR_HEADER_COMP;
1660
0
  }
1661
1662
0
  if (out > maxlen) {
1663
0
    DEBUGF("inflatehd: integer exceeded the maximum value %zu\n", maxlen);
1664
0
    return NGHTTP2_ERR_HEADER_COMP;
1665
0
  }
1666
1667
0
  inflater->left = out;
1668
1669
0
  DEBUGF("inflatehd: decoded integer is %u\n", out);
1670
1671
0
  return rv;
1672
0
}
1673
1674
/*
1675
 * Reads |inflater->left| bytes from the range [in, last) and performs
1676
 * huffman decoding against them and pushes the result into the
1677
 * |buffer|.
1678
 *
1679
 * This function returns the number of bytes read if it succeeds, or
1680
 * one of the following negative error codes:
1681
 *
1682
 * NGHTTP2_ERR_NOMEM
1683
 *   Out of memory
1684
 * NGHTTP2_ERR_HEADER_COMP
1685
 *   Huffman decoding failed
1686
 */
1687
static ssize_t hd_inflate_read_huff(nghttp2_hd_inflater *inflater,
1688
                                    nghttp2_buf *buf, const uint8_t *in,
1689
0
                                    const uint8_t *last) {
1690
0
  ssize_t readlen;
1691
0
  int fin = 0;
1692
0
  if ((size_t)(last - in) >= inflater->left) {
1693
0
    last = in + inflater->left;
1694
0
    fin = 1;
1695
0
  }
1696
0
  readlen = nghttp2_hd_huff_decode(&inflater->huff_decode_ctx, buf, in,
1697
0
                                   (size_t)(last - in), fin);
1698
1699
0
  if (readlen < 0) {
1700
0
    DEBUGF("inflatehd: huffman decoding failed\n");
1701
0
    return readlen;
1702
0
  }
1703
0
  if (nghttp2_hd_huff_decode_failure_state(&inflater->huff_decode_ctx)) {
1704
0
    DEBUGF("inflatehd: huffman decoding failed\n");
1705
0
    return NGHTTP2_ERR_HEADER_COMP;
1706
0
  }
1707
1708
0
  inflater->left -= (size_t)readlen;
1709
0
  return readlen;
1710
0
}
1711
1712
/*
1713
 * Reads |inflater->left| bytes from the range [in, last) and copies
1714
 * them into the |buffer|.
1715
 *
1716
 * This function returns the number of bytes read if it succeeds, or
1717
 * one of the following negative error codes:
1718
 *
1719
 * NGHTTP2_ERR_NOMEM
1720
 *   Out of memory
1721
 * NGHTTP2_ERR_HEADER_COMP
1722
 *   Header decompression failed
1723
 */
1724
static ssize_t hd_inflate_read(nghttp2_hd_inflater *inflater, nghttp2_buf *buf,
1725
0
                               const uint8_t *in, const uint8_t *last) {
1726
0
  size_t len = nghttp2_min((size_t)(last - in), inflater->left);
1727
1728
0
  buf->last = nghttp2_cpymem(buf->last, in, len);
1729
1730
0
  inflater->left -= len;
1731
0
  return (ssize_t)len;
1732
0
}
1733
1734
/*
1735
 * Finalize indexed header representation reception.  The referenced
1736
 * header is always emitted, and |*nv_out| is filled with that value.
1737
 */
1738
static void hd_inflate_commit_indexed(nghttp2_hd_inflater *inflater,
1739
0
                                      nghttp2_hd_nv *nv_out) {
1740
0
  nghttp2_hd_nv nv = nghttp2_hd_table_get(&inflater->ctx, inflater->index);
1741
1742
0
  emit_header(nv_out, &nv);
1743
0
}
1744
1745
/*
1746
 * Finalize literal header representation - new name- reception. If
1747
 * header is emitted, |*nv_out| is filled with that value and 0 is
1748
 * returned.
1749
 *
1750
 * This function returns 0 if it succeeds, or one of the following
1751
 * negative error codes:
1752
 *
1753
 * NGHTTP2_ERR_NOMEM
1754
 *   Out of memory
1755
 */
1756
static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater,
1757
0
                                     nghttp2_hd_nv *nv_out) {
1758
0
  nghttp2_hd_nv nv;
1759
0
  int rv;
1760
1761
0
  if (inflater->no_index) {
1762
0
    nv.flags = NGHTTP2_NV_FLAG_NO_INDEX;
1763
0
  } else {
1764
0
    nv.flags = NGHTTP2_NV_FLAG_NONE;
1765
0
  }
1766
1767
0
  nv.name = inflater->namercbuf;
1768
0
  nv.value = inflater->valuercbuf;
1769
0
  nv.token = lookup_token(inflater->namercbuf->base, inflater->namercbuf->len);
1770
1771
0
  if (inflater->index_required) {
1772
0
    rv = add_hd_table_incremental(&inflater->ctx, &nv, NULL, 0);
1773
1774
0
    if (rv != 0) {
1775
0
      return rv;
1776
0
    }
1777
0
  }
1778
1779
0
  emit_header(nv_out, &nv);
1780
1781
0
  inflater->nv_name_keep = nv.name;
1782
0
  inflater->nv_value_keep = nv.value;
1783
1784
0
  inflater->namercbuf = NULL;
1785
0
  inflater->valuercbuf = NULL;
1786
1787
0
  return 0;
1788
0
}
1789
1790
/*
1791
 * Finalize literal header representation - indexed name-
1792
 * reception. If header is emitted, |*nv_out| is filled with that
1793
 * value and 0 is returned.
1794
 *
1795
 * This function returns 0 if it succeeds, or one of the following
1796
 * negative error codes:
1797
 *
1798
 * NGHTTP2_ERR_NOMEM
1799
 *   Out of memory
1800
 */
1801
static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater,
1802
0
                                     nghttp2_hd_nv *nv_out) {
1803
0
  nghttp2_hd_nv nv;
1804
0
  int rv;
1805
1806
0
  nv = nghttp2_hd_table_get(&inflater->ctx, inflater->index);
1807
1808
0
  if (inflater->no_index) {
1809
0
    nv.flags = NGHTTP2_NV_FLAG_NO_INDEX;
1810
0
  } else {
1811
0
    nv.flags = NGHTTP2_NV_FLAG_NONE;
1812
0
  }
1813
1814
0
  nghttp2_rcbuf_incref(nv.name);
1815
1816
0
  nv.value = inflater->valuercbuf;
1817
1818
0
  if (inflater->index_required) {
1819
0
    rv = add_hd_table_incremental(&inflater->ctx, &nv, NULL, 0);
1820
0
    if (rv != 0) {
1821
0
      nghttp2_rcbuf_decref(nv.name);
1822
0
      return NGHTTP2_ERR_NOMEM;
1823
0
    }
1824
0
  }
1825
1826
0
  emit_header(nv_out, &nv);
1827
1828
0
  inflater->nv_name_keep = nv.name;
1829
0
  inflater->nv_value_keep = nv.value;
1830
1831
0
  inflater->valuercbuf = NULL;
1832
1833
0
  return 0;
1834
0
}
1835
1836
ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
1837
                              int *inflate_flags, uint8_t *in, size_t inlen,
1838
0
                              int in_final) {
1839
0
  return nghttp2_hd_inflate_hd2(inflater, nv_out, inflate_flags, in, inlen,
1840
0
                                in_final);
1841
0
}
1842
1843
ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater,
1844
                               nghttp2_nv *nv_out, int *inflate_flags,
1845
0
                               const uint8_t *in, size_t inlen, int in_final) {
1846
0
  ssize_t rv;
1847
0
  nghttp2_hd_nv hd_nv;
1848
1849
0
  rv = nghttp2_hd_inflate_hd_nv(inflater, &hd_nv, inflate_flags, in, inlen,
1850
0
                                in_final);
1851
1852
0
  if (rv < 0) {
1853
0
    return rv;
1854
0
  }
1855
1856
0
  if (*inflate_flags & NGHTTP2_HD_INFLATE_EMIT) {
1857
0
    nv_out->name = hd_nv.name->base;
1858
0
    nv_out->namelen = hd_nv.name->len;
1859
1860
0
    nv_out->value = hd_nv.value->base;
1861
0
    nv_out->valuelen = hd_nv.value->len;
1862
1863
0
    nv_out->flags = hd_nv.flags;
1864
0
  }
1865
1866
0
  return rv;
1867
0
}
1868
1869
ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
1870
                                 nghttp2_hd_nv *nv_out, int *inflate_flags,
1871
                                 const uint8_t *in, size_t inlen,
1872
0
                                 int in_final) {
1873
0
  ssize_t rv = 0;
1874
0
  const uint8_t *first = in;
1875
0
  const uint8_t *last = in + inlen;
1876
0
  int rfin = 0;
1877
0
  int busy = 0;
1878
0
  nghttp2_mem *mem;
1879
1880
0
  mem = inflater->ctx.mem;
1881
1882
0
  if (inflater->ctx.bad) {
1883
0
    return NGHTTP2_ERR_HEADER_COMP;
1884
0
  }
1885
1886
0
  DEBUGF("inflatehd: start state=%d\n", inflater->state);
1887
0
  hd_inflate_keep_free(inflater);
1888
0
  *inflate_flags = NGHTTP2_HD_INFLATE_NONE;
1889
0
  for (; in != last || busy;) {
1890
0
    busy = 0;
1891
0
    switch (inflater->state) {
1892
0
    case NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE:
1893
0
      if ((*in & 0xe0u) != 0x20u) {
1894
0
        DEBUGF("inflatehd: header table size change was expected, but saw "
1895
0
               "0x%02x as first byte",
1896
0
               *in);
1897
0
        rv = NGHTTP2_ERR_HEADER_COMP;
1898
0
        goto fail;
1899
0
      }
1900
    /* fall through */
1901
0
    case NGHTTP2_HD_STATE_INFLATE_START:
1902
0
    case NGHTTP2_HD_STATE_OPCODE:
1903
0
      if ((*in & 0xe0u) == 0x20u) {
1904
0
        DEBUGF("inflatehd: header table size change\n");
1905
0
        if (inflater->state == NGHTTP2_HD_STATE_OPCODE) {
1906
0
          DEBUGF("inflatehd: header table size change must appear at the head "
1907
0
                 "of header block\n");
1908
0
          rv = NGHTTP2_ERR_HEADER_COMP;
1909
0
          goto fail;
1910
0
        }
1911
0
        inflater->opcode = NGHTTP2_HD_OPCODE_INDEXED;
1912
0
        inflater->state = NGHTTP2_HD_STATE_READ_TABLE_SIZE;
1913
0
      } else if (*in & 0x80u) {
1914
0
        DEBUGF("inflatehd: indexed repr\n");
1915
0
        inflater->opcode = NGHTTP2_HD_OPCODE_INDEXED;
1916
0
        inflater->state = NGHTTP2_HD_STATE_READ_INDEX;
1917
0
      } else {
1918
0
        if (*in == 0x40u || *in == 0 || *in == 0x10u) {
1919
0
          DEBUGF("inflatehd: literal header repr - new name\n");
1920
0
          inflater->opcode = NGHTTP2_HD_OPCODE_NEWNAME;
1921
0
          inflater->state = NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN;
1922
0
        } else {
1923
0
          DEBUGF("inflatehd: literal header repr - indexed name\n");
1924
0
          inflater->opcode = NGHTTP2_HD_OPCODE_INDNAME;
1925
0
          inflater->state = NGHTTP2_HD_STATE_READ_INDEX;
1926
0
        }
1927
0
        inflater->index_required = (*in & 0x40) != 0;
1928
0
        inflater->no_index = (*in & 0xf0u) == 0x10u;
1929
0
        DEBUGF("inflatehd: indexing required=%d, no_index=%d\n",
1930
0
               inflater->index_required, inflater->no_index);
1931
0
        if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) {
1932
0
          ++in;
1933
0
        }
1934
0
      }
1935
0
      inflater->left = 0;
1936
0
      inflater->shift = 0;
1937
0
      break;
1938
0
    case NGHTTP2_HD_STATE_READ_TABLE_SIZE:
1939
0
      rfin = 0;
1940
0
      rv = hd_inflate_read_len(
1941
0
          inflater, &rfin, in, last, 5,
1942
0
          nghttp2_min(inflater->min_hd_table_bufsize_max,
1943
0
                      inflater->settings_hd_table_bufsize_max));
1944
0
      if (rv < 0) {
1945
0
        goto fail;
1946
0
      }
1947
0
      in += rv;
1948
0
      if (!rfin) {
1949
0
        goto almost_ok;
1950
0
      }
1951
0
      DEBUGF("inflatehd: table_size=%zu\n", inflater->left);
1952
0
      inflater->min_hd_table_bufsize_max = UINT32_MAX;
1953
0
      inflater->ctx.hd_table_bufsize_max = inflater->left;
1954
0
      hd_context_shrink_table_size(&inflater->ctx, NULL);
1955
0
      inflater->state = NGHTTP2_HD_STATE_INFLATE_START;
1956
0
      break;
1957
0
    case NGHTTP2_HD_STATE_READ_INDEX: {
1958
0
      size_t prefixlen;
1959
1960
0
      if (inflater->opcode == NGHTTP2_HD_OPCODE_INDEXED) {
1961
0
        prefixlen = 7;
1962
0
      } else if (inflater->index_required) {
1963
0
        prefixlen = 6;
1964
0
      } else {
1965
0
        prefixlen = 4;
1966
0
      }
1967
1968
0
      rfin = 0;
1969
0
      rv = hd_inflate_read_len(inflater, &rfin, in, last, prefixlen,
1970
0
                               get_max_index(&inflater->ctx));
1971
0
      if (rv < 0) {
1972
0
        goto fail;
1973
0
      }
1974
1975
0
      in += rv;
1976
1977
0
      if (!rfin) {
1978
0
        goto almost_ok;
1979
0
      }
1980
1981
0
      if (inflater->left == 0) {
1982
0
        rv = NGHTTP2_ERR_HEADER_COMP;
1983
0
        goto fail;
1984
0
      }
1985
1986
0
      DEBUGF("inflatehd: index=%zu\n", inflater->left);
1987
0
      if (inflater->opcode == NGHTTP2_HD_OPCODE_INDEXED) {
1988
0
        inflater->index = inflater->left;
1989
0
        --inflater->index;
1990
1991
0
        hd_inflate_commit_indexed(inflater, nv_out);
1992
1993
0
        inflater->state = NGHTTP2_HD_STATE_OPCODE;
1994
0
        *inflate_flags |= NGHTTP2_HD_INFLATE_EMIT;
1995
0
        return (ssize_t)(in - first);
1996
0
      } else {
1997
0
        inflater->index = inflater->left;
1998
0
        --inflater->index;
1999
2000
0
        inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN;
2001
0
      }
2002
0
      break;
2003
0
    }
2004
0
    case NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN:
2005
0
      hd_inflate_set_huffman_encoded(inflater, in);
2006
0
      inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN;
2007
0
      inflater->left = 0;
2008
0
      inflater->shift = 0;
2009
0
      DEBUGF("inflatehd: huffman encoded=%d\n", inflater->huffman_encoded != 0);
2010
    /* Fall through */
2011
0
    case NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN:
2012
0
      rfin = 0;
2013
0
      rv = hd_inflate_read_len(inflater, &rfin, in, last, 7, NGHTTP2_HD_MAX_NV);
2014
0
      if (rv < 0) {
2015
0
        goto fail;
2016
0
      }
2017
0
      in += rv;
2018
0
      if (!rfin) {
2019
0
        DEBUGF("inflatehd: integer not fully decoded. current=%zu\n",
2020
0
               inflater->left);
2021
2022
0
        goto almost_ok;
2023
0
      }
2024
2025
0
      if (inflater->huffman_encoded) {
2026
0
        nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx);
2027
2028
0
        inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF;
2029
2030
0
        rv = nghttp2_rcbuf_new(&inflater->namercbuf, inflater->left * 2 + 1,
2031
0
                               mem);
2032
0
      } else {
2033
0
        inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAME;
2034
0
        rv = nghttp2_rcbuf_new(&inflater->namercbuf, inflater->left + 1, mem);
2035
0
      }
2036
2037
0
      if (rv != 0) {
2038
0
        goto fail;
2039
0
      }
2040
2041
0
      nghttp2_buf_wrap_init(&inflater->namebuf, inflater->namercbuf->base,
2042
0
                            inflater->namercbuf->len);
2043
2044
0
      break;
2045
0
    case NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF:
2046
0
      rv = hd_inflate_read_huff(inflater, &inflater->namebuf, in, last);
2047
0
      if (rv < 0) {
2048
0
        goto fail;
2049
0
      }
2050
2051
0
      in += rv;
2052
2053
0
      DEBUGF("inflatehd: %zd bytes read\n", rv);
2054
2055
0
      if (inflater->left) {
2056
0
        DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left);
2057
2058
0
        goto almost_ok;
2059
0
      }
2060
2061
0
      *inflater->namebuf.last = '\0';
2062
0
      inflater->namercbuf->len = nghttp2_buf_len(&inflater->namebuf);
2063
2064
0
      inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN;
2065
2066
0
      break;
2067
0
    case NGHTTP2_HD_STATE_NEWNAME_READ_NAME:
2068
0
      rv = hd_inflate_read(inflater, &inflater->namebuf, in, last);
2069
0
      if (rv < 0) {
2070
0
        goto fail;
2071
0
      }
2072
2073
0
      in += rv;
2074
2075
0
      DEBUGF("inflatehd: %zd bytes read\n", rv);
2076
0
      if (inflater->left) {
2077
0
        DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left);
2078
2079
0
        goto almost_ok;
2080
0
      }
2081
2082
0
      *inflater->namebuf.last = '\0';
2083
0
      inflater->namercbuf->len = nghttp2_buf_len(&inflater->namebuf);
2084
2085
0
      inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN;
2086
2087
0
      break;
2088
0
    case NGHTTP2_HD_STATE_CHECK_VALUELEN:
2089
0
      hd_inflate_set_huffman_encoded(inflater, in);
2090
0
      inflater->state = NGHTTP2_HD_STATE_READ_VALUELEN;
2091
0
      inflater->left = 0;
2092
0
      inflater->shift = 0;
2093
0
      DEBUGF("inflatehd: huffman encoded=%d\n", inflater->huffman_encoded != 0);
2094
    /* Fall through */
2095
0
    case NGHTTP2_HD_STATE_READ_VALUELEN:
2096
0
      rfin = 0;
2097
0
      rv = hd_inflate_read_len(inflater, &rfin, in, last, 7, NGHTTP2_HD_MAX_NV);
2098
0
      if (rv < 0) {
2099
0
        goto fail;
2100
0
      }
2101
2102
0
      in += rv;
2103
2104
0
      if (!rfin) {
2105
0
        goto almost_ok;
2106
0
      }
2107
2108
0
      DEBUGF("inflatehd: valuelen=%zu\n", inflater->left);
2109
2110
0
      if (inflater->huffman_encoded) {
2111
0
        nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx);
2112
2113
0
        inflater->state = NGHTTP2_HD_STATE_READ_VALUEHUFF;
2114
2115
0
        rv = nghttp2_rcbuf_new(&inflater->valuercbuf, inflater->left * 2 + 1,
2116
0
                               mem);
2117
0
      } else {
2118
0
        inflater->state = NGHTTP2_HD_STATE_READ_VALUE;
2119
2120
0
        rv = nghttp2_rcbuf_new(&inflater->valuercbuf, inflater->left + 1, mem);
2121
0
      }
2122
2123
0
      if (rv != 0) {
2124
0
        goto fail;
2125
0
      }
2126
2127
0
      nghttp2_buf_wrap_init(&inflater->valuebuf, inflater->valuercbuf->base,
2128
0
                            inflater->valuercbuf->len);
2129
2130
0
      busy = 1;
2131
2132
0
      break;
2133
0
    case NGHTTP2_HD_STATE_READ_VALUEHUFF:
2134
0
      rv = hd_inflate_read_huff(inflater, &inflater->valuebuf, in, last);
2135
0
      if (rv < 0) {
2136
0
        goto fail;
2137
0
      }
2138
2139
0
      in += rv;
2140
2141
0
      DEBUGF("inflatehd: %zd bytes read\n", rv);
2142
2143
0
      if (inflater->left) {
2144
0
        DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left);
2145
2146
0
        goto almost_ok;
2147
0
      }
2148
2149
0
      *inflater->valuebuf.last = '\0';
2150
0
      inflater->valuercbuf->len = nghttp2_buf_len(&inflater->valuebuf);
2151
2152
0
      if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) {
2153
0
        rv = hd_inflate_commit_newname(inflater, nv_out);
2154
0
      } else {
2155
0
        rv = hd_inflate_commit_indname(inflater, nv_out);
2156
0
      }
2157
2158
0
      if (rv != 0) {
2159
0
        goto fail;
2160
0
      }
2161
2162
0
      inflater->state = NGHTTP2_HD_STATE_OPCODE;
2163
0
      *inflate_flags |= NGHTTP2_HD_INFLATE_EMIT;
2164
2165
0
      return (ssize_t)(in - first);
2166
0
    case NGHTTP2_HD_STATE_READ_VALUE:
2167
0
      rv = hd_inflate_read(inflater, &inflater->valuebuf, in, last);
2168
0
      if (rv < 0) {
2169
0
        DEBUGF("inflatehd: value read failure %zd: %s\n", rv,
2170
0
               nghttp2_strerror((int)rv));
2171
0
        goto fail;
2172
0
      }
2173
2174
0
      in += rv;
2175
2176
0
      DEBUGF("inflatehd: %zd bytes read\n", rv);
2177
2178
0
      if (inflater->left) {
2179
0
        DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left);
2180
0
        goto almost_ok;
2181
0
      }
2182
2183
0
      *inflater->valuebuf.last = '\0';
2184
0
      inflater->valuercbuf->len = nghttp2_buf_len(&inflater->valuebuf);
2185
2186
0
      if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) {
2187
0
        rv = hd_inflate_commit_newname(inflater, nv_out);
2188
0
      } else {
2189
0
        rv = hd_inflate_commit_indname(inflater, nv_out);
2190
0
      }
2191
2192
0
      if (rv != 0) {
2193
0
        goto fail;
2194
0
      }
2195
2196
0
      inflater->state = NGHTTP2_HD_STATE_OPCODE;
2197
0
      *inflate_flags |= NGHTTP2_HD_INFLATE_EMIT;
2198
2199
0
      return (ssize_t)(in - first);
2200
0
    }
2201
0
  }
2202
2203
0
  assert(in == last);
2204
2205
0
  DEBUGF("inflatehd: all input bytes were processed\n");
2206
2207
0
  if (in_final) {
2208
0
    DEBUGF("inflatehd: in_final set\n");
2209
2210
0
    if (inflater->state != NGHTTP2_HD_STATE_OPCODE &&
2211
0
        inflater->state != NGHTTP2_HD_STATE_INFLATE_START) {
2212
0
      DEBUGF("inflatehd: unacceptable state=%d\n", inflater->state);
2213
0
      rv = NGHTTP2_ERR_HEADER_COMP;
2214
2215
0
      goto fail;
2216
0
    }
2217
0
    *inflate_flags |= NGHTTP2_HD_INFLATE_FINAL;
2218
0
  }
2219
0
  return (ssize_t)(in - first);
2220
2221
0
almost_ok:
2222
0
  if (in_final) {
2223
0
    DEBUGF("inflatehd: input ended prematurely\n");
2224
2225
0
    rv = NGHTTP2_ERR_HEADER_COMP;
2226
2227
0
    goto fail;
2228
0
  }
2229
0
  return (ssize_t)(in - first);
2230
2231
0
fail:
2232
0
  DEBUGF("inflatehd: error return %zd\n", rv);
2233
2234
0
  inflater->ctx.bad = 1;
2235
0
  return rv;
2236
0
}
2237
2238
0
int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater) {
2239
0
  hd_inflate_keep_free(inflater);
2240
0
  inflater->state = NGHTTP2_HD_STATE_INFLATE_START;
2241
0
  return 0;
2242
0
}
2243
2244
0
int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr) {
2245
0
  return nghttp2_hd_inflate_new2(inflater_ptr, NULL);
2246
0
}
2247
2248
int nghttp2_hd_inflate_new2(nghttp2_hd_inflater **inflater_ptr,
2249
0
                            nghttp2_mem *mem) {
2250
0
  int rv;
2251
0
  nghttp2_hd_inflater *inflater;
2252
2253
0
  if (mem == NULL) {
2254
0
    mem = nghttp2_mem_default();
2255
0
  }
2256
2257
0
  inflater = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_inflater));
2258
2259
0
  if (inflater == NULL) {
2260
0
    return NGHTTP2_ERR_NOMEM;
2261
0
  }
2262
2263
0
  rv = nghttp2_hd_inflate_init(inflater, mem);
2264
2265
0
  if (rv != 0) {
2266
0
    nghttp2_mem_free(mem, inflater);
2267
2268
0
    return rv;
2269
0
  }
2270
2271
0
  *inflater_ptr = inflater;
2272
2273
0
  return 0;
2274
0
}
2275
2276
0
void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater) {
2277
0
  nghttp2_mem *mem;
2278
2279
0
  mem = inflater->ctx.mem;
2280
0
  nghttp2_hd_inflate_free(inflater);
2281
2282
0
  nghttp2_mem_free(mem, inflater);
2283
0
}
2284
2285
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t idx,
2286
0
                                  nghttp2_nv *nv, int indexing_mode) {
2287
2288
0
  return emit_indname_block(bufs, idx, nv, indexing_mode);
2289
0
}
2290
2291
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
2292
0
                                  int indexing_mode) {
2293
0
  return emit_newname_block(bufs, nv, indexing_mode);
2294
0
}
2295
2296
0
int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size) {
2297
0
  return emit_table_size(bufs, table_size);
2298
0
}
2299
2300
ssize_t nghttp2_hd_decode_length(uint32_t *res, size_t *shift_ptr, int *fin,
2301
                                 uint32_t initial, size_t shift, uint8_t *in,
2302
0
                                 uint8_t *last, size_t prefix) {
2303
0
  return decode_length(res, shift_ptr, fin, initial, shift, in, last, prefix);
2304
0
}
2305
2306
static const nghttp2_nv *hd_get_table_entry(nghttp2_hd_context *context,
2307
0
                                            size_t idx) {
2308
0
  if (idx == 0) {
2309
0
    return NULL;
2310
0
  }
2311
2312
0
  --idx;
2313
2314
0
  if (!INDEX_RANGE_VALID(context, idx)) {
2315
0
    return NULL;
2316
0
  }
2317
2318
0
  return nghttp2_hd_table_get2(context, idx);
2319
0
}
2320
2321
0
size_t nghttp2_hd_deflate_get_num_table_entries(nghttp2_hd_deflater *deflater) {
2322
0
  return get_max_index(&deflater->ctx);
2323
0
}
2324
2325
const nghttp2_nv *
2326
0
nghttp2_hd_deflate_get_table_entry(nghttp2_hd_deflater *deflater, size_t idx) {
2327
0
  return hd_get_table_entry(&deflater->ctx, idx);
2328
0
}
2329
2330
size_t
2331
0
nghttp2_hd_deflate_get_dynamic_table_size(nghttp2_hd_deflater *deflater) {
2332
0
  return deflater->ctx.hd_table_bufsize;
2333
0
}
2334
2335
size_t
2336
0
nghttp2_hd_deflate_get_max_dynamic_table_size(nghttp2_hd_deflater *deflater) {
2337
0
  return deflater->ctx.hd_table_bufsize_max;
2338
0
}
2339
2340
0
size_t nghttp2_hd_inflate_get_num_table_entries(nghttp2_hd_inflater *inflater) {
2341
0
  return get_max_index(&inflater->ctx);
2342
0
}
2343
2344
const nghttp2_nv *
2345
0
nghttp2_hd_inflate_get_table_entry(nghttp2_hd_inflater *inflater, size_t idx) {
2346
0
  return hd_get_table_entry(&inflater->ctx, idx);
2347
0
}
2348
2349
size_t
2350
0
nghttp2_hd_inflate_get_dynamic_table_size(nghttp2_hd_inflater *inflater) {
2351
0
  return inflater->ctx.hd_table_bufsize;
2352
0
}
2353
2354
size_t
2355
0
nghttp2_hd_inflate_get_max_dynamic_table_size(nghttp2_hd_inflater *inflater) {
2356
0
  return inflater->ctx.hd_table_bufsize_max;
2357
0
}