Coverage Report

Created: 2026-03-12 06:35

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