Coverage Report

Created: 2026-07-30 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/h2o/lib/http2/hpack.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Fastly, Inc.
3
 *
4
 * Permission is hereby granted, free of charge, to any person obtaining a copy
5
 * of this software and associated documentation files (the "Software"), to
6
 * deal in the Software without restriction, including without limitation the
7
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8
 * sell copies of the Software, and to permit persons to whom the Software is
9
 * furnished to do so, subject to the following conditions:
10
 *
11
 * The above copyright notice and this permission notice shall be included in
12
 * all copies or substantial portions of the Software.
13
 *
14
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20
 * IN THE SOFTWARE.
21
 */
22
#include <stddef.h>
23
#include <stdint.h>
24
#include <stdio.h>
25
#include <stdlib.h>
26
#include "h2o/hpack.h"
27
#include "h2o/http2_common.h"
28
29
235k
#define HEADER_TABLE_OFFSET 62
30
38.5k
#define HEADER_TABLE_ENTRY_SIZE_OFFSET 32
31
8.22k
#define DYNAMIC_TABLE_SIZE_UPDATE_MAX_SIZE 5
32
8.22k
#define STATUS_HEADER_MAX_SIZE 5
33
#define CONTENT_LENGTH_HEADER_MAX_SIZE                                                                                             \
34
7.51k
    (3 + sizeof(H2O_SIZE_T_LONGEST_STR) - 1) /* uses Literal Header Field without Indexing (RFC7541 6.2.2) */
35
36
#include "hpack_huffman_table.h"
37
38
static inline int value_is_part_of_static_table(const h2o_iovec_t *value)
39
40.5k
{
40
40.5k
    return &h2o_hpack_static_table[0].value <= value &&
41
40.5k
           value <= &h2o_hpack_static_table[sizeof(h2o_hpack_static_table) / sizeof(h2o_hpack_static_table[0]) - 1].value;
42
40.5k
}
43
44
static h2o_iovec_t *alloc_buf(h2o_mem_pool_t *pool, size_t len)
45
127k
{
46
127k
    h2o_iovec_t *buf = h2o_mem_alloc_shared(pool, sizeof(h2o_iovec_t) + len + 1, NULL);
47
127k
    buf->base = (char *)buf + sizeof(h2o_iovec_t);
48
127k
    buf->len = len;
49
127k
    return buf;
50
127k
}
51
52
int64_t h2o_hpack_decode_int(const uint8_t **src, const uint8_t *src_end, unsigned prefix_bits)
53
559k
{
54
559k
    uint64_t value;
55
559k
    unsigned shift;
56
559k
    uint8_t prefix_max = (1 << prefix_bits) - 1;
57
58
559k
    if (*src >= src_end)
59
5
        return H2O_HTTP2_ERROR_INCOMPLETE;
60
61
559k
    value = *(*src)++ & prefix_max;
62
559k
    if (value != prefix_max)
63
521k
        return (int64_t)value;
64
65
    /* decode upto 8 octets (excluding prefix), that are guaranteed not to cause overflow */
66
38.1k
    value = prefix_max;
67
62.8k
    for (shift = 0; shift < 56; shift += 7) {
68
62.1k
        if (*src == src_end)
69
183
            return H2O_HTTP2_ERROR_INCOMPLETE;
70
61.9k
        value += (uint64_t)(**src & 127) << shift;
71
61.9k
        if ((*(*src)++ & 128) == 0)
72
37.2k
            return (int64_t)value;
73
61.9k
    }
74
    /* handling the 9th octet */
75
769
    if (*src == src_end)
76
5
        return H2O_HTTP2_ERROR_INCOMPLETE;
77
764
    if ((**src & 128) != 0)
78
72
        return H2O_HTTP2_ERROR_COMPRESSION;
79
692
    value += (uint64_t)(*(*src)++ & 127) << shift;
80
692
    if (value > (uint64_t)INT64_MAX)
81
8
        return H2O_HTTP2_ERROR_COMPRESSION;
82
684
    return value;
83
692
}
84
85
static char *huffdecode4(char *dst, uint8_t in, uint8_t *state, int *maybe_eos, uint8_t *seen_char_types)
86
1.71M
{
87
1.71M
    const nghttp2_huff_decode *entry = huff_decode_table[*state] + in;
88
89
1.71M
    if ((entry->flags & NGHTTP2_HUFF_FAIL) != 0)
90
24
        return NULL;
91
1.71M
    if ((entry->flags & NGHTTP2_HUFF_SYM) != 0) {
92
1.12M
        *dst++ = entry->sym;
93
1.12M
        *seen_char_types |= (entry->flags & NGHTTP2_HUFF_INVALID_CHARS);
94
1.12M
    }
95
1.71M
    *state = entry->state;
96
1.71M
    *maybe_eos = (entry->flags & NGHTTP2_HUFF_ACCEPTED) != 0;
97
98
1.71M
    return dst;
99
1.71M
}
100
101
const char h2o_hpack_err_missing_mandatory_pseudo_header[] = "missing mandatory pseudo header";
102
const char h2o_hpack_err_invalid_pseudo_header[] = "invalid pseudo header";
103
const char h2o_hpack_err_found_upper_case_in_header_name[] = "found an upper-case letter in header name";
104
const char h2o_hpack_err_unexpected_connection_specific_header[] = "found an unexpected connection-specific header";
105
const char h2o_hpack_err_invalid_content_length_header[] = "invalid content-length header";
106
const char h2o_hpack_soft_err_found_invalid_char_in_header_name[] = "found an invalid character in header name";
107
const char h2o_hpack_soft_err_found_invalid_char_in_header_value[] = "found an invalid character in header value";
108
const char h2o_hpack_err_headers_too_long[] = "headers too long";
109
110
static int header_value_valid_as_whole(const char *s, size_t len)
111
129k
{
112
129k
    if (len != 0 && (s[0] == 0x20 || s[0] == 0x09 || s[len - 1] == 0x20 || s[len - 1] == 0x09))
113
4.20k
        return 0;
114
125k
    return 1;
115
129k
}
116
117
size_t h2o_hpack_decode_huffman(char *_dst, unsigned *soft_errors, const uint8_t *src, size_t len, int is_name,
118
                                const char **err_desc)
119
39.1k
{
120
39.1k
    char *dst = _dst;
121
39.1k
    const uint8_t *src_end = src + len;
122
39.1k
    uint8_t state = 0, seen_char_types = 0;
123
39.1k
    int maybe_eos = 1;
124
125
    /* decode */
126
895k
    for (; src < src_end; src++) {
127
856k
        if ((dst = huffdecode4(dst, *src >> 4, &state, &maybe_eos, &seen_char_types)) == NULL)
128
12
            return SIZE_MAX;
129
856k
        if ((dst = huffdecode4(dst, *src & 0xf, &state, &maybe_eos, &seen_char_types)) == NULL)
130
12
            return SIZE_MAX;
131
856k
    }
132
39.0k
    if (!maybe_eos)
133
240
        return SIZE_MAX;
134
135
    /* validate */
136
38.8k
    if (is_name) {
137
16.0k
        if (dst == _dst) {
138
1.26k
            *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_NAME;
139
14.8k
        } else {
140
            /* pseudo-headers are checked later in `decode_header` */
141
14.8k
            if ((seen_char_types & NGHTTP2_HUFF_INVALID_FOR_HEADER_NAME) != 0 && _dst[0] != ':') {
142
10.0k
                if ((seen_char_types & NGHTTP2_HUFF_UPPER_CASE_CHAR) != 0) {
143
0
                    *err_desc = h2o_hpack_err_found_upper_case_in_header_name;
144
0
                    return SIZE_MAX;
145
10.0k
                } else {
146
10.0k
                    *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_NAME;
147
10.0k
                }
148
10.0k
            }
149
14.8k
        }
150
22.7k
    } else {
151
22.7k
        if ((seen_char_types & NGHTTP2_HUFF_INVALID_FOR_HEADER_VALUE) != 0 || !header_value_valid_as_whole(_dst, dst - _dst))
152
1.52k
            *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_VALUE;
153
22.7k
    }
154
155
38.8k
    return dst - _dst;
156
38.8k
}
157
158
/* validate a header name against https://tools.ietf.org/html/rfc7230#section-3.2,
159
 * in addition to that, we disallow upper case chars as well.
160
 * This sets @err_desc for all invalid characters, but only returns true
161
 * for upper case characters, this is because we return a protocol error
162
 * in that case. */
163
int h2o_hpack_validate_header_name(unsigned *soft_errors, const char *s, size_t len, const char **err_desc)
164
68.0k
{
165
    /* all printable chars, except upper case and separator characters */
166
68.0k
    static const char valid_h2_header_name_char[] = {
167
68.0k
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*    0-31 */
168
68.0k
        0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /*   32-63 */
169
68.0k
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, /*   64-95 */
170
68.0k
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, /*  96-127 */
171
68.0k
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-159 */
172
68.0k
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 160-191 */
173
68.0k
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 192-223 */
174
68.0k
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 224-255 */
175
68.0k
    };
176
177
68.0k
    if (len == 0) {
178
26.0k
        *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_NAME;
179
41.9k
    } else {
180
482k
        for (; len != 0; ++s, --len) {
181
440k
            unsigned char ch = (unsigned char)*s;
182
440k
            if (!valid_h2_header_name_char[ch]) {
183
113k
                if (ch - 'A' < 26U) {
184
142
                    *err_desc = h2o_hpack_err_found_upper_case_in_header_name;
185
142
                    return 0;
186
142
                }
187
113k
                *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_NAME;
188
113k
            }
189
440k
        }
190
41.9k
    }
191
67.9k
    return 1;
192
68.0k
}
193
194
void h2o_hpack_validate_header_value(unsigned *soft_errors, const char *s, size_t len)
195
106k
{
196
    /* surrounding whitespace RFC 9113 8.2.1 */
197
106k
    if (!header_value_valid_as_whole(s, len))
198
3.10k
        goto Invalid;
199
200
    /* all printable chars + horizontal tab (RFC 7230 3.2) */
201
103k
    static const char valid_h2_field_value_char[] = {
202
103k
        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*    0-31 */
203
103k
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*   32-63 */
204
103k
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*   64-95 */
205
103k
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /*  96-127 */
206
103k
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 128-159 */
207
103k
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 160-191 */
208
103k
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 192-223 */
209
103k
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 224-255 */
210
103k
    };
211
212
395k
    for (; len != 0; ++s, --len) {
213
322k
        unsigned char ch = (unsigned char)*s;
214
322k
        if (!valid_h2_field_value_char[ch])
215
30.9k
            goto Invalid;
216
322k
    }
217
72.9k
    return;
218
219
72.9k
Invalid:
220
34.0k
    *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_VALUE;
221
34.0k
}
222
223
static h2o_iovec_t *decode_string(h2o_mem_pool_t *pool, unsigned *soft_errors, const uint8_t **src, const uint8_t *src_end,
224
                                  int is_header_name, const char **err_desc)
225
124k
{
226
124k
    h2o_iovec_t *ret;
227
124k
    int is_huffman;
228
124k
    int64_t len;
229
230
124k
    if (*src >= src_end)
231
496
        return NULL;
232
233
124k
    is_huffman = (**src & 0x80) != 0;
234
124k
    if ((len = h2o_hpack_decode_int(src, src_end, 7)) < 0)
235
35
        return NULL;
236
237
124k
    if (is_huffman) {
238
14.4k
        if (len > src_end - *src)
239
446
            return NULL;
240
14.0k
        ret = alloc_buf(pool, len * 2); /* max compression ratio is >= 0.5 */
241
14.0k
        if ((ret->len = h2o_hpack_decode_huffman(ret->base, soft_errors, *src, len, is_header_name, err_desc)) == SIZE_MAX)
242
108
            return NULL;
243
13.9k
        ret->base[ret->len] = '\0';
244
109k
    } else {
245
109k
        if (len > src_end - *src)
246
1.12k
            return NULL;
247
108k
        if (is_header_name) {
248
            /* pseudo-headers are checked later in `decode_header` */
249
46.6k
            if ((len == 0 || **src != (uint8_t)':') && !h2o_hpack_validate_header_name(soft_errors, (char *)*src, len, err_desc))
250
61
                return NULL;
251
61.9k
        } else {
252
61.9k
            h2o_hpack_validate_header_value(soft_errors, (char *)*src, len);
253
61.9k
        }
254
108k
        ret = alloc_buf(pool, len);
255
108k
        memcpy(ret->base, *src, len);
256
108k
        ret->base[len] = '\0';
257
108k
    }
258
122k
    *src += len;
259
260
122k
    return ret;
261
124k
}
262
263
static void header_table_evict_one(h2o_hpack_header_table_t *table)
264
7.66k
{
265
7.66k
    struct st_h2o_hpack_header_table_entry_t *entry;
266
7.66k
    assert(table->num_entries != 0);
267
268
7.66k
    entry = h2o_hpack_header_table_get(table, --table->num_entries);
269
7.66k
    table->hpack_size -= entry->name->len + entry->value->len + HEADER_TABLE_ENTRY_SIZE_OFFSET;
270
7.66k
    if (!h2o_iovec_is_token(entry->name))
271
1.43k
        h2o_mem_release_shared(entry->name);
272
7.66k
    if (!value_is_part_of_static_table(entry->value))
273
7.66k
        h2o_mem_release_shared(entry->value);
274
7.66k
    memset(entry, 0, sizeof(*entry));
275
7.66k
}
276
277
static struct st_h2o_hpack_header_table_entry_t *header_table_add(h2o_hpack_header_table_t *table, size_t size_add,
278
                                                                  size_t max_num_entries)
279
30.9k
{
280
    /* adjust the size */
281
33.8k
    while (table->num_entries != 0 && table->hpack_size + size_add > table->hpack_capacity)
282
2.94k
        header_table_evict_one(table);
283
30.9k
    while (max_num_entries <= table->num_entries)
284
0
        header_table_evict_one(table);
285
30.9k
    if (table->num_entries == 0) {
286
15.8k
        assert(table->hpack_size == 0);
287
15.8k
        if (size_add > table->hpack_capacity)
288
7.97k
            return NULL;
289
15.8k
    }
290
22.9k
    table->hpack_size += size_add;
291
292
    /* grow the entries if full */
293
22.9k
    if (table->num_entries == table->entry_capacity) {
294
6.41k
        size_t new_capacity = table->num_entries * 2;
295
6.41k
        if (new_capacity < 16)
296
6.19k
            new_capacity = 16;
297
6.41k
        struct st_h2o_hpack_header_table_entry_t *new_entries =
298
6.41k
            h2o_mem_alloc(new_capacity * sizeof(struct st_h2o_hpack_header_table_entry_t));
299
6.41k
        if (table->num_entries != 0) {
300
225
            size_t src_index = table->entry_start_index, dst_index = 0;
301
6.86k
            do {
302
6.86k
                new_entries[dst_index] = table->entries[src_index];
303
6.86k
                ++dst_index;
304
6.86k
                src_index = (src_index + 1) % table->entry_capacity;
305
6.86k
            } while (dst_index != table->num_entries);
306
225
        }
307
6.41k
        memset(new_entries + table->num_entries, 0, sizeof(*new_entries) * (new_capacity - table->num_entries));
308
6.41k
        free(table->entries);
309
6.41k
        table->entries = new_entries;
310
6.41k
        table->entry_capacity = new_capacity;
311
6.41k
        table->entry_start_index = 0;
312
6.41k
    }
313
314
22.9k
    ++table->num_entries;
315
22.9k
    table->entry_start_index = (table->entry_start_index + table->entry_capacity - 1) % table->entry_capacity;
316
22.9k
    return table->entries + table->entry_start_index;
317
30.9k
}
318
319
int h2o_hpack_decode_header(h2o_mem_pool_t *pool, void *_hpack_header_table, h2o_iovec_t **_name, h2o_iovec_t *_value,
320
                            const uint8_t **const src, const uint8_t *src_end, const char **err_desc)
321
175k
{
322
175k
    h2o_hpack_header_table_t *hpack_header_table = _hpack_header_table;
323
175k
    h2o_iovec_t *name = NULL, *value = NULL;
324
175k
    int64_t index = 0;
325
175k
    int value_is_indexed = 0, do_index = 0;
326
327
203k
Redo:
328
203k
    if (*src >= src_end)
329
78
        return H2O_HTTP2_ERROR_COMPRESSION;
330
331
    /* determine the mode and handle accordingly */
332
203k
    if (**src >= 128) {
333
        /* indexed header field representation */
334
97.7k
        if ((index = h2o_hpack_decode_int(src, src_end, 7)) <= 0)
335
82
            return H2O_HTTP2_ERROR_COMPRESSION;
336
97.6k
        value_is_indexed = 1;
337
105k
    } else if (**src >= 64) {
338
        /* literal header field with incremental handling */
339
25.5k
        if (**src == 64) {
340
5.45k
            ++*src;
341
20.1k
        } else if ((index = h2o_hpack_decode_int(src, src_end, 6)) <= 0) {
342
10
            return H2O_HTTP2_ERROR_COMPRESSION;
343
10
        }
344
25.5k
        do_index = 1;
345
80.1k
    } else if (**src < 32) {
346
        /* literal header field without indexing / never indexed */
347
51.4k
        if ((**src & 0xf) == 0) {
348
42.9k
            ++*src;
349
42.9k
        } else if ((index = h2o_hpack_decode_int(src, src_end, 4)) <= 0) {
350
18
            return H2O_HTTP2_ERROR_COMPRESSION;
351
18
        }
352
51.4k
    } else {
353
        /* size update */
354
28.7k
        int64_t new_capacity;
355
28.7k
        if ((new_capacity = h2o_hpack_decode_int(src, src_end, 5)) < 0) {
356
32
            return H2O_HTTP2_ERROR_COMPRESSION;
357
32
        }
358
28.7k
        if (new_capacity > hpack_header_table->hpack_max_capacity) {
359
200
            return H2O_HTTP2_ERROR_COMPRESSION;
360
200
        }
361
28.5k
        hpack_header_table->hpack_capacity = (size_t)new_capacity;
362
33.2k
        while (hpack_header_table->num_entries != 0 && hpack_header_table->hpack_size > hpack_header_table->hpack_capacity) {
363
4.68k
            header_table_evict_one(hpack_header_table);
364
4.68k
        }
365
28.5k
        goto Redo;
366
28.7k
    }
367
368
    /* determine the header */
369
174k
    unsigned soft_errors = 0;
370
174k
    if (index > 0) {
371
        /* existing name (and value?) */
372
126k
        if (index < HEADER_TABLE_OFFSET) {
373
76.1k
            name = (h2o_iovec_t *)h2o_hpack_static_table[index - 1].name;
374
76.1k
            if (value_is_indexed)
375
49.1k
                value = (h2o_iovec_t *)&h2o_hpack_static_table[index - 1].value;
376
76.1k
        } else if (index - HEADER_TABLE_OFFSET < hpack_header_table->num_entries) {
377
49.2k
            struct st_h2o_hpack_header_table_entry_t *entry =
378
49.2k
                h2o_hpack_header_table_get(hpack_header_table, index - HEADER_TABLE_OFFSET);
379
49.2k
            soft_errors = entry->soft_errors;
380
49.2k
            name = entry->name;
381
49.2k
            if (!h2o_iovec_is_token(name))
382
10.9k
                h2o_mem_link_shared(pool, name);
383
49.2k
            if (value_is_indexed) {
384
47.9k
                value = entry->value;
385
47.9k
                h2o_mem_link_shared(pool, value);
386
47.9k
            }
387
49.2k
        } else {
388
817
            return H2O_HTTP2_ERROR_COMPRESSION;
389
817
        }
390
126k
    } else {
391
        /* non-existing name */
392
48.3k
        const h2o_token_t *name_token;
393
48.3k
        if ((name = decode_string(pool, &soft_errors, src, src_end, 1, err_desc)) == NULL) {
394
353
            if (*err_desc == h2o_hpack_err_found_upper_case_in_header_name)
395
61
                return H2O_HTTP2_ERROR_PROTOCOL;
396
292
            return H2O_HTTP2_ERROR_COMPRESSION;
397
353
        }
398
        /* predefined header names should be interned */
399
48.0k
        if ((name_token = h2o_lookup_token(name->base, name->len)) != NULL)
400
5.56k
            name = (h2o_iovec_t *)&name_token->buf;
401
48.0k
    }
402
403
    /* determine the value (if necessary) */
404
173k
    if (!value_is_indexed) {
405
76.3k
        soft_errors &= ~H2O_HPACK_SOFT_ERROR_BIT_INVALID_VALUE;
406
76.3k
        if ((value = decode_string(pool, &soft_errors, src, src_end, 0, err_desc)) == NULL)
407
1.92k
            return H2O_HTTP2_ERROR_COMPRESSION;
408
76.3k
    }
409
410
    /* add the decoded header to the header table if necessary */
411
171k
    if (do_index) {
412
24.6k
        struct st_h2o_hpack_header_table_entry_t *entry =
413
24.6k
            header_table_add(hpack_header_table, name->len + value->len + HEADER_TABLE_ENTRY_SIZE_OFFSET, SIZE_MAX);
414
24.6k
        if (entry != NULL) {
415
17.5k
            entry->soft_errors = soft_errors;
416
17.5k
            entry->name = name;
417
17.5k
            if (!h2o_iovec_is_token(entry->name))
418
3.85k
                h2o_mem_addref_shared(entry->name);
419
17.5k
            entry->value = value;
420
17.5k
            if (!value_is_part_of_static_table(entry->value))
421
17.5k
                h2o_mem_addref_shared(entry->value);
422
17.5k
        }
423
24.6k
    }
424
425
171k
    *_name = name;
426
171k
    *_value = *value;
427
171k
    if (soft_errors != 0) {
428
70.8k
        *err_desc = (soft_errors & H2O_HPACK_SOFT_ERROR_BIT_INVALID_NAME) != 0
429
70.8k
                        ? h2o_hpack_soft_err_found_invalid_char_in_header_name
430
70.8k
                        : h2o_hpack_soft_err_found_invalid_char_in_header_value;
431
70.8k
        return H2O_HTTP2_ERROR_INVALID_HEADER_CHAR;
432
100k
    } else {
433
100k
        return 0;
434
100k
    }
435
171k
}
436
437
static uint8_t *encode_status(uint8_t *dst, int status)
438
8.22k
{
439
    /* see also: STATUS_HEADER_MAX_SIZE */
440
441
8.22k
    assert(100 <= status && status <= 999);
442
443
8.22k
    switch (status) {
444
0
#define COMMON_CODE(code, st)                                                                                                      \
445
7.75k
    case st:                                                                                                                       \
446
7.75k
        *dst++ = 0x80 | code;                                                                                                      \
447
7.75k
        break
448
707
        COMMON_CODE(8, 200);
449
0
        COMMON_CODE(9, 204);
450
0
        COMMON_CODE(10, 206);
451
0
        COMMON_CODE(11, 304);
452
2.46k
        COMMON_CODE(12, 400);
453
4.57k
        COMMON_CODE(13, 404);
454
0
        COMMON_CODE(14, 500);
455
0
#undef COMMON_CODE
456
475
    default:
457
        /* use literal header field without indexing - indexed name */
458
475
        *dst++ = 8;
459
475
        *dst++ = 3;
460
475
        sprintf((char *)dst, "%d", status);
461
475
        dst += 3;
462
475
        break;
463
8.22k
    }
464
465
8.22k
    return dst;
466
8.22k
}
467
468
static uint8_t *encode_content_length(uint8_t *dst, size_t value)
469
7.51k
{
470
7.51k
    char buf[32], *p = buf + sizeof(buf);
471
7.51k
    size_t l;
472
473
10.4k
    do {
474
10.4k
        *--p = '0' + value % 10;
475
10.4k
    } while ((value /= 10) != 0);
476
7.51k
    l = buf + sizeof(buf) - p;
477
7.51k
    *dst++ = 0x0f;
478
7.51k
    *dst++ = 0x0d;
479
7.51k
    *dst++ = (uint8_t)l;
480
7.51k
    memcpy(dst, p, l);
481
7.51k
    dst += l;
482
483
7.51k
    return dst;
484
7.51k
}
485
486
void h2o_hpack_dispose_header_table(h2o_hpack_header_table_t *header_table)
487
21.5k
{
488
21.5k
    if (header_table->num_entries != 0) {
489
5.29k
        size_t index = header_table->entry_start_index;
490
15.2k
        do {
491
15.2k
            struct st_h2o_hpack_header_table_entry_t *entry = header_table->entries + index;
492
15.2k
            if (!h2o_iovec_is_token(entry->name))
493
2.41k
                h2o_mem_release_shared(entry->name);
494
15.2k
            if (!value_is_part_of_static_table(entry->value))
495
15.2k
                h2o_mem_release_shared(entry->value);
496
15.2k
            index = (index + 1) % header_table->entry_capacity;
497
15.2k
        } while (--header_table->num_entries != 0);
498
5.29k
    }
499
21.5k
    free(header_table->entries);
500
21.5k
}
501
502
int h2o_hpack_parse_request(h2o_mem_pool_t *pool, h2o_hpack_decode_header_cb decode_cb, void *decode_ctx, h2o_iovec_t *method,
503
                            const h2o_url_scheme_t **scheme, h2o_iovec_t *authority, h2o_iovec_t *path, h2o_iovec_t *protocol,
504
                            h2o_headers_t *headers, int *pseudo_header_exists_map, size_t *content_length, h2o_iovec_t *expect,
505
                            h2o_cache_digests_t **digests, h2o_iovec_t *datagram_flow_id, const uint8_t *src, size_t len,
506
                            const char **err_desc)
507
22.0k
{
508
22.0k
    const uint8_t *src_end = src + len;
509
22.0k
    size_t num_headers_decoded = 0;
510
511
22.0k
    *content_length = SIZE_MAX;
512
513
402k
    while (src != src_end) {
514
388k
        h2o_iovec_t *name, value;
515
388k
        const char *decode_err = NULL;
516
388k
        int ret = decode_cb(pool, decode_ctx, &name, &value, &src, src_end, &decode_err);
517
388k
        if (ret != 0) {
518
110k
            if (ret == H2O_HTTP2_ERROR_INVALID_HEADER_CHAR) {
519
                /* this is a soft error, we continue parsing, but register only the first error */
520
103k
                if (*err_desc == NULL) {
521
5.95k
                    *err_desc = decode_err;
522
5.95k
                }
523
103k
            } else {
524
6.77k
                *err_desc = decode_err;
525
6.77k
                return ret;
526
6.77k
            }
527
110k
        }
528
381k
        ++num_headers_decoded;
529
381k
        if (num_headers_decoded > H2O_HPACK_MAX_HEADERS_HARD_LIMIT) {
530
38
            *err_desc = h2o_hpack_err_headers_too_long;
531
38
            return H2O_HTTP2_ERROR_COMPRESSION;
532
38
        }
533
381k
        if (name->base[0] == ':') {
534
42.3k
            if (pseudo_header_exists_map != NULL) {
535
                /* FIXME validate the chars in the value (e.g. reject SP in path) */
536
42.0k
                if (name == &H2O_TOKEN_AUTHORITY->buf) {
537
8.06k
                    if (authority->base != NULL) {
538
9
                        *err_desc = h2o_hpack_err_invalid_pseudo_header;
539
9
                        return H2O_HTTP2_ERROR_PROTOCOL;
540
9
                    }
541
8.05k
                    *authority = value;
542
8.05k
                    *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_AUTHORITY_EXISTS;
543
34.0k
                } else if (name == &H2O_TOKEN_METHOD->buf) {
544
11.9k
                    if (method->base != NULL) {
545
8
                        *err_desc = h2o_hpack_err_invalid_pseudo_header;
546
8
                        return H2O_HTTP2_ERROR_PROTOCOL;
547
8
                    }
548
11.9k
                    *method = value;
549
11.9k
                    *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_METHOD_EXISTS;
550
22.0k
                } else if (name == &H2O_TOKEN_PROTOCOL->buf) {
551
9
                    if (protocol->base != NULL)
552
2
                        return H2O_HTTP2_ERROR_PROTOCOL;
553
7
                    *protocol = value;
554
7
                    *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_PROTOCOL_EXISTS;
555
22.0k
                } else if (name == &H2O_TOKEN_PATH->buf) {
556
10.8k
                    if (path->base != NULL) {
557
7
                        *err_desc = h2o_hpack_err_invalid_pseudo_header;
558
7
                        return H2O_HTTP2_ERROR_PROTOCOL;
559
7
                    }
560
10.8k
                    if (value.len == 0) {
561
6
                        *err_desc = h2o_hpack_err_invalid_pseudo_header;
562
6
                        return H2O_HTTP2_ERROR_PROTOCOL;
563
6
                    }
564
10.8k
                    *path = value;
565
10.8k
                    *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_PATH_EXISTS;
566
11.1k
                } else if (name == &H2O_TOKEN_SCHEME->buf) {
567
11.1k
                    if (*scheme != NULL) {
568
9
                        *err_desc = h2o_hpack_err_invalid_pseudo_header;
569
9
                        return H2O_HTTP2_ERROR_PROTOCOL;
570
9
                    }
571
11.1k
                    if (h2o_memis(value.base, value.len, H2O_STRLIT("https"))) {
572
1.63k
                        *scheme = &H2O_URL_SCHEME_HTTPS;
573
9.50k
                    } else if (h2o_memis(value.base, value.len, H2O_STRLIT("masque"))) {
574
3
                        *scheme = &H2O_URL_SCHEME_MASQUE;
575
9.50k
                    } else {
576
                        /* draft-16 8.1.2.3 suggests quote: ":scheme is not restricted to http and https schemed URIs" */
577
9.50k
                        *scheme = &H2O_URL_SCHEME_HTTP;
578
9.50k
                    }
579
11.1k
                    *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_SCHEME_EXISTS;
580
11.1k
                } else {
581
34
                    return H2O_HTTP2_ERROR_PROTOCOL;
582
34
                }
583
42.0k
            } else {
584
251
                *err_desc = h2o_hpack_err_invalid_pseudo_header;
585
251
                return H2O_HTTP2_ERROR_PROTOCOL;
586
251
            }
587
338k
        } else {
588
338k
            pseudo_header_exists_map = NULL;
589
338k
            if (h2o_iovec_is_token(name)) {
590
252k
                h2o_token_t *token = H2O_STRUCT_FROM_MEMBER(h2o_token_t, buf, name);
591
252k
                if (token->flags.is_hpack_special) {
592
31.5k
                    if (token == H2O_TOKEN_CONTENT_LENGTH) {
593
6.35k
                        if ((*content_length = h2o_strtosize(value.base, value.len)) == SIZE_MAX) {
594
89
                            *err_desc = h2o_hpack_err_invalid_content_length_header;
595
89
                            return H2O_HTTP2_ERROR_PROTOCOL;
596
89
                        }
597
6.26k
                        goto Next;
598
25.1k
                    } else if (token == H2O_TOKEN_EXPECT) {
599
5.13k
                        *expect = value;
600
5.13k
                        goto Next;
601
20.0k
                    } else if (token == H2O_TOKEN_HOST && authority != NULL) {
602
                        /* HTTP2 allows the use of host header (in place of :authority) */
603
1.98k
                        if (authority->base == NULL)
604
316
                            *authority = value;
605
1.98k
                        goto Next;
606
18.0k
                    } else if (token == H2O_TOKEN_TE && h2o_lcstris(value.base, value.len, H2O_STRLIT("trailers"))) {
607
                        /* do not reject */
608
17.0k
                    } else if (token == H2O_TOKEN_CACHE_DIGEST && digests != NULL) {
609
                        /* TODO cache the decoded result in HPACK, as well as delay the decoding of the digest until being used */
610
16.4k
                        h2o_cache_digests_load_header(digests, value.base, value.len);
611
16.4k
                    } else if (token == H2O_TOKEN_DATAGRAM_FLOW_ID) {
612
619
                        if (datagram_flow_id != NULL)
613
104
                            *datagram_flow_id = value;
614
619
                        goto Next;
615
619
                    } else {
616
                        /* rest of the header fields that are marked as special are rejected */
617
71
                        *err_desc = h2o_hpack_err_unexpected_connection_specific_header;
618
71
                        return H2O_HTTP2_ERROR_PROTOCOL;
619
71
                    }
620
31.5k
                }
621
238k
                if (headers->size < H2O_MAX_HEADERS) {
622
114k
                    h2o_add_header(pool, headers, token, NULL, value.base, value.len);
623
123k
                } else if (*err_desc == NULL) {
624
81
                    *err_desc = h2o_hpack_err_headers_too_long;
625
81
                }
626
238k
            } else {
627
86.5k
                if (headers->size < H2O_MAX_HEADERS) {
628
40.7k
                    h2o_add_header_by_str(pool, headers, name->base, name->len, 0, NULL, value.base, value.len);
629
45.8k
                } else if (*err_desc == NULL) {
630
3
                    *err_desc = h2o_hpack_err_headers_too_long;
631
3
                }
632
86.5k
            }
633
338k
        }
634
380k
    Next:;
635
380k
    }
636
637
14.7k
    if (*err_desc != NULL)
638
3.18k
        return H2O_HTTP2_ERROR_INVALID_HEADER_CHAR;
639
11.5k
    return 0;
640
14.7k
}
641
642
int h2o_hpack_parse_response(h2o_mem_pool_t *pool, h2o_hpack_decode_header_cb decode_cb, void *decode_ctx, int *status,
643
                             h2o_headers_t *headers, h2o_iovec_t *datagram_flow_id, const uint8_t *src, size_t len,
644
                             const char **err_desc)
645
0
{
646
0
    if (status != NULL)
647
0
        *status = 0;
648
649
0
    const uint8_t *src_end = src + len;
650
0
    size_t num_headers_decoded = 0;
651
652
    /* the response MUST contain a :status header as the first element */
653
0
    if (status != NULL && src == src_end) {
654
0
        *err_desc = h2o_hpack_err_missing_mandatory_pseudo_header;
655
0
        return H2O_HTTP2_ERROR_PROTOCOL;
656
0
    }
657
658
0
    do {
659
0
        h2o_iovec_t *name, value;
660
0
        const char *decode_err = NULL;
661
0
        int ret = decode_cb(pool, decode_ctx, &name, &value, &src, src_end, &decode_err);
662
0
        if (ret != 0) {
663
0
            if (ret == H2O_HTTP2_ERROR_INVALID_HEADER_CHAR) {
664
                /* this is a soft error, we continue parsing, but register only the first error */
665
0
                if (*err_desc == NULL) {
666
0
                    *err_desc = decode_err;
667
0
                }
668
0
            } else {
669
0
                *err_desc = decode_err;
670
0
                return ret;
671
0
            }
672
0
        }
673
0
        ++num_headers_decoded;
674
0
        if (num_headers_decoded > H2O_HPACK_MAX_HEADERS_HARD_LIMIT) {
675
0
            *err_desc = h2o_hpack_err_headers_too_long;
676
0
            return H2O_HTTP2_ERROR_COMPRESSION;
677
0
        }
678
0
        if (name->base[0] == ':') {
679
0
            if (status == NULL) {
680
0
                *err_desc = h2o_hpack_err_invalid_pseudo_header;
681
0
                return H2O_HTTP2_ERROR_PROTOCOL; /* Trailers MUST NOT include pseudo-header fields */
682
0
            }
683
0
            if (name != &H2O_TOKEN_STATUS->buf) {
684
0
                *err_desc = h2o_hpack_err_invalid_pseudo_header;
685
0
                return H2O_HTTP2_ERROR_PROTOCOL;
686
0
            }
687
0
            if (*status != 0) {
688
0
                *err_desc = h2o_hpack_err_invalid_pseudo_header;
689
0
                return H2O_HTTP2_ERROR_PROTOCOL;
690
0
            }
691
            /* parse status */
692
0
            if (value.len != 3) {
693
0
                *err_desc = h2o_hpack_err_invalid_pseudo_header;
694
0
                return H2O_HTTP2_ERROR_PROTOCOL;
695
0
            }
696
0
            char *c = value.base;
697
0
#define PARSE_DIGIT(mul, min_digit)                                                                                                \
698
0
    do {                                                                                                                           \
699
0
        if (*c < '0' + (min_digit) || '9' < *c) {                                                                                  \
700
0
            *err_desc = h2o_hpack_err_invalid_pseudo_header;                                                                       \
701
0
            return H2O_HTTP2_ERROR_PROTOCOL;                                                                                       \
702
0
        }                                                                                                                          \
703
0
        *status += (*c - '0') * mul;                                                                                               \
704
0
        ++c;                                                                                                                       \
705
0
    } while (0)
706
0
            PARSE_DIGIT(100, 1);
707
0
            PARSE_DIGIT(10, 0);
708
0
            PARSE_DIGIT(1, 0);
709
0
#undef PARSE_DIGIT
710
0
        } else {
711
0
            if (status != NULL && *status == 0) {
712
0
                *err_desc = h2o_hpack_err_missing_mandatory_pseudo_header;
713
0
                return H2O_HTTP2_ERROR_PROTOCOL;
714
0
            }
715
0
            if (h2o_iovec_is_token(name)) {
716
0
                h2o_token_t *token = H2O_STRUCT_FROM_MEMBER(h2o_token_t, buf, name);
717
                /* reject headers as defined in draft-16 8.1.2.2 */
718
0
                if (token->flags.is_hpack_special) {
719
0
                    if (token == H2O_TOKEN_CONTENT_LENGTH || token == H2O_TOKEN_CACHE_DIGEST || token == H2O_TOKEN_HOST) {
720
                        /* pass them through when found in response headers (TODO reconsider?) */
721
0
                    } else if (token == H2O_TOKEN_DATAGRAM_FLOW_ID) {
722
0
                        if (datagram_flow_id != NULL)
723
0
                            *datagram_flow_id = value;
724
0
                        goto Next;
725
0
                    } else {
726
0
                        *err_desc = h2o_hpack_err_unexpected_connection_specific_header;
727
0
                        return H2O_HTTP2_ERROR_PROTOCOL;
728
0
                    }
729
0
                }
730
0
                if (headers->size < H2O_MAX_HEADERS) {
731
0
                    h2o_add_header(pool, headers, token, NULL, value.base, value.len);
732
0
                } else if (*err_desc == NULL) {
733
0
                    *err_desc = h2o_hpack_err_headers_too_long;
734
0
                }
735
0
            } else {
736
0
                if (headers->size < H2O_MAX_HEADERS) {
737
0
                    h2o_add_header_by_str(pool, headers, name->base, name->len, 0, NULL, value.base, value.len);
738
0
                } else if (*err_desc == NULL) {
739
0
                    *err_desc = h2o_hpack_err_headers_too_long;
740
0
                }
741
0
            }
742
0
        }
743
0
    Next:;
744
0
    } while (src != src_end);
745
746
0
    if (*err_desc != NULL) {
747
0
        return H2O_HTTP2_ERROR_INVALID_HEADER_CHAR;
748
0
    }
749
0
    return 0;
750
0
}
751
752
static inline int encode_int_is_onebyte(int64_t value, unsigned prefix_bits)
753
38.3k
{
754
38.3k
    return value < (1 << prefix_bits) - 1;
755
38.3k
}
756
757
uint8_t *h2o_hpack_encode_int(uint8_t *dst, int64_t value, unsigned prefix_bits)
758
32.1k
{
759
32.1k
    if (encode_int_is_onebyte(value, prefix_bits)) {
760
28.6k
        *dst++ |= value;
761
28.6k
    } else {
762
        /* see also: MAX_ENCODE_INT_LENGTH */
763
3.44k
        assert(value >= 0);
764
3.44k
        value -= (1 << prefix_bits) - 1;
765
3.44k
        *dst++ |= (1 << prefix_bits) - 1;
766
3.46k
        for (; value >= 128; value >>= 7) {
767
22
            *dst++ = 0x80 | value;
768
22
        }
769
3.44k
        *dst++ = value;
770
3.44k
    }
771
32.1k
    return dst;
772
32.1k
}
773
774
size_t h2o_hpack_encode_huffman(uint8_t *_dst, const uint8_t *src, size_t len)
775
10.8k
{
776
10.8k
    uint8_t *dst = _dst, *dst_end = dst + len;
777
10.8k
    const uint8_t *src_end = src + len;
778
10.8k
    uint64_t bits = 0;
779
10.8k
    int bits_left = 40;
780
781
243k
    while (src != src_end) {
782
232k
        const nghttp2_huff_sym *sym = huff_sym_table + *src++;
783
232k
        bits |= (uint64_t)sym->code << (bits_left - sym->nbits);
784
232k
        bits_left -= sym->nbits;
785
397k
        while (bits_left <= 32) {
786
165k
            *dst++ = bits >> 32;
787
165k
            bits <<= 8;
788
165k
            bits_left += 8;
789
165k
            if (dst == dst_end) {
790
0
                return SIZE_MAX;
791
0
            }
792
165k
        }
793
232k
    }
794
795
10.8k
    if (bits_left != 40) {
796
10.6k
        bits |= ((uint64_t)1 << bits_left) - 1;
797
10.6k
        *dst++ = bits >> 32;
798
10.6k
    }
799
10.8k
    if (dst == dst_end) {
800
1.34k
        return SIZE_MAX;
801
1.34k
    }
802
803
9.46k
    return dst - _dst;
804
10.8k
}
805
806
static size_t encode_as_is(uint8_t *dst, const char *s, size_t len)
807
0
{
808
0
    uint8_t *start = dst;
809
0
    *dst = '\0';
810
0
    dst = h2o_hpack_encode_int(dst, len, 7);
811
0
    memcpy(dst, s, len);
812
0
    dst += len;
813
0
    return dst - start;
814
0
}
815
816
size_t h2o_hpack_encode_string(uint8_t *dst, const char *s, size_t len)
817
6.27k
{
818
6.27k
    if (H2O_LIKELY(len != 0)) {
819
        /* try to encode using huffman */
820
6.27k
        size_t hufflen = h2o_hpack_encode_huffman(dst + 1, (const uint8_t *)s, len);
821
6.27k
        if (H2O_LIKELY(hufflen != SIZE_MAX)) {
822
6.27k
            size_t head_len;
823
6.27k
            if (H2O_LIKELY(encode_int_is_onebyte((uint32_t)hufflen, 7))) {
824
6.27k
                dst[0] = (uint8_t)(0x80 | hufflen);
825
6.27k
                head_len = 1;
826
6.27k
            } else {
827
0
                uint8_t head[8];
828
0
                head[0] = '\x80';
829
0
                head_len = h2o_hpack_encode_int(head, hufflen, 7) - head;
830
0
                memmove(dst + head_len, dst + 1, hufflen);
831
0
                memcpy(dst, head, head_len);
832
0
            }
833
6.27k
            return head_len + hufflen;
834
6.27k
        }
835
6.27k
    }
836
0
    return encode_as_is(dst, s, len);
837
6.27k
}
838
839
static uint8_t *header_table_adjust_size(h2o_hpack_header_table_t *table, uint32_t new_capacity, uint8_t *dst)
840
8.22k
{
841
    /* Do nothing if user-supplied value is greater than the current value. Because we never allow the peer to increase the table
842
     * size here, there is no need to worry about using excess memory. */
843
8.22k
    if (new_capacity >= table->hpack_capacity)
844
8.11k
        return dst;
845
846
    /* update state */
847
115
    table->hpack_capacity = new_capacity;
848
146
    while (table->num_entries != 0 && table->hpack_size > table->hpack_capacity)
849
31
        header_table_evict_one(table);
850
851
    /* encode Dynamic Table Size Update */
852
115
    *dst = 0x20;
853
115
    dst = h2o_hpack_encode_int(dst, table->hpack_capacity, 5);
854
855
115
    return dst;
856
8.22k
}
857
858
static uint8_t *do_encode_header(h2o_hpack_header_table_t *header_table, uint8_t *dst, const h2o_iovec_t *name,
859
                                 const h2o_iovec_t *value, int dont_compress)
860
16.4k
{
861
16.4k
    int is_token = h2o_iovec_is_token(name);
862
16.4k
    int name_index = is_token ? ((const h2o_token_t *)name)->flags.http2_static_table_name_index : 0;
863
864
    /* try to send as indexed */
865
16.4k
    {
866
16.4k
        size_t header_table_index = header_table->entry_start_index, n;
867
24.9k
        for (n = header_table->num_entries; n != 0; --n) {
868
18.7k
            struct st_h2o_hpack_header_table_entry_t *entry = header_table->entries + header_table_index;
869
18.7k
            if (is_token) {
870
18.7k
                if (name != entry->name)
871
8.51k
                    goto Next;
872
18.7k
            } else {
873
0
                if (!h2o_memis(name->base, name->len, entry->name->base, entry->name->len))
874
0
                    goto Next;
875
0
                if (name_index == 0)
876
0
                    name_index = (int)(header_table->num_entries - n + HEADER_TABLE_OFFSET);
877
0
            }
878
            /* name matched! */
879
10.1k
            if (!h2o_memis(value->base, value->len, entry->value->base, entry->value->len))
880
20
                goto Next;
881
            /* name and value matched! */
882
10.1k
            *dst = 0x80;
883
10.1k
            dst = h2o_hpack_encode_int(dst, header_table->num_entries - n + HEADER_TABLE_OFFSET, 7);
884
10.1k
            return dst;
885
8.53k
        Next:
886
8.53k
            ++header_table_index;
887
8.53k
            if (header_table_index == header_table->entry_capacity)
888
2.36k
                header_table_index = 0;
889
8.53k
        }
890
16.4k
    }
891
892
6.27k
    if (!dont_compress && is_token)
893
6.27k
        dont_compress = ((const h2o_token_t *)name)->flags.dont_compress;
894
6.27k
    if (dont_compress)
895
0
        dont_compress = value->len < 20;
896
897
6.27k
    if (name_index != 0) {
898
        /* literal header field with indexing (indexed name). */
899
6.27k
        if (dont_compress == 1) {
900
            /* mark the field as 'never indexed' */
901
0
            *dst = 0x10;
902
0
            dst = h2o_hpack_encode_int(dst, name_index, 4);
903
6.27k
        } else {
904
6.27k
            *dst = 0x40;
905
6.27k
            dst = h2o_hpack_encode_int(dst, name_index, 6);
906
6.27k
        }
907
6.27k
    } else {
908
        /* literal header field with indexing (new name) */
909
0
        *dst++ = 0x40;
910
0
        dst += h2o_hpack_encode_string(dst, name->base, name->len);
911
0
    }
912
6.27k
    if (dont_compress == 1) {
913
        /* bypass huffman encoding */
914
0
        dst += encode_as_is(dst, value->base, value->len);
915
6.27k
    } else {
916
        /* add to header table (maximum number of entries in output header table is limited to 32 so that the search (see above)
917
           would
918
           not take too long) */
919
6.27k
        dst += h2o_hpack_encode_string(dst, value->base, value->len);
920
6.27k
        struct st_h2o_hpack_header_table_entry_t *entry =
921
6.27k
            header_table_add(header_table, name->len + value->len + HEADER_TABLE_ENTRY_SIZE_OFFSET, 32);
922
6.27k
        if (entry != NULL) {
923
5.36k
            if (is_token) {
924
5.36k
                entry->name = (h2o_iovec_t *)name;
925
5.36k
            } else {
926
0
                entry->name = alloc_buf(NULL, name->len);
927
0
                entry->name->base[name->len] = '\0';
928
0
                memcpy(entry->name->base, name->base, name->len);
929
0
            }
930
5.36k
            entry->value = alloc_buf(NULL, value->len);
931
5.36k
            entry->value->base[value->len] = '\0';
932
5.36k
            memcpy(entry->value->base, value->base, value->len);
933
5.36k
        }
934
6.27k
    }
935
936
6.27k
    return dst;
937
16.4k
}
938
939
static uint8_t *encode_header(h2o_hpack_header_table_t *header_table, uint8_t *dst, const h2o_header_t *header)
940
8.22k
{
941
8.22k
    return do_encode_header(header_table, dst, header->name, &header->value, header->flags.dont_compress);
942
8.22k
}
943
944
static uint8_t *encode_header_token(h2o_hpack_header_table_t *header_table, uint8_t *dst, const h2o_token_t *token,
945
                                    const h2o_iovec_t *value)
946
8.22k
{
947
8.22k
    return do_encode_header(header_table, dst, &token->buf, value, token->flags.dont_compress);
948
8.22k
}
949
950
static uint8_t *encode_method(h2o_hpack_header_table_t *header_table, uint8_t *dst, h2o_iovec_t value)
951
0
{
952
0
    if (h2o_memis(value.base, value.len, H2O_STRLIT("GET"))) {
953
0
        *dst++ = 0x82;
954
0
        return dst;
955
0
    }
956
0
    if (h2o_memis(value.base, value.len, H2O_STRLIT("POST"))) {
957
0
        *dst++ = 0x83;
958
0
        return dst;
959
0
    }
960
0
    return encode_header_token(header_table, dst, H2O_TOKEN_METHOD, &value);
961
0
}
962
963
static uint8_t *encode_scheme(h2o_hpack_header_table_t *header_table, uint8_t *dst, const h2o_url_scheme_t *scheme)
964
0
{
965
0
    if (scheme == &H2O_URL_SCHEME_HTTPS) {
966
0
        *dst++ = 0x87;
967
0
        return dst;
968
0
    }
969
0
    if (scheme == &H2O_URL_SCHEME_HTTP) {
970
0
        *dst++ = 0x86;
971
0
        return dst;
972
0
    }
973
0
    return encode_header_token(header_table, dst, H2O_TOKEN_SCHEME, &scheme->name);
974
0
}
975
976
static uint8_t *encode_path(h2o_hpack_header_table_t *header_table, uint8_t *dst, h2o_iovec_t value)
977
0
{
978
0
    if (h2o_memis(value.base, value.len, H2O_STRLIT("/"))) {
979
0
        *dst++ = 0x84;
980
0
        return dst;
981
0
    }
982
0
    if (h2o_memis(value.base, value.len, H2O_STRLIT("/index.html"))) {
983
0
        *dst++ = 0x85;
984
0
        return dst;
985
0
    }
986
0
    return encode_header_token(header_table, dst, H2O_TOKEN_PATH, &value);
987
0
}
988
989
static uint8_t *encode_literal_header_without_indexing(uint8_t *dst, const h2o_iovec_t *name, const h2o_iovec_t *value)
990
0
{
991
0
    /* literal header field without indexing / never indexed */
992
0
    *dst++ = 0;
993
0
    dst += h2o_hpack_encode_string(dst, name->base, name->len);
994
0
    dst += h2o_hpack_encode_string(dst, value->base, value->len);
995
0
    return dst;
996
0
}
997
998
static size_t calc_capacity(size_t name_len, size_t value_len)
999
8.22k
{
1000
8.22k
    return name_len + value_len + 1 + H2O_HPACK_ENCODE_INT_MAX_LENGTH * 2;
1001
8.22k
}
1002
1003
static size_t calc_headers_capacity(const h2o_header_t *headers, size_t num_headers)
1004
8.22k
{
1005
8.22k
    const h2o_header_t *header;
1006
8.22k
    size_t capacity = 0;
1007
16.4k
    for (header = headers; num_headers != 0; ++header, --num_headers)
1008
8.22k
        capacity += calc_capacity(header->name->len, header->value.len);
1009
8.22k
    return capacity;
1010
8.22k
}
1011
1012
static void fixup_frame_headers(h2o_buffer_t **buf, size_t start_at, uint8_t type, uint32_t stream_id, size_t max_frame_size,
1013
                                int flags)
1014
8.22k
{
1015
    /* try to fit all data into single frame, using the preallocated space for the frame header */
1016
8.22k
    size_t payload_size = (*buf)->size - start_at - H2O_HTTP2_FRAME_HEADER_SIZE;
1017
8.22k
    if (payload_size <= max_frame_size) {
1018
8.22k
        h2o_http2_encode_frame_header((uint8_t *)((*buf)->bytes + start_at), payload_size, type,
1019
8.22k
                                      H2O_HTTP2_FRAME_FLAG_END_HEADERS | flags, stream_id);
1020
8.22k
        return;
1021
8.22k
    }
1022
1023
    /* need to setup continuation frames */
1024
0
    size_t off;
1025
0
    h2o_http2_encode_frame_header((uint8_t *)((*buf)->bytes + start_at), max_frame_size, type, flags, stream_id);
1026
0
    off = start_at + H2O_HTTP2_FRAME_HEADER_SIZE + max_frame_size;
1027
0
    while (1) {
1028
0
        size_t left = (*buf)->size - off;
1029
0
        h2o_buffer_reserve(buf, H2O_HTTP2_FRAME_HEADER_SIZE);
1030
0
        memmove((*buf)->bytes + off + H2O_HTTP2_FRAME_HEADER_SIZE, (*buf)->bytes + off, left);
1031
0
        (*buf)->size += H2O_HTTP2_FRAME_HEADER_SIZE;
1032
0
        if (left <= max_frame_size) {
1033
0
            h2o_http2_encode_frame_header((uint8_t *)((*buf)->bytes + off), left, H2O_HTTP2_FRAME_TYPE_CONTINUATION,
1034
0
                                          H2O_HTTP2_FRAME_FLAG_END_HEADERS, stream_id);
1035
0
            break;
1036
0
        } else {
1037
0
            h2o_http2_encode_frame_header((uint8_t *)((*buf)->bytes + off), max_frame_size, H2O_HTTP2_FRAME_TYPE_CONTINUATION, 0,
1038
0
                                          stream_id);
1039
0
            off += H2O_HTTP2_FRAME_HEADER_SIZE + max_frame_size;
1040
0
        }
1041
0
    }
1042
0
}
1043
1044
void h2o_hpack_flatten_request(h2o_buffer_t **buf, h2o_hpack_header_table_t *header_table, uint32_t hpack_capacity,
1045
                               uint32_t stream_id, size_t max_frame_size, h2o_iovec_t method, h2o_url_t *url, h2o_iovec_t protocol,
1046
                               const h2o_header_t *headers, size_t num_headers, int is_end_stream, int send_own_expect)
1047
0
{
1048
0
    static const h2o_iovec_t hundred_continue = (h2o_iovec_t){H2O_STRLIT("100-continue")};
1049
0
    int old_style_connect = h2o_memis(method.base, method.len, H2O_STRLIT("CONNECT")) && protocol.base == NULL;
1050
1051
0
    size_t capacity = calc_headers_capacity(headers, num_headers);
1052
0
    capacity += H2O_HTTP2_FRAME_HEADER_SIZE;
1053
0
    capacity += DYNAMIC_TABLE_SIZE_UPDATE_MAX_SIZE;
1054
0
    capacity += calc_capacity(H2O_TOKEN_METHOD->buf.len, method.len);
1055
0
    if (!old_style_connect)
1056
0
        capacity += calc_capacity(H2O_TOKEN_SCHEME->buf.len, url->scheme->name.len);
1057
0
    capacity += calc_capacity(H2O_TOKEN_AUTHORITY->buf.len, url->authority.len);
1058
0
    if (!old_style_connect)
1059
0
        capacity += calc_capacity(H2O_TOKEN_PATH->buf.len, url->path.len);
1060
0
    capacity += calc_capacity(H2O_TOKEN_PROTOCOL->buf.len, protocol.len);
1061
0
    if (send_own_expect)
1062
0
        capacity += calc_capacity(H2O_TOKEN_EXPECT->buf.len, hundred_continue.len);
1063
1064
0
    size_t start_at = (*buf)->size;
1065
0
    uint8_t *dst = (void *)(h2o_buffer_reserve(buf, capacity).base + H2O_HTTP2_FRAME_HEADER_SIZE);
1066
1067
    /* encode */
1068
0
    dst = header_table_adjust_size(header_table, hpack_capacity, dst);
1069
0
    dst = encode_method(header_table, dst, method);
1070
0
    if (!old_style_connect)
1071
0
        dst = encode_scheme(header_table, dst, url->scheme);
1072
0
    dst = encode_header_token(header_table, dst, H2O_TOKEN_AUTHORITY, &url->authority);
1073
0
    if (!old_style_connect)
1074
0
        dst = encode_path(header_table, dst, url->path);
1075
0
    if (protocol.base != NULL) {
1076
0
        h2o_header_t h = {&H2O_TOKEN_PROTOCOL->buf, NULL, protocol};
1077
0
        dst = encode_header(header_table, dst, &h);
1078
0
    }
1079
0
    if (send_own_expect)
1080
0
        dst = encode_header_token(header_table, dst, H2O_TOKEN_EXPECT, &hundred_continue);
1081
1082
0
    for (size_t i = 0; i != num_headers; ++i) {
1083
0
        const h2o_header_t *header = headers + i;
1084
0
        if (header->name == &H2O_TOKEN_ACCEPT_ENCODING->buf &&
1085
0
            h2o_memis(header->value.base, header->value.len, H2O_STRLIT("gzip, deflate"))) {
1086
0
            *dst++ = 0x90;
1087
0
        } else {
1088
0
            dst = encode_header(header_table, dst, header);
1089
0
        }
1090
0
    }
1091
0
    (*buf)->size = (char *)dst - (*buf)->bytes;
1092
1093
    /* setup the frame headers */
1094
0
    fixup_frame_headers(buf, start_at, H2O_HTTP2_FRAME_TYPE_HEADERS, stream_id, max_frame_size,
1095
0
                        is_end_stream ? H2O_HTTP2_FRAME_FLAG_END_STREAM : 0);
1096
0
}
1097
1098
void h2o_hpack_flatten_push_promise(h2o_buffer_t **buf, h2o_hpack_header_table_t *header_table, uint32_t hpack_capacity,
1099
                                    uint32_t stream_id, size_t max_frame_size, const h2o_url_scheme_t *scheme,
1100
                                    h2o_iovec_t authority, h2o_iovec_t method, h2o_iovec_t path, const h2o_header_t *headers,
1101
                                    size_t num_headers, uint32_t parent_stream_id)
1102
0
{
1103
0
    size_t capacity = calc_headers_capacity(headers, num_headers);
1104
0
    capacity += H2O_HTTP2_FRAME_HEADER_SIZE /* first frame header */
1105
0
                + 4;                        /* promised stream id */
1106
0
    capacity += DYNAMIC_TABLE_SIZE_UPDATE_MAX_SIZE;
1107
0
    capacity += calc_capacity(H2O_TOKEN_METHOD->buf.len, method.len);
1108
0
    capacity += calc_capacity(H2O_TOKEN_SCHEME->buf.len, scheme->name.len);
1109
0
    capacity += calc_capacity(H2O_TOKEN_AUTHORITY->buf.len, authority.len);
1110
0
    capacity += calc_capacity(H2O_TOKEN_PATH->buf.len, path.len);
1111
1112
0
    size_t start_at = (*buf)->size;
1113
0
    uint8_t *dst = (void *)(h2o_buffer_reserve(buf, capacity).base + H2O_HTTP2_FRAME_HEADER_SIZE);
1114
1115
    /* encode */
1116
0
    dst = h2o_http2_encode32u(dst, stream_id);
1117
0
    dst = header_table_adjust_size(header_table, hpack_capacity, dst);
1118
0
    dst = encode_method(header_table, dst, method);
1119
0
    dst = encode_scheme(header_table, dst, scheme);
1120
0
    dst = encode_header_token(header_table, dst, H2O_TOKEN_AUTHORITY, &authority);
1121
0
    dst = encode_path(header_table, dst, path);
1122
0
    for (size_t i = 0; i != num_headers; ++i) {
1123
0
        const h2o_header_t *header = headers + i;
1124
0
        if (header->name == &H2O_TOKEN_ACCEPT_ENCODING->buf &&
1125
0
            h2o_memis(header->value.base, header->value.len, H2O_STRLIT("gzip, deflate"))) {
1126
0
            *dst++ = 0x90;
1127
0
        } else {
1128
0
            dst = encode_header(header_table, dst, header);
1129
0
        }
1130
0
    }
1131
0
    (*buf)->size = (char *)dst - (*buf)->bytes;
1132
1133
    /* setup the frame headers */
1134
0
    fixup_frame_headers(buf, start_at, H2O_HTTP2_FRAME_TYPE_PUSH_PROMISE, parent_stream_id, max_frame_size, 0);
1135
0
}
1136
1137
size_t h2o_hpack_flatten_response(h2o_buffer_t **buf, h2o_hpack_header_table_t *header_table, uint32_t hpack_capacity,
1138
                                  uint32_t stream_id, size_t max_frame_size, int status, const h2o_header_t *headers,
1139
                                  size_t num_headers, const h2o_iovec_t *server_name, size_t content_length, int is_end_stream)
1140
8.22k
{
1141
8.22k
    size_t capacity = calc_headers_capacity(headers, num_headers);
1142
8.22k
    capacity += H2O_HTTP2_FRAME_HEADER_SIZE; /* for the first header */
1143
8.22k
    capacity += DYNAMIC_TABLE_SIZE_UPDATE_MAX_SIZE;
1144
8.22k
    capacity += STATUS_HEADER_MAX_SIZE; /* for :status: */
1145
8.22k
#ifndef H2O_UNITTEST
1146
8.22k
    if (server_name != NULL && server_name->len) {
1147
8.22k
        capacity += 5 + server_name->len; /* for Server: */
1148
8.22k
    }
1149
8.22k
#endif
1150
8.22k
    if (content_length != SIZE_MAX)
1151
7.51k
        capacity += CONTENT_LENGTH_HEADER_MAX_SIZE; /* for content-length: UINT64_MAX (with huffman compression applied) */
1152
1153
8.22k
    size_t start_at = (*buf)->size;
1154
8.22k
    uint8_t *dst = (void *)(h2o_buffer_reserve(buf, capacity).base + H2O_HTTP2_FRAME_HEADER_SIZE); /* skip frame header */
1155
1156
    /* encode */
1157
8.22k
    dst = header_table_adjust_size(header_table, hpack_capacity, dst);
1158
8.22k
    dst = encode_status(dst, status);
1159
8.22k
#ifndef H2O_UNITTEST
1160
    /* TODO keep some kind of reference to the indexed Server header, and reuse it */
1161
8.22k
    if (server_name != NULL && server_name->len) {
1162
8.22k
        dst = encode_header_token(header_table, dst, H2O_TOKEN_SERVER, server_name);
1163
8.22k
    }
1164
8.22k
#endif
1165
16.4k
    for (size_t i = 0; i != num_headers; ++i)
1166
8.22k
        dst = encode_header(header_table, dst, headers + i);
1167
8.22k
    if (content_length != SIZE_MAX)
1168
7.51k
        dst = encode_content_length(dst, content_length);
1169
8.22k
    (*buf)->size = (char *)dst - (*buf)->bytes;
1170
8.22k
    size_t headers_size = (*buf)->size - start_at - H2O_HTTP2_FRAME_HEADER_SIZE;
1171
1172
    /* setup the frame headers */
1173
8.22k
    fixup_frame_headers(buf, start_at, H2O_HTTP2_FRAME_TYPE_HEADERS, stream_id, max_frame_size,
1174
8.22k
                        is_end_stream ? H2O_HTTP2_FRAME_FLAG_END_STREAM : 0);
1175
1176
8.22k
    return headers_size;
1177
8.22k
}
1178
1179
void h2o_hpack_flatten_trailers(h2o_buffer_t **buf, h2o_hpack_header_table_t *header_table, uint32_t hpack_capacity,
1180
                                uint32_t stream_id, size_t max_frame_size, const h2o_header_t *headers, size_t num_headers)
1181
0
{
1182
0
    size_t capacity = calc_headers_capacity(headers, num_headers);
1183
0
    capacity += H2O_HTTP2_FRAME_HEADER_SIZE;
1184
0
    capacity += DYNAMIC_TABLE_SIZE_UPDATE_MAX_SIZE;
1185
1186
0
    size_t start_at = (*buf)->size;
1187
0
    uint8_t *dst = (void *)(h2o_buffer_reserve(buf, capacity).base + H2O_HTTP2_FRAME_HEADER_SIZE); /* skip frame header */
1188
1189
0
    dst = header_table_adjust_size(header_table, hpack_capacity, dst);
1190
0
    for (size_t i = 0; i != num_headers; ++i)
1191
0
        dst = encode_header(header_table, dst, headers + i);
1192
0
    (*buf)->size = (char *)dst - (*buf)->bytes;
1193
1194
    /* setup the frame headers */
1195
0
    fixup_frame_headers(buf, start_at, H2O_HTTP2_FRAME_TYPE_HEADERS, stream_id, max_frame_size, H2O_HTTP2_FRAME_FLAG_END_STREAM);
1196
0
}