Coverage Report

Created: 2025-12-14 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nghttp2/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
15.2k
static int memeq(const void *s1, const void *s2, size_t n) {
114
15.2k
  return memcmp(s1, s2, n) == 0;
115
15.2k
}
116
117
/*
118
 * This function was generated by genlibtokenlookup.py.  Inspired by
119
 * h2o header lookup.  https://github.com/h2o/h2o
120
 */
121
18.8k
static int32_t lookup_token(const uint8_t *name, size_t namelen) {
122
18.8k
  switch (namelen) {
123
751
  case 2:
124
751
    switch (name[1]) {
125
542
    case 'e':
126
542
      if (memeq("t", name, 1)) {
127
332
        return NGHTTP2_TOKEN_TE;
128
332
      }
129
210
      break;
130
751
    }
131
419
    break;
132
1.03k
  case 3:
133
1.03k
    switch (name[2]) {
134
422
    case 'a':
135
422
      if (memeq("vi", name, 2)) {
136
195
        return NGHTTP2_TOKEN_VIA;
137
195
      }
138
227
      break;
139
423
    case 'e':
140
423
      if (memeq("ag", name, 2)) {
141
194
        return NGHTTP2_TOKEN_AGE;
142
194
      }
143
229
      break;
144
1.03k
    }
145
650
    break;
146
2.35k
  case 4:
147
2.35k
    switch (name[3]) {
148
303
    case 'e':
149
303
      if (memeq("dat", name, 3)) {
150
66
        return NGHTTP2_TOKEN_DATE;
151
66
      }
152
237
      break;
153
430
    case 'g':
154
430
      if (memeq("eta", name, 3)) {
155
194
        return NGHTTP2_TOKEN_ETAG;
156
194
      }
157
236
      break;
158
417
    case 'k':
159
417
      if (memeq("lin", name, 3)) {
160
194
        return NGHTTP2_TOKEN_LINK;
161
194
      }
162
223
      break;
163
429
    case 'm':
164
429
      if (memeq("fro", name, 3)) {
165
194
        return NGHTTP2_TOKEN_FROM;
166
194
      }
167
235
      break;
168
277
    case 't':
169
277
      if (memeq("hos", name, 3)) {
170
66
        return NGHTTP2_TOKEN_HOST;
171
66
      }
172
211
      break;
173
433
    case 'y':
174
433
      if (memeq("var", name, 3)) {
175
194
        return NGHTTP2_TOKEN_VARY;
176
194
      }
177
239
      break;
178
2.35k
    }
179
1.44k
    break;
180
1.44k
  case 5:
181
472
    switch (name[4]) {
182
138
    case 'e':
183
138
      if (memeq("rang", name, 4)) {
184
71
        return NGHTTP2_TOKEN_RANGE;
185
71
      }
186
67
      break;
187
133
    case 'h':
188
133
      if (memeq(":pat", name, 4)) {
189
66
        return NGHTTP2_TOKEN__PATH;
190
66
      }
191
67
      break;
192
133
    case 'w':
193
133
      if (memeq("allo", name, 4)) {
194
66
        return NGHTTP2_TOKEN_ALLOW;
195
66
      }
196
67
      break;
197
472
    }
198
269
    break;
199
531
  case 6:
200
531
    switch (name[5]) {
201
132
    case 'e':
202
132
      if (memeq("cooki", name, 5)) {
203
66
        return NGHTTP2_TOKEN_COOKIE;
204
66
      }
205
66
      break;
206
132
    case 'r':
207
132
      if (memeq("serve", name, 5)) {
208
66
        return NGHTTP2_TOKEN_SERVER;
209
66
      }
210
66
      break;
211
200
    case 't':
212
200
      if (memeq("accep", name, 5)) {
213
66
        return NGHTTP2_TOKEN_ACCEPT;
214
66
      }
215
134
      if (memeq("expec", name, 5)) {
216
66
        return NGHTTP2_TOKEN_EXPECT;
217
66
      }
218
68
      break;
219
531
    }
220
267
    break;
221
862
  case 7:
222
862
    switch (name[6]) {
223
132
    case 'd':
224
132
      if (memeq(":metho", name, 6)) {
225
66
        return NGHTTP2_TOKEN__METHOD;
226
66
      }
227
66
      break;
228
199
    case 'e':
229
199
      if (memeq(":schem", name, 6)) {
230
66
        return NGHTTP2_TOKEN__SCHEME;
231
66
      }
232
133
      if (memeq("upgrad", name, 6)) {
233
66
        return NGHTTP2_TOKEN_UPGRADE;
234
66
      }
235
67
      break;
236
133
    case 'h':
237
133
      if (memeq("refres", name, 6)) {
238
66
        return NGHTTP2_TOKEN_REFRESH;
239
66
      }
240
67
      break;
241
132
    case 'r':
242
132
      if (memeq("refere", name, 6)) {
243
66
        return NGHTTP2_TOKEN_REFERER;
244
66
      }
245
66
      break;
246
199
    case 's':
247
199
      if (memeq(":statu", name, 6)) {
248
66
        return NGHTTP2_TOKEN__STATUS;
249
66
      }
250
133
      if (memeq("expire", name, 6)) {
251
66
        return NGHTTP2_TOKEN_EXPIRES;
252
66
      }
253
67
      break;
254
862
    }
255
400
    break;
256
5.26k
  case 8:
257
5.26k
    switch (name[7]) {
258
132
    case 'e':
259
132
      if (memeq("if-rang", name, 7)) {
260
66
        return NGHTTP2_TOKEN_IF_RANGE;
261
66
      }
262
66
      break;
263
133
    case 'h':
264
133
      if (memeq("if-matc", name, 7)) {
265
66
        return NGHTTP2_TOKEN_IF_MATCH;
266
66
      }
267
67
      break;
268
134
    case 'n':
269
134
      if (memeq("locatio", name, 7)) {
270
66
        return NGHTTP2_TOKEN_LOCATION;
271
66
      }
272
68
      break;
273
4.29k
    case 'y':
274
4.29k
      if (memeq("priorit", name, 7)) {
275
4.22k
        return NGHTTP2_TOKEN_PRIORITY;
276
4.22k
      }
277
70
      break;
278
5.26k
    }
279
836
    break;
280
836
  case 9:
281
219
    switch (name[8]) {
282
145
    case 'l':
283
145
      if (memeq(":protoco", name, 8)) {
284
66
        return NGHTTP2_TOKEN__PROTOCOL;
285
66
      }
286
79
      break;
287
219
    }
288
153
    break;
289
709
  case 10:
290
709
    switch (name[9]) {
291
211
    case 'e':
292
211
      if (memeq("keep-aliv", name, 9)) {
293
66
        return NGHTTP2_TOKEN_KEEP_ALIVE;
294
66
      }
295
145
      if (memeq("set-cooki", name, 9)) {
296
66
        return NGHTTP2_TOKEN_SET_COOKIE;
297
66
      }
298
79
      break;
299
146
    case 'n':
300
146
      if (memeq("connectio", name, 9)) {
301
67
        return NGHTTP2_TOKEN_CONNECTION;
302
67
      }
303
79
      break;
304
142
    case 't':
305
142
      if (memeq("user-agen", name, 9)) {
306
66
        return NGHTTP2_TOKEN_USER_AGENT;
307
66
      }
308
76
      break;
309
144
    case 'y':
310
144
      if (memeq(":authorit", name, 9)) {
311
66
        return NGHTTP2_TOKEN__AUTHORITY;
312
66
      }
313
78
      break;
314
709
    }
315
378
    break;
316
378
  case 11:
317
215
    switch (name[10]) {
318
141
    case 'r':
319
141
      if (memeq("retry-afte", name, 10)) {
320
66
        return NGHTTP2_TOKEN_RETRY_AFTER;
321
66
      }
322
75
      break;
323
215
    }
324
149
    break;
325
347
  case 12:
326
347
    switch (name[11]) {
327
140
    case 'e':
328
140
      if (memeq("content-typ", name, 11)) {
329
66
        return NGHTTP2_TOKEN_CONTENT_TYPE;
330
66
      }
331
74
      break;
332
141
    case 's':
333
141
      if (memeq("max-forward", name, 11)) {
334
66
        return NGHTTP2_TOKEN_MAX_FORWARDS;
335
66
      }
336
75
      break;
337
347
    }
338
215
    break;
339
919
  case 13:
340
919
    switch (name[12]) {
341
147
    case 'd':
342
147
      if (memeq("last-modifie", name, 12)) {
343
66
        return NGHTTP2_TOKEN_LAST_MODIFIED;
344
66
      }
345
81
      break;
346
139
    case 'e':
347
139
      if (memeq("content-rang", name, 12)) {
348
66
        return NGHTTP2_TOKEN_CONTENT_RANGE;
349
66
      }
350
73
      break;
351
145
    case 'h':
352
145
      if (memeq("if-none-matc", name, 12)) {
353
66
        return NGHTTP2_TOKEN_IF_NONE_MATCH;
354
66
      }
355
79
      break;
356
144
    case 'l':
357
144
      if (memeq("cache-contro", name, 12)) {
358
66
        return NGHTTP2_TOKEN_CACHE_CONTROL;
359
66
      }
360
78
      break;
361
139
    case 'n':
362
139
      if (memeq("authorizatio", name, 12)) {
363
66
        return NGHTTP2_TOKEN_AUTHORIZATION;
364
66
      }
365
73
      break;
366
139
    case 's':
367
139
      if (memeq("accept-range", name, 12)) {
368
66
        return NGHTTP2_TOKEN_ACCEPT_RANGES;
369
66
      }
370
73
      break;
371
919
    }
372
523
    break;
373
523
  case 14:
374
347
    switch (name[13]) {
375
140
    case 'h':
376
140
      if (memeq("content-lengt", name, 13)) {
377
66
        return NGHTTP2_TOKEN_CONTENT_LENGTH;
378
66
      }
379
74
      break;
380
140
    case 't':
381
140
      if (memeq("accept-charse", name, 13)) {
382
66
        return NGHTTP2_TOKEN_ACCEPT_CHARSET;
383
66
      }
384
74
      break;
385
347
    }
386
215
    break;
387
362
  case 15:
388
362
    switch (name[14]) {
389
144
    case 'e':
390
144
      if (memeq("accept-languag", name, 14)) {
391
66
        return NGHTTP2_TOKEN_ACCEPT_LANGUAGE;
392
66
      }
393
78
      break;
394
140
    case 'g':
395
140
      if (memeq("accept-encodin", name, 14)) {
396
66
        return NGHTTP2_TOKEN_ACCEPT_ENCODING;
397
66
      }
398
74
      break;
399
362
    }
400
230
    break;
401
643
  case 16:
402
643
    switch (name[15]) {
403
220
    case 'e':
404
220
      if (memeq("content-languag", name, 15)) {
405
66
        return NGHTTP2_TOKEN_CONTENT_LANGUAGE;
406
66
      }
407
154
      if (memeq("www-authenticat", name, 15)) {
408
66
        return NGHTTP2_TOKEN_WWW_AUTHENTICATE;
409
66
      }
410
88
      break;
411
142
    case 'g':
412
142
      if (memeq("content-encodin", name, 15)) {
413
66
        return NGHTTP2_TOKEN_CONTENT_ENCODING;
414
66
      }
415
76
      break;
416
213
    case 'n':
417
213
      if (memeq("content-locatio", name, 15)) {
418
66
        return NGHTTP2_TOKEN_CONTENT_LOCATION;
419
66
      }
420
147
      if (memeq("proxy-connectio", name, 15)) {
421
66
        return NGHTTP2_TOKEN_PROXY_CONNECTION;
422
66
      }
423
81
      break;
424
643
    }
425
313
    break;
426
350
  case 17:
427
350
    switch (name[16]) {
428
146
    case 'e':
429
146
      if (memeq("if-modified-sinc", name, 16)) {
430
66
        return NGHTTP2_TOKEN_IF_MODIFIED_SINCE;
431
66
      }
432
80
      break;
433
138
    case 'g':
434
138
      if (memeq("transfer-encodin", name, 16)) {
435
66
        return NGHTTP2_TOKEN_TRANSFER_ENCODING;
436
66
      }
437
72
      break;
438
350
    }
439
218
    break;
440
218
  case 18:
441
202
    switch (name[17]) {
442
133
    case 'e':
443
133
      if (memeq("proxy-authenticat", name, 17)) {
444
66
        return NGHTTP2_TOKEN_PROXY_AUTHENTICATE;
445
66
      }
446
67
      break;
447
202
    }
448
136
    break;
449
419
  case 19:
450
419
    switch (name[18]) {
451
140
    case 'e':
452
140
      if (memeq("if-unmodified-sinc", name, 18)) {
453
66
        return NGHTTP2_TOKEN_IF_UNMODIFIED_SINCE;
454
66
      }
455
74
      break;
456
213
    case 'n':
457
213
      if (memeq("content-dispositio", name, 18)) {
458
66
        return NGHTTP2_TOKEN_CONTENT_DISPOSITION;
459
66
      }
460
147
      if (memeq("proxy-authorizatio", name, 18)) {
461
66
        return NGHTTP2_TOKEN_PROXY_AUTHORIZATION;
462
66
      }
463
81
      break;
464
419
    }
465
221
    break;
466
221
  case 25:
467
215
    switch (name[24]) {
468
146
    case 'y':
469
146
      if (memeq("strict-transport-securit", name, 24)) {
470
66
        return NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY;
471
66
      }
472
80
      break;
473
215
    }
474
149
    break;
475
218
  case 27:
476
218
    switch (name[26]) {
477
143
    case 'n':
478
143
      if (memeq("access-control-allow-origi", name, 26)) {
479
66
        return NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN;
480
66
      }
481
77
      break;
482
218
    }
483
152
    break;
484
18.8k
  }
485
9.75k
  return -1;
486
18.8k
}
487
488
17.9k
void nghttp2_hd_entry_init(nghttp2_hd_entry *ent, nghttp2_hd_nv *nv) {
489
17.9k
  ent->nv = *nv;
490
17.9k
  ent->cnv.name = nv->name->base;
491
17.9k
  ent->cnv.namelen = nv->name->len;
492
17.9k
  ent->cnv.value = nv->value->base;
493
17.9k
  ent->cnv.valuelen = nv->value->len;
494
17.9k
  ent->cnv.flags = nv->flags;
495
17.9k
  ent->next = NULL;
496
17.9k
  ent->hash = 0;
497
498
17.9k
  nghttp2_rcbuf_incref(ent->nv.name);
499
17.9k
  nghttp2_rcbuf_incref(ent->nv.value);
500
17.9k
}
501
502
17.9k
void nghttp2_hd_entry_free(nghttp2_hd_entry *ent) {
503
17.9k
  nghttp2_rcbuf_decref(ent->nv.value);
504
17.9k
  nghttp2_rcbuf_decref(ent->nv.name);
505
17.9k
}
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
11.0k
static void hd_map_init(nghttp2_hd_map *map) {
531
11.0k
  memset(map, 0, sizeof(nghttp2_hd_map));
532
11.0k
}
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
22.1k
                           nghttp2_mem *mem) {
596
22.1k
  size_t size;
597
22.1k
  const size_t max_size = SIZE_MAX / sizeof(nghttp2_hd_entry *);
598
599
22.1k
  if (bufsize > max_size) {
600
0
    return NGHTTP2_ERR_NOMEM;
601
0
  }
602
603
177k
  for (size = 1; size < bufsize; size <<= 1)
604
155k
    ;
605
606
22.1k
  if (size > max_size) {
607
0
    return NGHTTP2_ERR_NOMEM;
608
0
  }
609
610
22.1k
  ringbuf->buffer = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_entry *) * size);
611
22.1k
  if (ringbuf->buffer == NULL) {
612
0
    return NGHTTP2_ERR_NOMEM;
613
0
  }
614
22.1k
  ringbuf->mask = size - 1;
615
22.1k
  ringbuf->first = 0;
616
22.1k
  ringbuf->len = 0;
617
22.1k
  return 0;
618
22.1k
}
619
620
static nghttp2_hd_entry *hd_ringbuf_get(nghttp2_hd_ringbuf *ringbuf,
621
45.7k
                                        size_t idx) {
622
45.7k
  assert(idx < ringbuf->len);
623
45.7k
  return ringbuf->buffer[(ringbuf->first + idx) & ringbuf->mask];
624
45.7k
}
625
626
static int hd_ringbuf_reserve(nghttp2_hd_ringbuf *ringbuf, size_t bufsize,
627
17.9k
                              nghttp2_mem *mem) {
628
17.9k
  size_t i;
629
17.9k
  size_t size;
630
17.9k
  nghttp2_hd_entry **buffer;
631
632
17.9k
  if (ringbuf->mask + 1 >= bufsize) {
633
17.9k
    return 0;
634
17.9k
  }
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
22.1k
static void hd_ringbuf_free(nghttp2_hd_ringbuf *ringbuf, nghttp2_mem *mem) {
652
22.1k
  size_t i;
653
22.1k
  if (ringbuf == NULL) {
654
0
    return;
655
0
  }
656
38.8k
  for (i = 0; i < ringbuf->len; ++i) {
657
16.7k
    nghttp2_hd_entry *ent = hd_ringbuf_get(ringbuf, i);
658
659
16.7k
    nghttp2_hd_entry_free(ent);
660
16.7k
    nghttp2_mem_free(mem, ent);
661
16.7k
  }
662
22.1k
  nghttp2_mem_free(mem, ringbuf->buffer);
663
22.1k
}
664
665
static int hd_ringbuf_push_front(nghttp2_hd_ringbuf *ringbuf,
666
17.9k
                                 nghttp2_hd_entry *ent, nghttp2_mem *mem) {
667
17.9k
  int rv;
668
669
17.9k
  rv = hd_ringbuf_reserve(ringbuf, ringbuf->len + 1, mem);
670
671
17.9k
  if (rv != 0) {
672
0
    return rv;
673
0
  }
674
675
17.9k
  ringbuf->buffer[--ringbuf->first & ringbuf->mask] = ent;
676
17.9k
  ++ringbuf->len;
677
678
17.9k
  return 0;
679
17.9k
}
680
681
1.24k
static void hd_ringbuf_pop_back(nghttp2_hd_ringbuf *ringbuf) {
682
1.24k
  assert(ringbuf->len > 0);
683
1.24k
  --ringbuf->len;
684
1.24k
}
685
686
22.1k
static int hd_context_init(nghttp2_hd_context *context, nghttp2_mem *mem) {
687
22.1k
  int rv;
688
22.1k
  context->mem = mem;
689
22.1k
  context->bad = 0;
690
22.1k
  context->hd_table_bufsize_max = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
691
22.1k
  rv = hd_ringbuf_init(
692
22.1k
    &context->hd_table,
693
22.1k
    context->hd_table_bufsize_max / NGHTTP2_HD_ENTRY_OVERHEAD, mem);
694
22.1k
  if (rv != 0) {
695
0
    return rv;
696
0
  }
697
698
22.1k
  context->hd_table_bufsize = 0;
699
22.1k
  context->next_seq = 0;
700
701
22.1k
  return 0;
702
22.1k
}
703
704
22.1k
static void hd_context_free(nghttp2_hd_context *context) {
705
22.1k
  hd_ringbuf_free(&context->hd_table, context->mem);
706
22.1k
}
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
11.0k
                             nghttp2_mem *mem) {
716
11.0k
  int rv;
717
11.0k
  rv = hd_context_init(&deflater->ctx, mem);
718
11.0k
  if (rv != 0) {
719
0
    return rv;
720
0
  }
721
722
11.0k
  hd_map_init(&deflater->map);
723
724
11.0k
  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
11.0k
  } else {
728
11.0k
    deflater->notify_table_size_change = 0;
729
11.0k
  }
730
731
11.0k
  deflater->deflate_hd_table_bufsize_max = max_deflate_dynamic_table_size;
732
11.0k
  deflater->min_hd_table_bufsize_max = UINT32_MAX;
733
734
11.0k
  return 0;
735
11.0k
}
736
737
11.0k
int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem) {
738
11.0k
  int rv;
739
740
11.0k
  rv = hd_context_init(&inflater->ctx, mem);
741
11.0k
  if (rv != 0) {
742
0
    goto fail;
743
0
  }
744
745
11.0k
  inflater->settings_hd_table_bufsize_max = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
746
11.0k
  inflater->min_hd_table_bufsize_max = UINT32_MAX;
747
748
11.0k
  inflater->nv_name_keep = NULL;
749
11.0k
  inflater->nv_value_keep = NULL;
750
751
11.0k
  inflater->opcode = NGHTTP2_HD_OPCODE_NONE;
752
11.0k
  inflater->state = NGHTTP2_HD_STATE_INFLATE_START;
753
754
11.0k
  nghttp2_buf_init(&inflater->namebuf);
755
11.0k
  nghttp2_buf_init(&inflater->valuebuf);
756
757
11.0k
  inflater->namercbuf = NULL;
758
11.0k
  inflater->valuercbuf = NULL;
759
760
11.0k
  inflater->huffman_encoded = 0;
761
11.0k
  inflater->index = 0;
762
11.0k
  inflater->left = 0;
763
11.0k
  inflater->shift = 0;
764
11.0k
  inflater->index_required = 0;
765
11.0k
  inflater->no_index = 0;
766
767
11.0k
  return 0;
768
769
0
fail:
770
0
  return rv;
771
11.0k
}
772
773
102k
static void hd_inflate_keep_free(nghttp2_hd_inflater *inflater) {
774
102k
  nghttp2_rcbuf_decref(inflater->nv_value_keep);
775
102k
  nghttp2_rcbuf_decref(inflater->nv_name_keep);
776
777
102k
  inflater->nv_value_keep = NULL;
778
102k
  inflater->nv_name_keep = NULL;
779
102k
}
780
781
11.0k
void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater) {
782
11.0k
  hd_context_free(&deflater->ctx);
783
11.0k
}
784
785
11.0k
void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater) {
786
11.0k
  hd_inflate_keep_free(inflater);
787
788
11.0k
  nghttp2_rcbuf_decref(inflater->valuercbuf);
789
11.0k
  nghttp2_rcbuf_decref(inflater->namercbuf);
790
791
11.0k
  hd_context_free(&inflater->ctx);
792
11.0k
}
793
794
19.6k
static size_t entry_room(size_t namelen, size_t valuelen) {
795
19.6k
  return NGHTTP2_HD_ENTRY_OVERHEAD + namelen + valuelen;
796
19.6k
}
797
798
71.7k
static void emit_header(nghttp2_hd_nv *nv_out, nghttp2_hd_nv *nv) {
799
71.7k
  DEBUGF("inflatehd: header emission: %s: %s\n", nv->name->base,
800
71.7k
         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
71.7k
  *nv_out = *nv;
804
71.7k
}
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
107k
                                   size_t prefix) {
869
107k
  uint32_t k = (uint8_t)((1 << prefix) - 1);
870
107k
  uint32_t n = initial;
871
107k
  const uint8_t *start = in;
872
873
107k
  *shift_ptr = 0;
874
107k
  *fin = 0;
875
876
107k
  if (n == 0) {
877
106k
    if ((*in & k) != k) {
878
102k
      *res = (*in) & k;
879
102k
      *fin = 1;
880
102k
      return 1;
881
102k
    }
882
883
3.80k
    n = k;
884
885
3.80k
    if (++in == last) {
886
94
      *res = n;
887
94
      return (nghttp2_ssize)(in - start);
888
94
    }
889
3.80k
  }
890
891
11.5k
  for (; in != last; ++in, shift += 7) {
892
10.4k
    uint32_t add = *in & 0x7f;
893
894
10.4k
    if (shift >= 32) {
895
25
      DEBUGF("inflate: shift exponent overflow\n");
896
25
      return -1;
897
25
    }
898
899
10.4k
    if ((UINT32_MAX >> shift) < add) {
900
26
      DEBUGF("inflate: integer overflow on shift\n");
901
26
      return -1;
902
26
    }
903
904
10.4k
    add <<= shift;
905
906
10.4k
    if (UINT32_MAX - add < n) {
907
44
      DEBUGF("inflate: integer overflow on addition\n");
908
44
      return -1;
909
44
    }
910
911
10.3k
    n += add;
912
913
10.3k
    if ((*in & (1 << 7)) == 0) {
914
3.19k
      break;
915
3.19k
    }
916
10.3k
  }
917
918
4.25k
  *shift_ptr = shift;
919
920
4.25k
  if (in == last) {
921
1.06k
    *res = n;
922
1.06k
    return (nghttp2_ssize)(in - start);
923
1.06k
  }
924
925
3.19k
  *res = n;
926
3.19k
  *fin = 1;
927
3.19k
  return (nghttp2_ssize)(in + 1 - start);
928
4.25k
}
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
18.3k
                                    uint32_t hash) {
1116
18.3k
  int rv;
1117
18.3k
  nghttp2_hd_entry *new_ent;
1118
18.3k
  size_t room;
1119
18.3k
  nghttp2_mem *mem;
1120
1121
18.3k
  mem = context->mem;
1122
18.3k
  room = entry_room(nv->name->len, nv->value->len);
1123
1124
19.4k
  while (context->hd_table_bufsize + room > context->hd_table_bufsize_max &&
1125
1.47k
         context->hd_table.len > 0) {
1126
1.07k
    size_t idx = context->hd_table.len - 1;
1127
1.07k
    nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, idx);
1128
1129
1.07k
    context->hd_table_bufsize -=
1130
1.07k
      entry_room(ent->nv.name->len, ent->nv.value->len);
1131
1132
1.07k
    DEBUGF("hpack: remove item from header table: %s: %s\n",
1133
1.07k
           (char *)ent->nv.name->base, (char *)ent->nv.value->base);
1134
1135
1.07k
    hd_ringbuf_pop_back(&context->hd_table);
1136
1.07k
    if (map) {
1137
0
      hd_map_remove(map, ent);
1138
0
    }
1139
1140
1.07k
    nghttp2_hd_entry_free(ent);
1141
1.07k
    nghttp2_mem_free(mem, ent);
1142
1.07k
  }
1143
1144
18.3k
  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
402
    return 0;
1148
402
  }
1149
1150
17.9k
  new_ent = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_entry));
1151
17.9k
  if (new_ent == NULL) {
1152
0
    return NGHTTP2_ERR_NOMEM;
1153
0
  }
1154
1155
17.9k
  nghttp2_hd_entry_init(new_ent, nv);
1156
1157
17.9k
  rv = hd_ringbuf_push_front(&context->hd_table, new_ent, mem);
1158
1159
17.9k
  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
17.9k
  new_ent->seq = context->next_seq++;
1167
17.9k
  new_ent->hash = hash;
1168
1169
17.9k
  if (map) {
1170
0
    hd_map_insert(map, new_ent);
1171
0
  }
1172
1173
17.9k
  context->hd_table_bufsize += room;
1174
1175
17.9k
  return 0;
1176
17.9k
}
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
1.96k
                                         nghttp2_hd_map *map) {
1237
1.96k
  nghttp2_mem *mem;
1238
1239
1.96k
  mem = context->mem;
1240
1241
2.14k
  while (context->hd_table_bufsize > context->hd_table_bufsize_max &&
1242
176
         context->hd_table.len > 0) {
1243
176
    size_t idx = context->hd_table.len - 1;
1244
176
    nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, idx);
1245
176
    context->hd_table_bufsize -=
1246
176
      entry_room(ent->nv.name->len, ent->nv.value->len);
1247
176
    hd_ringbuf_pop_back(&context->hd_table);
1248
176
    if (map) {
1249
0
      hd_map_remove(map, ent);
1250
0
    }
1251
1252
176
    nghttp2_hd_entry_free(ent);
1253
176
    nghttp2_mem_free(mem, ent);
1254
176
  }
1255
1.96k
}
1256
1257
int nghttp2_hd_deflate_change_table_size(
1258
615
  nghttp2_hd_deflater *deflater, size_t settings_max_dynamic_table_size) {
1259
615
  size_t next_bufsize = nghttp2_min_size(
1260
615
    settings_max_dynamic_table_size, deflater->deflate_hd_table_bufsize_max);
1261
1262
615
  deflater->ctx.hd_table_bufsize_max = next_bufsize;
1263
1264
615
  deflater->min_hd_table_bufsize_max =
1265
615
    nghttp2_min_size(deflater->min_hd_table_bufsize_max, next_bufsize);
1266
1267
615
  deflater->notify_table_size_change = 1;
1268
1269
615
  hd_context_shrink_table_size(&deflater->ctx, &deflater->map);
1270
615
  return 0;
1271
615
}
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
53.9k
static size_t get_max_index(nghttp2_hd_context *context) {
1310
53.9k
  return context->hd_table.len + NGHTTP2_STATIC_TABLE_LENGTH;
1311
53.9k
}
1312
1313
52.8k
nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t idx) {
1314
52.8k
  assert(INDEX_RANGE_VALID(context, idx));
1315
52.8k
  if (idx >= NGHTTP2_STATIC_TABLE_LENGTH) {
1316
27.8k
    return hd_ringbuf_get(&context->hd_table, idx - NGHTTP2_STATIC_TABLE_LENGTH)
1317
27.8k
      ->nv;
1318
27.8k
  } else {
1319
25.0k
    const nghttp2_hd_static_entry *ent = &static_table[idx];
1320
25.0k
    nghttp2_hd_nv nv = {(nghttp2_rcbuf *)&ent->name,
1321
25.0k
                        (nghttp2_rcbuf *)&ent->value, ent->token,
1322
25.0k
                        NGHTTP2_NV_FLAG_NONE};
1323
25.0k
    return nv;
1324
25.0k
  }
1325
52.8k
}
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
51.3k
                                           const uint8_t *in) {
1651
51.3k
  inflater->huffman_encoded = (*in & (1 << 7)) != 0;
1652
51.3k
}
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
107k
                                         size_t maxlen) {
1671
107k
  nghttp2_ssize rv;
1672
107k
  uint32_t out;
1673
1674
107k
  *rfin = 0;
1675
1676
107k
  rv = decode_length(&out, &inflater->shift, rfin, (uint32_t)inflater->left,
1677
107k
                     inflater->shift, in, last, prefix);
1678
1679
107k
  if (rv == -1) {
1680
95
    DEBUGF("inflatehd: integer decoding failed\n");
1681
95
    return NGHTTP2_ERR_HEADER_COMP;
1682
95
  }
1683
1684
107k
  if (out > maxlen) {
1685
782
    DEBUGF("inflatehd: integer exceeded the maximum value %zu\n", maxlen);
1686
782
    return NGHTTP2_ERR_HEADER_COMP;
1687
782
  }
1688
1689
106k
  inflater->left = out;
1690
1691
106k
  DEBUGF("inflatehd: decoded integer is %u\n", out);
1692
1693
106k
  return rv;
1694
107k
}
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
15.8k
                                          const uint8_t *last) {
1712
15.8k
  nghttp2_ssize readlen;
1713
15.8k
  int fin = 0;
1714
15.8k
  if ((size_t)(last - in) >= inflater->left) {
1715
15.6k
    last = in + inflater->left;
1716
15.6k
    fin = 1;
1717
15.6k
  }
1718
15.8k
  readlen = nghttp2_hd_huff_decode(&inflater->huff_decode_ctx, buf, in,
1719
15.8k
                                   (size_t)(last - in), fin);
1720
1721
15.8k
  if (readlen < 0) {
1722
7
    DEBUGF("inflatehd: huffman decoding failed\n");
1723
7
    return readlen;
1724
7
  }
1725
15.8k
  if (nghttp2_hd_huff_decode_failure_state(&inflater->huff_decode_ctx)) {
1726
8
    DEBUGF("inflatehd: huffman decoding failed\n");
1727
8
    return NGHTTP2_ERR_HEADER_COMP;
1728
8
  }
1729
1730
15.7k
  inflater->left -= (size_t)readlen;
1731
15.7k
  return readlen;
1732
15.8k
}
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
35.1k
                                     const uint8_t *last) {
1749
35.1k
  size_t len = nghttp2_min_size((size_t)(last - in), inflater->left);
1750
1751
35.1k
  buf->last = nghttp2_cpymem(buf->last, in, len);
1752
1753
35.1k
  inflater->left -= len;
1754
35.1k
  return (nghttp2_ssize)len;
1755
35.1k
}
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
39.9k
                                      nghttp2_hd_nv *nv_out) {
1763
39.9k
  nghttp2_hd_nv nv = nghttp2_hd_table_get(&inflater->ctx, inflater->index);
1764
1765
39.9k
  emit_header(nv_out, &nv);
1766
39.9k
}
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
18.8k
                                     nghttp2_hd_nv *nv_out) {
1781
18.8k
  nghttp2_hd_nv nv;
1782
18.8k
  int rv;
1783
1784
18.8k
  if (inflater->no_index) {
1785
865
    nv.flags = NGHTTP2_NV_FLAG_NO_INDEX;
1786
17.9k
  } else {
1787
17.9k
    nv.flags = NGHTTP2_NV_FLAG_NONE;
1788
17.9k
  }
1789
1790
18.8k
  nv.name = inflater->namercbuf;
1791
18.8k
  nv.value = inflater->valuercbuf;
1792
18.8k
  nv.token = lookup_token(inflater->namercbuf->base, inflater->namercbuf->len);
1793
1794
18.8k
  if (inflater->index_required) {
1795
8.14k
    rv = add_hd_table_incremental(&inflater->ctx, &nv, NULL, 0);
1796
1797
8.14k
    if (rv != 0) {
1798
0
      return rv;
1799
0
    }
1800
8.14k
  }
1801
1802
18.8k
  emit_header(nv_out, &nv);
1803
1804
18.8k
  inflater->nv_name_keep = nv.name;
1805
18.8k
  inflater->nv_value_keep = nv.value;
1806
1807
18.8k
  inflater->namercbuf = NULL;
1808
18.8k
  inflater->valuercbuf = NULL;
1809
1810
18.8k
  return 0;
1811
18.8k
}
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
12.9k
                                     nghttp2_hd_nv *nv_out) {
1826
12.9k
  nghttp2_hd_nv nv;
1827
12.9k
  int rv;
1828
1829
12.9k
  nv = nghttp2_hd_table_get(&inflater->ctx, inflater->index);
1830
1831
12.9k
  if (inflater->no_index) {
1832
451
    nv.flags = NGHTTP2_NV_FLAG_NO_INDEX;
1833
12.4k
  } else {
1834
12.4k
    nv.flags = NGHTTP2_NV_FLAG_NONE;
1835
12.4k
  }
1836
1837
12.9k
  nghttp2_rcbuf_incref(nv.name);
1838
1839
12.9k
  nv.value = inflater->valuercbuf;
1840
1841
12.9k
  if (inflater->index_required) {
1842
10.2k
    rv = add_hd_table_incremental(&inflater->ctx, &nv, NULL, 0);
1843
10.2k
    if (rv != 0) {
1844
0
      nghttp2_rcbuf_decref(nv.name);
1845
0
      return NGHTTP2_ERR_NOMEM;
1846
0
    }
1847
10.2k
  }
1848
1849
12.9k
  emit_header(nv_out, &nv);
1850
1851
12.9k
  inflater->nv_name_keep = nv.name;
1852
12.9k
  inflater->nv_value_keep = nv.value;
1853
1854
12.9k
  inflater->valuercbuf = NULL;
1855
1856
12.9k
  return 0;
1857
12.9k
}
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
85.8k
                                       size_t inlen, int in_final) {
1904
85.8k
  nghttp2_ssize rv = 0;
1905
85.8k
  const uint8_t *first = in;
1906
85.8k
  const uint8_t *last = in + inlen;
1907
85.8k
  int rfin = 0;
1908
85.8k
  int busy = 0;
1909
85.8k
  nghttp2_mem *mem;
1910
1911
85.8k
  mem = inflater->ctx.mem;
1912
1913
85.8k
  if (inflater->ctx.bad) {
1914
0
    return NGHTTP2_ERR_HEADER_COMP;
1915
0
  }
1916
1917
85.8k
  DEBUGF("inflatehd: start state=%d\n", inflater->state);
1918
85.8k
  hd_inflate_keep_free(inflater);
1919
85.8k
  *inflate_flags = NGHTTP2_HD_INFLATE_NONE;
1920
244k
  for (; in != last || busy;) {
1921
232k
    busy = 0;
1922
232k
    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
14.4k
    case NGHTTP2_HD_STATE_INFLATE_START:
1933
74.4k
    case NGHTTP2_HD_STATE_OPCODE:
1934
74.4k
      if ((*in & 0xe0u) == 0x20u) {
1935
1.60k
        DEBUGF("inflatehd: header table size change\n");
1936
1.60k
        if (inflater->state == NGHTTP2_HD_STATE_OPCODE) {
1937
10
          DEBUGF("inflatehd: header table size change must appear at the head "
1938
10
                 "of header block\n");
1939
10
          rv = NGHTTP2_ERR_HEADER_COMP;
1940
10
          goto fail;
1941
10
        }
1942
1.59k
        inflater->opcode = NGHTTP2_HD_OPCODE_INDEXED;
1943
1.59k
        inflater->state = NGHTTP2_HD_STATE_READ_TABLE_SIZE;
1944
72.8k
      } else if (*in & 0x80u) {
1945
40.1k
        DEBUGF("inflatehd: indexed repr\n");
1946
40.1k
        inflater->opcode = NGHTTP2_HD_OPCODE_INDEXED;
1947
40.1k
        inflater->state = NGHTTP2_HD_STATE_READ_INDEX;
1948
40.1k
      } else {
1949
32.6k
        if (*in == 0x40u || *in == 0 || *in == 0x10u) {
1950
19.2k
          DEBUGF("inflatehd: literal header repr - new name\n");
1951
19.2k
          inflater->opcode = NGHTTP2_HD_OPCODE_NEWNAME;
1952
19.2k
          inflater->state = NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN;
1953
19.2k
        } else {
1954
13.4k
          DEBUGF("inflatehd: literal header repr - indexed name\n");
1955
13.4k
          inflater->opcode = NGHTTP2_HD_OPCODE_INDNAME;
1956
13.4k
          inflater->state = NGHTTP2_HD_STATE_READ_INDEX;
1957
13.4k
        }
1958
32.6k
        inflater->index_required = (*in & 0x40) != 0;
1959
32.6k
        inflater->no_index = (*in & 0xf0u) == 0x10u;
1960
32.6k
        DEBUGF("inflatehd: indexing required=%d, no_index=%d\n",
1961
32.6k
               inflater->index_required, inflater->no_index);
1962
32.6k
        if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) {
1963
19.2k
          ++in;
1964
19.2k
        }
1965
32.6k
      }
1966
74.4k
      inflater->left = 0;
1967
74.4k
      inflater->shift = 0;
1968
74.4k
      break;
1969
1.73k
    case NGHTTP2_HD_STATE_READ_TABLE_SIZE:
1970
1.73k
      rfin = 0;
1971
1.73k
      rv = hd_inflate_read_len(
1972
1.73k
        inflater, &rfin, in, last, 5,
1973
1.73k
        nghttp2_min_size(inflater->min_hd_table_bufsize_max,
1974
1.73k
                         inflater->settings_hd_table_bufsize_max));
1975
1.73k
      if (rv < 0) {
1976
202
        goto fail;
1977
202
      }
1978
1.53k
      in += rv;
1979
1.53k
      if (!rfin) {
1980
182
        goto almost_ok;
1981
182
      }
1982
1.35k
      DEBUGF("inflatehd: table_size=%zu\n", inflater->left);
1983
1.35k
      inflater->min_hd_table_bufsize_max = UINT32_MAX;
1984
1.35k
      inflater->ctx.hd_table_bufsize_max = inflater->left;
1985
1.35k
      hd_context_shrink_table_size(&inflater->ctx, NULL);
1986
1.35k
      inflater->state = NGHTTP2_HD_STATE_INFLATE_START;
1987
1.35k
      break;
1988
53.9k
    case NGHTTP2_HD_STATE_READ_INDEX: {
1989
53.9k
      size_t prefixlen;
1990
1991
53.9k
      if (inflater->opcode == NGHTTP2_HD_OPCODE_INDEXED) {
1992
40.1k
        prefixlen = 7;
1993
40.1k
      } else if (inflater->index_required) {
1994
10.4k
        prefixlen = 6;
1995
10.4k
      } else {
1996
3.31k
        prefixlen = 4;
1997
3.31k
      }
1998
1999
53.9k
      rfin = 0;
2000
53.9k
      rv = hd_inflate_read_len(inflater, &rfin, in, last, prefixlen,
2001
53.9k
                               get_max_index(&inflater->ctx));
2002
53.9k
      if (rv < 0) {
2003
353
        goto fail;
2004
353
      }
2005
2006
53.5k
      in += rv;
2007
2008
53.5k
      if (!rfin) {
2009
283
        goto almost_ok;
2010
283
      }
2011
2012
53.2k
      if (inflater->left == 0) {
2013
8
        rv = NGHTTP2_ERR_HEADER_COMP;
2014
8
        goto fail;
2015
8
      }
2016
2017
53.2k
      DEBUGF("inflatehd: index=%zu\n", inflater->left);
2018
53.2k
      if (inflater->opcode == NGHTTP2_HD_OPCODE_INDEXED) {
2019
39.9k
        inflater->index = inflater->left;
2020
39.9k
        --inflater->index;
2021
2022
39.9k
        hd_inflate_commit_indexed(inflater, nv_out);
2023
2024
39.9k
        inflater->state = NGHTTP2_HD_STATE_OPCODE;
2025
39.9k
        *inflate_flags |= NGHTTP2_HD_INFLATE_EMIT;
2026
39.9k
        return (nghttp2_ssize)(in - first);
2027
39.9k
      } else {
2028
13.2k
        inflater->index = inflater->left;
2029
13.2k
        --inflater->index;
2030
2031
13.2k
        inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN;
2032
13.2k
      }
2033
13.2k
      break;
2034
53.2k
    }
2035
19.2k
    case NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN:
2036
19.2k
      hd_inflate_set_huffman_encoded(inflater, in);
2037
19.2k
      inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN;
2038
19.2k
      inflater->left = 0;
2039
19.2k
      inflater->shift = 0;
2040
19.2k
      DEBUGF("inflatehd: huffman encoded=%d\n", inflater->huffman_encoded != 0);
2041
    /* Fall through */
2042
19.3k
    case NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN:
2043
19.3k
      rfin = 0;
2044
19.3k
      rv = hd_inflate_read_len(inflater, &rfin, in, last, 7, NGHTTP2_HD_MAX_NV);
2045
19.3k
      if (rv < 0) {
2046
155
        goto fail;
2047
155
      }
2048
19.1k
      in += rv;
2049
19.1k
      if (!rfin) {
2050
147
        DEBUGF("inflatehd: integer not fully decoded. current=%zu\n",
2051
147
               inflater->left);
2052
2053
147
        goto almost_ok;
2054
147
      }
2055
2056
19.0k
      if (inflater->huffman_encoded) {
2057
7.60k
        nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx);
2058
2059
7.60k
        inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF;
2060
2061
7.60k
        rv =
2062
7.60k
          nghttp2_rcbuf_new(&inflater->namercbuf, inflater->left * 2 + 1, mem);
2063
11.4k
      } else {
2064
11.4k
        inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAME;
2065
11.4k
        rv = nghttp2_rcbuf_new(&inflater->namercbuf, inflater->left + 1, mem);
2066
11.4k
      }
2067
2068
19.0k
      if (rv != 0) {
2069
0
        goto fail;
2070
0
      }
2071
2072
19.0k
      nghttp2_buf_wrap_init(&inflater->namebuf, inflater->namercbuf->base,
2073
19.0k
                            inflater->namercbuf->len);
2074
2075
19.0k
      break;
2076
7.59k
    case NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF:
2077
7.59k
      rv = hd_inflate_read_huff(inflater, &inflater->namebuf, in, last);
2078
7.59k
      if (rv < 0) {
2079
9
        goto fail;
2080
9
      }
2081
2082
7.58k
      in += rv;
2083
2084
7.58k
      DEBUGF("inflatehd: %td bytes read\n", rv);
2085
2086
7.58k
      if (inflater->left) {
2087
44
        DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left);
2088
2089
44
        goto almost_ok;
2090
44
      }
2091
2092
7.54k
      *inflater->namebuf.last = '\0';
2093
7.54k
      inflater->namercbuf->len = nghttp2_buf_len(&inflater->namebuf);
2094
2095
7.54k
      inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN;
2096
2097
7.54k
      break;
2098
11.3k
    case NGHTTP2_HD_STATE_NEWNAME_READ_NAME:
2099
11.3k
      rv = hd_inflate_read(inflater, &inflater->namebuf, in, last);
2100
11.3k
      if (rv < 0) {
2101
0
        goto fail;
2102
0
      }
2103
2104
11.3k
      in += rv;
2105
2106
11.3k
      DEBUGF("inflatehd: %td bytes read\n", rv);
2107
11.3k
      if (inflater->left) {
2108
45
        DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left);
2109
2110
45
        goto almost_ok;
2111
45
      }
2112
2113
11.3k
      *inflater->namebuf.last = '\0';
2114
11.3k
      inflater->namercbuf->len = nghttp2_buf_len(&inflater->namebuf);
2115
2116
11.3k
      inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN;
2117
2118
11.3k
      break;
2119
32.1k
    case NGHTTP2_HD_STATE_CHECK_VALUELEN:
2120
32.1k
      hd_inflate_set_huffman_encoded(inflater, in);
2121
32.1k
      inflater->state = NGHTTP2_HD_STATE_READ_VALUELEN;
2122
32.1k
      inflater->left = 0;
2123
32.1k
      inflater->shift = 0;
2124
32.1k
      DEBUGF("inflatehd: huffman encoded=%d\n", inflater->huffman_encoded != 0);
2125
    /* Fall through */
2126
32.2k
    case NGHTTP2_HD_STATE_READ_VALUELEN:
2127
32.2k
      rfin = 0;
2128
32.2k
      rv = hd_inflate_read_len(inflater, &rfin, in, last, 7, NGHTTP2_HD_MAX_NV);
2129
32.2k
      if (rv < 0) {
2130
167
        goto fail;
2131
167
      }
2132
2133
32.0k
      in += rv;
2134
2135
32.0k
      if (!rfin) {
2136
178
        goto almost_ok;
2137
178
      }
2138
2139
31.9k
      DEBUGF("inflatehd: valuelen=%zu\n", inflater->left);
2140
2141
31.9k
      if (inflater->huffman_encoded) {
2142
8.19k
        nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx);
2143
2144
8.19k
        inflater->state = NGHTTP2_HD_STATE_READ_VALUEHUFF;
2145
2146
8.19k
        rv =
2147
8.19k
          nghttp2_rcbuf_new(&inflater->valuercbuf, inflater->left * 2 + 1, mem);
2148
23.7k
      } else {
2149
23.7k
        inflater->state = NGHTTP2_HD_STATE_READ_VALUE;
2150
2151
23.7k
        rv = nghttp2_rcbuf_new(&inflater->valuercbuf, inflater->left + 1, mem);
2152
23.7k
      }
2153
2154
31.9k
      if (rv != 0) {
2155
0
        goto fail;
2156
0
      }
2157
2158
31.9k
      nghttp2_buf_wrap_init(&inflater->valuebuf, inflater->valuercbuf->base,
2159
31.9k
                            inflater->valuercbuf->len);
2160
2161
31.9k
      busy = 1;
2162
2163
31.9k
      break;
2164
8.21k
    case NGHTTP2_HD_STATE_READ_VALUEHUFF:
2165
8.21k
      rv = hd_inflate_read_huff(inflater, &inflater->valuebuf, in, last);
2166
8.21k
      if (rv < 0) {
2167
6
        goto fail;
2168
6
      }
2169
2170
8.20k
      in += rv;
2171
2172
8.20k
      DEBUGF("inflatehd: %td bytes read\n", rv);
2173
2174
8.20k
      if (inflater->left) {
2175
81
        DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left);
2176
2177
81
        goto almost_ok;
2178
81
      }
2179
2180
8.12k
      *inflater->valuebuf.last = '\0';
2181
8.12k
      inflater->valuercbuf->len = nghttp2_buf_len(&inflater->valuebuf);
2182
2183
8.12k
      if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) {
2184
2.81k
        rv = hd_inflate_commit_newname(inflater, nv_out);
2185
5.31k
      } else {
2186
5.31k
        rv = hd_inflate_commit_indname(inflater, nv_out);
2187
5.31k
      }
2188
2189
8.12k
      if (rv != 0) {
2190
0
        goto fail;
2191
0
      }
2192
2193
8.12k
      inflater->state = NGHTTP2_HD_STATE_OPCODE;
2194
8.12k
      *inflate_flags |= NGHTTP2_HD_INFLATE_EMIT;
2195
2196
8.12k
      return (nghttp2_ssize)(in - first);
2197
23.7k
    case NGHTTP2_HD_STATE_READ_VALUE:
2198
23.7k
      rv = hd_inflate_read(inflater, &inflater->valuebuf, in, last);
2199
23.7k
      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
23.7k
      in += rv;
2206
2207
23.7k
      DEBUGF("inflatehd: %td bytes read\n", rv);
2208
2209
23.7k
      if (inflater->left) {
2210
86
        DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left);
2211
86
        goto almost_ok;
2212
86
      }
2213
2214
23.6k
      *inflater->valuebuf.last = '\0';
2215
23.6k
      inflater->valuercbuf->len = nghttp2_buf_len(&inflater->valuebuf);
2216
2217
23.6k
      if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) {
2218
16.0k
        rv = hd_inflate_commit_newname(inflater, nv_out);
2219
16.0k
      } else {
2220
7.60k
        rv = hd_inflate_commit_indname(inflater, nv_out);
2221
7.60k
      }
2222
2223
23.6k
      if (rv != 0) {
2224
0
        goto fail;
2225
0
      }
2226
2227
23.6k
      inflater->state = NGHTTP2_HD_STATE_OPCODE;
2228
23.6k
      *inflate_flags |= NGHTTP2_HD_INFLATE_EMIT;
2229
2230
23.6k
      return (nghttp2_ssize)(in - first);
2231
232k
    }
2232
232k
  }
2233
2234
85.8k
  assert(in == last);
2235
2236
12.1k
  DEBUGF("inflatehd: all input bytes were processed\n");
2237
2238
12.1k
  if (in_final) {
2239
5.88k
    DEBUGF("inflatehd: in_final set\n");
2240
2241
5.88k
    if (inflater->state != NGHTTP2_HD_STATE_OPCODE &&
2242
927
        inflater->state != NGHTTP2_HD_STATE_INFLATE_START) {
2243
6
      DEBUGF("inflatehd: unacceptable state=%d\n", inflater->state);
2244
6
      rv = NGHTTP2_ERR_HEADER_COMP;
2245
2246
6
      goto fail;
2247
6
    }
2248
5.88k
    *inflate_flags |= NGHTTP2_HD_INFLATE_FINAL;
2249
5.88k
  }
2250
12.1k
  return (nghttp2_ssize)(in - first);
2251
2252
1.04k
almost_ok:
2253
1.04k
  if (in_final) {
2254
15
    DEBUGF("inflatehd: input ended prematurely\n");
2255
2256
15
    rv = NGHTTP2_ERR_HEADER_COMP;
2257
2258
15
    goto fail;
2259
15
  }
2260
1.03k
  return (nghttp2_ssize)(in - first);
2261
2262
931
fail:
2263
931
  DEBUGF("inflatehd: error return %td\n", rv);
2264
2265
931
  inflater->ctx.bad = 1;
2266
931
  return rv;
2267
1.04k
}
2268
2269
5.88k
int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater) {
2270
5.88k
  hd_inflate_keep_free(inflater);
2271
5.88k
  inflater->state = NGHTTP2_HD_STATE_INFLATE_START;
2272
5.88k
  return 0;
2273
5.88k
}
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
}