Coverage Report

Created: 2023-03-26 06:11

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