Coverage Report

Created: 2026-07-16 06:29

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
248k
#define HEADER_TABLE_OFFSET 62
30
44.5k
#define HEADER_TABLE_ENTRY_SIZE_OFFSET 32
31
9.12k
#define DYNAMIC_TABLE_SIZE_UPDATE_MAX_SIZE 5
32
9.12k
#define STATUS_HEADER_MAX_SIZE 5
33
#define CONTENT_LENGTH_HEADER_MAX_SIZE                                                                                             \
34
8.39k
    (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
45.2k
{
40
45.2k
    return &h2o_hpack_static_table[0].value <= value &&
41
45.2k
           value <= &h2o_hpack_static_table[sizeof(h2o_hpack_static_table) / sizeof(h2o_hpack_static_table[0]) - 1].value;
42
45.2k
}
43
44
static h2o_iovec_t *alloc_buf(h2o_mem_pool_t *pool, size_t len)
45
145k
{
46
145k
    h2o_iovec_t *buf = h2o_mem_alloc_shared(pool, sizeof(h2o_iovec_t) + len + 1, NULL);
47
145k
    buf->base = (char *)buf + sizeof(h2o_iovec_t);
48
145k
    buf->len = len;
49
145k
    return buf;
50
145k
}
51
52
int64_t h2o_hpack_decode_int(const uint8_t **src, const uint8_t *src_end, unsigned prefix_bits)
53
583k
{
54
583k
    uint64_t value;
55
583k
    unsigned shift;
56
583k
    uint8_t prefix_max = (1 << prefix_bits) - 1;
57
58
583k
    if (*src >= src_end)
59
5
        return H2O_HTTP2_ERROR_INCOMPLETE;
60
61
583k
    value = *(*src)++ & prefix_max;
62
583k
    if (value != prefix_max)
63
547k
        return (int64_t)value;
64
65
    /* decode upto 8 octets (excluding prefix), that are guaranteed not to cause overflow */
66
36.7k
    value = prefix_max;
67
62.9k
    for (shift = 0; shift < 56; shift += 7) {
68
62.0k
        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
35.7k
            return (int64_t)value;
73
61.9k
    }
74
    /* handling the 9th octet */
75
843
    if (*src == src_end)
76
7
        return H2O_HTTP2_ERROR_INCOMPLETE;
77
836
    if ((**src & 128) != 0)
78
72
        return H2O_HTTP2_ERROR_COMPRESSION;
79
764
    value += (uint64_t)(*(*src)++ & 127) << shift;
80
764
    if (value > (uint64_t)INT64_MAX)
81
7
        return H2O_HTTP2_ERROR_COMPRESSION;
82
757
    return value;
83
764
}
84
85
static char *huffdecode4(char *dst, uint8_t in, uint8_t *state, int *maybe_eos, uint8_t *seen_char_types)
86
1.82M
{
87
1.82M
    const nghttp2_huff_decode *entry = huff_decode_table[*state] + in;
88
89
1.82M
    if ((entry->flags & NGHTTP2_HUFF_FAIL) != 0)
90
32
        return NULL;
91
1.82M
    if ((entry->flags & NGHTTP2_HUFF_SYM) != 0) {
92
1.20M
        *dst++ = entry->sym;
93
1.20M
        *seen_char_types |= (entry->flags & NGHTTP2_HUFF_INVALID_CHARS);
94
1.20M
    }
95
1.82M
    *state = entry->state;
96
1.82M
    *maybe_eos = (entry->flags & NGHTTP2_HUFF_ACCEPTED) != 0;
97
98
1.82M
    return dst;
99
1.82M
}
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
137k
{
112
137k
    if (len != 0 && (s[0] == 0x20 || s[0] == 0x09 || s[len - 1] == 0x20 || s[len - 1] == 0x09))
113
4.52k
        return 0;
114
133k
    return 1;
115
137k
}
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
40.0k
{
120
40.0k
    char *dst = _dst;
121
40.0k
    const uint8_t *src_end = src + len;
122
40.0k
    uint8_t state = 0, seen_char_types = 0;
123
40.0k
    int maybe_eos = 1;
124
125
    /* decode */
126
952k
    for (; src < src_end; src++) {
127
912k
        if ((dst = huffdecode4(dst, *src >> 4, &state, &maybe_eos, &seen_char_types)) == NULL)
128
12
            return SIZE_MAX;
129
912k
        if ((dst = huffdecode4(dst, *src & 0xf, &state, &maybe_eos, &seen_char_types)) == NULL)
130
20
            return SIZE_MAX;
131
912k
    }
132
39.9k
    if (!maybe_eos)
133
240
        return SIZE_MAX;
134
135
    /* validate */
136
39.7k
    if (is_name) {
137
15.7k
        if (dst == _dst) {
138
1.29k
            *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_NAME;
139
14.4k
        } else {
140
            /* pseudo-headers are checked later in `decode_header` */
141
14.4k
            if ((seen_char_types & NGHTTP2_HUFF_INVALID_FOR_HEADER_NAME) != 0 && _dst[0] != ':') {
142
9.75k
                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
9.75k
                } else {
146
9.75k
                    *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_NAME;
147
9.75k
                }
148
9.75k
            }
149
14.4k
        }
150
24.0k
    } else {
151
24.0k
        if ((seen_char_types & NGHTTP2_HUFF_INVALID_FOR_HEADER_VALUE) != 0 || !header_value_valid_as_whole(_dst, dst - _dst))
152
1.64k
            *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_VALUE;
153
24.0k
    }
154
155
39.7k
    return dst - _dst;
156
39.7k
}
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
74.3k
{
165
    /* all printable chars, except upper case and separator characters */
166
74.3k
    static const char valid_h2_header_name_char[] = {
167
74.3k
        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
74.3k
        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
74.3k
        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
74.3k
        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
74.3k
        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
74.3k
        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
74.3k
        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
74.3k
        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
74.3k
    };
176
177
74.3k
    if (len == 0) {
178
30.4k
        *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_NAME;
179
43.8k
    } else {
180
504k
        for (; len != 0; ++s, --len) {
181
460k
            unsigned char ch = (unsigned char)*s;
182
460k
            if (!valid_h2_header_name_char[ch]) {
183
125k
                if (ch - 'A' < 26U) {
184
169
                    *err_desc = h2o_hpack_err_found_upper_case_in_header_name;
185
169
                    return 0;
186
169
                }
187
124k
                *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_NAME;
188
124k
            }
189
460k
        }
190
43.8k
    }
191
74.1k
    return 1;
192
74.3k
}
193
194
void h2o_hpack_validate_header_value(unsigned *soft_errors, const char *s, size_t len)
195
114k
{
196
    /* surrounding whitespace RFC 9113 8.2.1 */
197
114k
    if (!header_value_valid_as_whole(s, len))
198
3.36k
        goto Invalid;
199
200
    /* all printable chars + horizontal tab (RFC 7230 3.2) */
201
110k
    static const char valid_h2_field_value_char[] = {
202
110k
        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
110k
        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
110k
        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
110k
        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
110k
        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
110k
        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
110k
        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
110k
        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
110k
    };
211
212
419k
    for (; len != 0; ++s, --len) {
213
340k
        unsigned char ch = (unsigned char)*s;
214
340k
        if (!valid_h2_field_value_char[ch])
215
32.0k
            goto Invalid;
216
340k
    }
217
78.9k
    return;
218
219
78.9k
Invalid:
220
35.4k
    *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_VALUE;
221
35.4k
}
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
141k
{
226
141k
    h2o_iovec_t *ret;
227
141k
    int is_huffman;
228
141k
    int64_t len;
229
230
141k
    if (*src >= src_end)
231
543
        return NULL;
232
233
140k
    is_huffman = (**src & 0x80) != 0;
234
140k
    if ((len = h2o_hpack_decode_int(src, src_end, 7)) < 0)
235
43
        return NULL;
236
237
140k
    if (is_huffman) {
238
16.1k
        if (len > src_end - *src)
239
521
            return NULL;
240
15.6k
        ret = alloc_buf(pool, len * 2); /* max compression ratio is >= 0.5 */
241
15.6k
        if ((ret->len = h2o_hpack_decode_huffman(ret->base, soft_errors, *src, len, is_header_name, err_desc)) == SIZE_MAX)
242
127
            return NULL;
243
15.5k
        ret->base[ret->len] = '\0';
244
124k
    } else {
245
124k
        if (len > src_end - *src)
246
1.29k
            return NULL;
247
123k
        if (is_header_name) {
248
            /* pseudo-headers are checked later in `decode_header` */
249
53.3k
            if ((len == 0 || **src != (uint8_t)':') && !h2o_hpack_validate_header_name(soft_errors, (char *)*src, len, err_desc))
250
76
                return NULL;
251
69.8k
        } else {
252
69.8k
            h2o_hpack_validate_header_value(soft_errors, (char *)*src, len);
253
69.8k
        }
254
123k
        ret = alloc_buf(pool, len);
255
123k
        memcpy(ret->base, *src, len);
256
123k
        ret->base[len] = '\0';
257
123k
    }
258
138k
    *src += len;
259
260
138k
    return ret;
261
140k
}
262
263
static void header_table_evict_one(h2o_hpack_header_table_t *table)
264
9.37k
{
265
9.37k
    struct st_h2o_hpack_header_table_entry_t *entry;
266
9.37k
    assert(table->num_entries != 0);
267
268
9.37k
    entry = h2o_hpack_header_table_get(table, --table->num_entries);
269
9.37k
    table->hpack_size -= entry->name->len + entry->value->len + HEADER_TABLE_ENTRY_SIZE_OFFSET;
270
9.37k
    if (!h2o_iovec_is_token(entry->name))
271
1.74k
        h2o_mem_release_shared(entry->name);
272
9.37k
    if (!value_is_part_of_static_table(entry->value))
273
9.37k
        h2o_mem_release_shared(entry->value);
274
9.37k
    memset(entry, 0, sizeof(*entry));
275
9.37k
}
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
35.2k
{
280
    /* adjust the size */
281
39.3k
    while (table->num_entries != 0 && table->hpack_size + size_add > table->hpack_capacity)
282
4.10k
        header_table_evict_one(table);
283
35.2k
    while (max_num_entries <= table->num_entries)
284
0
        header_table_evict_one(table);
285
35.2k
    if (table->num_entries == 0) {
286
19.0k
        assert(table->hpack_size == 0);
287
19.0k
        if (size_add > table->hpack_capacity)
288
9.08k
            return NULL;
289
19.0k
    }
290
26.1k
    table->hpack_size += size_add;
291
292
    /* grow the entries if full */
293
26.1k
    if (table->num_entries == table->entry_capacity) {
294
7.46k
        size_t new_capacity = table->num_entries * 2;
295
7.46k
        if (new_capacity < 16)
296
7.22k
            new_capacity = 16;
297
7.46k
        struct st_h2o_hpack_header_table_entry_t *new_entries =
298
7.46k
            h2o_mem_alloc(new_capacity * sizeof(struct st_h2o_hpack_header_table_entry_t));
299
7.46k
        if (table->num_entries != 0) {
300
236
            size_t src_index = table->entry_start_index, dst_index = 0;
301
6.99k
            do {
302
6.99k
                new_entries[dst_index] = table->entries[src_index];
303
6.99k
                ++dst_index;
304
6.99k
                src_index = (src_index + 1) % table->entry_capacity;
305
6.99k
            } while (dst_index != table->num_entries);
306
236
        }
307
7.46k
        memset(new_entries + table->num_entries, 0, sizeof(*new_entries) * (new_capacity - table->num_entries));
308
7.46k
        free(table->entries);
309
7.46k
        table->entries = new_entries;
310
7.46k
        table->entry_capacity = new_capacity;
311
7.46k
        table->entry_start_index = 0;
312
7.46k
    }
313
314
26.1k
    ++table->num_entries;
315
26.1k
    table->entry_start_index = (table->entry_start_index + table->entry_capacity - 1) % table->entry_capacity;
316
26.1k
    return table->entries + table->entry_start_index;
317
35.2k
}
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
192k
{
322
192k
    h2o_hpack_header_table_t *hpack_header_table = _hpack_header_table;
323
192k
    h2o_iovec_t *name = NULL, *value = NULL;
324
192k
    int64_t index = 0;
325
192k
    int value_is_indexed = 0, do_index = 0;
326
327
222k
Redo:
328
222k
    if (*src >= src_end)
329
89
        return H2O_HTTP2_ERROR_COMPRESSION;
330
331
    /* determine the mode and handle accordingly */
332
222k
    if (**src >= 128) {
333
        /* indexed header field representation */
334
104k
        if ((index = h2o_hpack_decode_int(src, src_end, 7)) <= 0)
335
80
            return H2O_HTTP2_ERROR_COMPRESSION;
336
104k
        value_is_indexed = 1;
337
117k
    } else if (**src >= 64) {
338
        /* literal header field with incremental handling */
339
28.2k
        if (**src == 64) {
340
6.06k
            ++*src;
341
22.2k
        } else if ((index = h2o_hpack_decode_int(src, src_end, 6)) <= 0) {
342
11
            return H2O_HTTP2_ERROR_COMPRESSION;
343
11
        }
344
28.2k
        do_index = 1;
345
89.5k
    } else if (**src < 32) {
346
        /* literal header field without indexing / never indexed */
347
58.5k
        if ((**src & 0xf) == 0) {
348
49.1k
            ++*src;
349
49.1k
        } else if ((index = h2o_hpack_decode_int(src, src_end, 4)) <= 0) {
350
20
            return H2O_HTTP2_ERROR_COMPRESSION;
351
20
        }
352
58.5k
    } else {
353
        /* size update */
354
31.0k
        int64_t new_capacity;
355
31.0k
        if ((new_capacity = h2o_hpack_decode_int(src, src_end, 5)) < 0) {
356
27
            return H2O_HTTP2_ERROR_COMPRESSION;
357
27
        }
358
30.9k
        if (new_capacity > hpack_header_table->hpack_max_capacity) {
359
229
            return H2O_HTTP2_ERROR_COMPRESSION;
360
229
        }
361
30.7k
        hpack_header_table->hpack_capacity = (size_t)new_capacity;
362
35.9k
        while (hpack_header_table->num_entries != 0 && hpack_header_table->hpack_size > hpack_header_table->hpack_capacity) {
363
5.23k
            header_table_evict_one(hpack_header_table);
364
5.23k
        }
365
30.7k
        goto Redo;
366
30.9k
    }
367
368
    /* determine the header */
369
191k
    unsigned soft_errors = 0;
370
191k
    if (index > 0) {
371
        /* existing name (and value?) */
372
136k
        if (index < HEADER_TABLE_OFFSET) {
373
85.1k
            name = (h2o_iovec_t *)h2o_hpack_static_table[index - 1].name;
374
85.1k
            if (value_is_indexed)
375
55.3k
                value = (h2o_iovec_t *)&h2o_hpack_static_table[index - 1].value;
376
85.1k
        } else if (index - HEADER_TABLE_OFFSET < hpack_header_table->num_entries) {
377
50.3k
            struct st_h2o_hpack_header_table_entry_t *entry =
378
50.3k
                h2o_hpack_header_table_get(hpack_header_table, index - HEADER_TABLE_OFFSET);
379
50.3k
            soft_errors = entry->soft_errors;
380
50.3k
            name = entry->name;
381
50.3k
            if (!h2o_iovec_is_token(name))
382
11.1k
                h2o_mem_link_shared(pool, name);
383
50.3k
            if (value_is_indexed) {
384
48.9k
                value = entry->value;
385
48.9k
                h2o_mem_link_shared(pool, value);
386
48.9k
            }
387
50.3k
        } else {
388
901
            return H2O_HTTP2_ERROR_COMPRESSION;
389
901
        }
390
136k
    } else {
391
        /* non-existing name */
392
55.2k
        const h2o_token_t *name_token;
393
55.2k
        if ((name = decode_string(pool, &soft_errors, src, src_end, 1, err_desc)) == NULL) {
394
398
            if (*err_desc == h2o_hpack_err_found_upper_case_in_header_name)
395
76
                return H2O_HTTP2_ERROR_PROTOCOL;
396
322
            return H2O_HTTP2_ERROR_COMPRESSION;
397
398
        }
398
        /* predefined header names should be interned */
399
54.8k
        if ((name_token = h2o_lookup_token(name->base, name->len)) != NULL)
400
5.99k
            name = (h2o_iovec_t *)&name_token->buf;
401
54.8k
    }
402
403
    /* determine the value (if necessary) */
404
190k
    if (!value_is_indexed) {
405
86.1k
        soft_errors &= ~H2O_HPACK_SOFT_ERROR_BIT_INVALID_VALUE;
406
86.1k
        if ((value = decode_string(pool, &soft_errors, src, src_end, 0, err_desc)) == NULL)
407
2.20k
            return H2O_HTTP2_ERROR_COMPRESSION;
408
86.1k
    }
409
410
    /* add the decoded header to the header table if necessary */
411
188k
    if (do_index) {
412
27.2k
        struct st_h2o_hpack_header_table_entry_t *entry =
413
27.2k
            header_table_add(hpack_header_table, name->len + value->len + HEADER_TABLE_ENTRY_SIZE_OFFSET, SIZE_MAX);
414
27.2k
        if (entry != NULL) {
415
19.0k
            entry->soft_errors = soft_errors;
416
19.0k
            entry->name = name;
417
19.0k
            if (!h2o_iovec_is_token(entry->name))
418
4.32k
                h2o_mem_addref_shared(entry->name);
419
19.0k
            entry->value = value;
420
19.0k
            if (!value_is_part_of_static_table(entry->value))
421
19.0k
                h2o_mem_addref_shared(entry->value);
422
19.0k
        }
423
27.2k
    }
424
425
188k
    *_name = name;
426
188k
    *_value = *value;
427
188k
    if (soft_errors != 0) {
428
78.1k
        *err_desc = (soft_errors & H2O_HPACK_SOFT_ERROR_BIT_INVALID_NAME) != 0
429
78.1k
                        ? h2o_hpack_soft_err_found_invalid_char_in_header_name
430
78.1k
                        : h2o_hpack_soft_err_found_invalid_char_in_header_value;
431
78.1k
        return H2O_HTTP2_ERROR_INVALID_HEADER_CHAR;
432
110k
    } else {
433
110k
        return 0;
434
110k
    }
435
188k
}
436
437
static uint8_t *encode_status(uint8_t *dst, int status)
438
9.12k
{
439
    /* see also: STATUS_HEADER_MAX_SIZE */
440
441
9.12k
    assert(100 <= status && status <= 999);
442
443
9.12k
    switch (status) {
444
0
#define COMMON_CODE(code, st)                                                                                                      \
445
8.58k
    case st:                                                                                                                       \
446
8.58k
        *dst++ = 0x80 | code;                                                                                                      \
447
8.58k
        break
448
731
        COMMON_CODE(8, 200);
449
0
        COMMON_CODE(9, 204);
450
0
        COMMON_CODE(10, 206);
451
0
        COMMON_CODE(11, 304);
452
2.76k
        COMMON_CODE(12, 400);
453
5.09k
        COMMON_CODE(13, 404);
454
0
        COMMON_CODE(14, 500);
455
0
#undef COMMON_CODE
456
535
    default:
457
        /* use literal header field without indexing - indexed name */
458
535
        *dst++ = 8;
459
535
        *dst++ = 3;
460
535
        sprintf((char *)dst, "%d", status);
461
535
        dst += 3;
462
535
        break;
463
9.12k
    }
464
465
9.12k
    return dst;
466
9.12k
}
467
468
static uint8_t *encode_content_length(uint8_t *dst, size_t value)
469
8.39k
{
470
8.39k
    char buf[32], *p = buf + sizeof(buf);
471
8.39k
    size_t l;
472
473
11.6k
    do {
474
11.6k
        *--p = '0' + value % 10;
475
11.6k
    } while ((value /= 10) != 0);
476
8.39k
    l = buf + sizeof(buf) - p;
477
8.39k
    *dst++ = 0x0f;
478
8.39k
    *dst++ = 0x0d;
479
8.39k
    *dst++ = (uint8_t)l;
480
8.39k
    memcpy(dst, p, l);
481
8.39k
    dst += l;
482
483
8.39k
    return dst;
484
8.39k
}
485
486
void h2o_hpack_dispose_header_table(h2o_hpack_header_table_t *header_table)
487
25.3k
{
488
25.3k
    if (header_table->num_entries != 0) {
489
6.21k
        size_t index = header_table->entry_start_index;
490
16.7k
        do {
491
16.7k
            struct st_h2o_hpack_header_table_entry_t *entry = header_table->entries + index;
492
16.7k
            if (!h2o_iovec_is_token(entry->name))
493
2.58k
                h2o_mem_release_shared(entry->name);
494
16.7k
            if (!value_is_part_of_static_table(entry->value))
495
16.7k
                h2o_mem_release_shared(entry->value);
496
16.7k
            index = (index + 1) % header_table->entry_capacity;
497
16.7k
        } while (--header_table->num_entries != 0);
498
6.21k
    }
499
25.3k
    free(header_table->entries);
500
25.3k
}
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
24.7k
{
508
24.7k
    const uint8_t *src_end = src + len;
509
24.7k
    size_t num_headers_decoded = 0;
510
511
24.7k
    *content_length = SIZE_MAX;
512
513
417k
    while (src != src_end) {
514
400k
        h2o_iovec_t *name, value;
515
400k
        const char *decode_err = NULL;
516
400k
        int ret = decode_cb(pool, decode_ctx, &name, &value, &src, src_end, &decode_err);
517
400k
        if (ret != 0) {
518
116k
            if (ret == H2O_HTTP2_ERROR_INVALID_HEADER_CHAR) {
519
                /* this is a soft error, we continue parsing, but register only the first error */
520
109k
                if (*err_desc == NULL) {
521
6.50k
                    *err_desc = decode_err;
522
6.50k
                }
523
109k
            } else {
524
7.30k
                *err_desc = decode_err;
525
7.30k
                return ret;
526
7.30k
            }
527
116k
        }
528
393k
        ++num_headers_decoded;
529
393k
        if (num_headers_decoded > H2O_HPACK_MAX_HEADERS_HARD_LIMIT) {
530
36
            *err_desc = h2o_hpack_err_headers_too_long;
531
36
            return H2O_HTTP2_ERROR_COMPRESSION;
532
36
        }
533
393k
        if (name->base[0] == ':') {
534
46.6k
            if (pseudo_header_exists_map != NULL) {
535
                /* FIXME validate the chars in the value (e.g. reject SP in path) */
536
46.3k
                if (name == &H2O_TOKEN_AUTHORITY->buf) {
537
8.87k
                    if (authority->base != NULL) {
538
10
                        *err_desc = h2o_hpack_err_invalid_pseudo_header;
539
10
                        return H2O_HTTP2_ERROR_PROTOCOL;
540
10
                    }
541
8.86k
                    *authority = value;
542
8.86k
                    *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_AUTHORITY_EXISTS;
543
37.4k
                } else if (name == &H2O_TOKEN_METHOD->buf) {
544
13.1k
                    if (method->base != NULL) {
545
8
                        *err_desc = h2o_hpack_err_invalid_pseudo_header;
546
8
                        return H2O_HTTP2_ERROR_PROTOCOL;
547
8
                    }
548
13.1k
                    *method = value;
549
13.1k
                    *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_METHOD_EXISTS;
550
24.3k
                } 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
24.3k
                } else if (name == &H2O_TOKEN_PATH->buf) {
556
11.9k
                    if (path->base != NULL) {
557
9
                        *err_desc = h2o_hpack_err_invalid_pseudo_header;
558
9
                        return H2O_HTTP2_ERROR_PROTOCOL;
559
9
                    }
560
11.9k
                    if (value.len == 0) {
561
6
                        *err_desc = h2o_hpack_err_invalid_pseudo_header;
562
6
                        return H2O_HTTP2_ERROR_PROTOCOL;
563
6
                    }
564
11.9k
                    *path = value;
565
11.9k
                    *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_PATH_EXISTS;
566
12.3k
                } else if (name == &H2O_TOKEN_SCHEME->buf) {
567
12.2k
                    if (*scheme != NULL) {
568
14
                        *err_desc = h2o_hpack_err_invalid_pseudo_header;
569
14
                        return H2O_HTTP2_ERROR_PROTOCOL;
570
14
                    }
571
12.2k
                    if (h2o_memis(value.base, value.len, H2O_STRLIT("https"))) {
572
1.77k
                        *scheme = &H2O_URL_SCHEME_HTTPS;
573
10.4k
                    } else if (h2o_memis(value.base, value.len, H2O_STRLIT("masque"))) {
574
3
                        *scheme = &H2O_URL_SCHEME_MASQUE;
575
10.4k
                    } else {
576
                        /* draft-16 8.1.2.3 suggests quote: ":scheme is not restricted to http and https schemed URIs" */
577
10.4k
                        *scheme = &H2O_URL_SCHEME_HTTP;
578
10.4k
                    }
579
12.2k
                    *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_SCHEME_EXISTS;
580
12.2k
                } else {
581
36
                    return H2O_HTTP2_ERROR_PROTOCOL;
582
36
                }
583
46.3k
            } else {
584
278
                *err_desc = h2o_hpack_err_invalid_pseudo_header;
585
278
                return H2O_HTTP2_ERROR_PROTOCOL;
586
278
            }
587
346k
        } else {
588
346k
            pseudo_header_exists_map = NULL;
589
346k
            if (h2o_iovec_is_token(name)) {
590
254k
                h2o_token_t *token = H2O_STRUCT_FROM_MEMBER(h2o_token_t, buf, name);
591
254k
                if (token->flags.is_hpack_special) {
592
32.0k
                    if (token == H2O_TOKEN_CONTENT_LENGTH) {
593
6.74k
                        if ((*content_length = h2o_strtosize(value.base, value.len)) == SIZE_MAX) {
594
99
                            *err_desc = h2o_hpack_err_invalid_content_length_header;
595
99
                            return H2O_HTTP2_ERROR_PROTOCOL;
596
99
                        }
597
6.64k
                        goto Next;
598
25.3k
                    } else if (token == H2O_TOKEN_EXPECT) {
599
4.65k
                        *expect = value;
600
4.65k
                        goto Next;
601
20.6k
                    } else if (token == H2O_TOKEN_HOST && authority != NULL) {
602
                        /* HTTP2 allows the use of host header (in place of :authority) */
603
1.95k
                        if (authority->base == NULL)
604
348
                            *authority = value;
605
1.95k
                        goto Next;
606
18.7k
                    } else if (token == H2O_TOKEN_TE && h2o_lcstris(value.base, value.len, H2O_STRLIT("trailers"))) {
607
                        /* do not reject */
608
17.6k
                    } 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.9k
                        h2o_cache_digests_load_header(digests, value.base, value.len);
611
16.9k
                    } else if (token == H2O_TOKEN_DATAGRAM_FLOW_ID) {
612
618
                        if (datagram_flow_id != NULL)
613
122
                            *datagram_flow_id = value;
614
618
                        goto Next;
615
618
                    } else {
616
                        /* rest of the header fields that are marked as special are rejected */
617
80
                        *err_desc = h2o_hpack_err_unexpected_connection_specific_header;
618
80
                        return H2O_HTTP2_ERROR_PROTOCOL;
619
80
                    }
620
32.0k
                }
621
240k
                if (headers->size < H2O_MAX_HEADERS) {
622
121k
                    h2o_add_header(pool, headers, token, NULL, value.base, value.len);
623
121k
                } else if (*err_desc == NULL) {
624
78
                    *err_desc = h2o_hpack_err_headers_too_long;
625
78
                }
626
240k
            } else {
627
91.8k
                if (headers->size < H2O_MAX_HEADERS) {
628
43.9k
                    h2o_add_header_by_str(pool, headers, name->base, name->len, 0, NULL, value.base, value.len);
629
47.9k
                } else if (*err_desc == NULL) {
630
4
                    *err_desc = h2o_hpack_err_headers_too_long;
631
4
                }
632
91.8k
            }
633
346k
        }
634
392k
    Next:;
635
392k
    }
636
637
16.8k
    if (*err_desc != NULL)
638
3.54k
        return H2O_HTTP2_ERROR_INVALID_HEADER_CHAR;
639
13.3k
    return 0;
640
16.8k
}
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
42.9k
{
754
42.9k
    return value < (1 << prefix_bits) - 1;
755
42.9k
}
756
757
uint8_t *h2o_hpack_encode_int(uint8_t *dst, int64_t value, unsigned prefix_bits)
758
35.0k
{
759
35.0k
    if (encode_int_is_onebyte(value, prefix_bits)) {
760
31.3k
        *dst++ |= value;
761
31.3k
    } else {
762
        /* see also: MAX_ENCODE_INT_LENGTH */
763
3.70k
        assert(value >= 0);
764
3.70k
        value -= (1 << prefix_bits) - 1;
765
3.70k
        *dst++ |= (1 << prefix_bits) - 1;
766
3.72k
        for (; value >= 128; value >>= 7) {
767
25
            *dst++ = 0x80 | value;
768
25
        }
769
3.70k
        *dst++ = value;
770
3.70k
    }
771
35.0k
    return dst;
772
35.0k
}
773
774
size_t h2o_hpack_encode_huffman(uint8_t *_dst, const uint8_t *src, size_t len)
775
12.8k
{
776
12.8k
    uint8_t *dst = _dst, *dst_end = dst + len;
777
12.8k
    const uint8_t *src_end = src + len;
778
12.8k
    uint64_t bits = 0;
779
12.8k
    int bits_left = 40;
780
781
292k
    while (src != src_end) {
782
279k
        const nghttp2_huff_sym *sym = huff_sym_table + *src++;
783
279k
        bits |= (uint64_t)sym->code << (bits_left - sym->nbits);
784
279k
        bits_left -= sym->nbits;
785
478k
        while (bits_left <= 32) {
786
198k
            *dst++ = bits >> 32;
787
198k
            bits <<= 8;
788
198k
            bits_left += 8;
789
198k
            if (dst == dst_end) {
790
0
                return SIZE_MAX;
791
0
            }
792
198k
        }
793
279k
    }
794
795
12.8k
    if (bits_left != 40) {
796
12.1k
        bits |= ((uint64_t)1 << bits_left) - 1;
797
12.1k
        *dst++ = bits >> 32;
798
12.1k
    }
799
12.8k
    if (dst == dst_end) {
800
1.42k
        return SIZE_MAX;
801
1.42k
    }
802
803
11.4k
    return dst - _dst;
804
12.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
7.99k
{
818
7.99k
    if (H2O_LIKELY(len != 0)) {
819
        /* try to encode using huffman */
820
7.99k
        size_t hufflen = h2o_hpack_encode_huffman(dst + 1, (const uint8_t *)s, len);
821
7.99k
        if (H2O_LIKELY(hufflen != SIZE_MAX)) {
822
7.99k
            size_t head_len;
823
7.99k
            if (H2O_LIKELY(encode_int_is_onebyte((uint32_t)hufflen, 7))) {
824
7.99k
                dst[0] = (uint8_t)(0x80 | hufflen);
825
7.99k
                head_len = 1;
826
7.99k
            } 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
7.99k
            return head_len + hufflen;
834
7.99k
        }
835
7.99k
    }
836
0
    return encode_as_is(dst, s, len);
837
7.99k
}
838
839
static uint8_t *header_table_adjust_size(h2o_hpack_header_table_t *table, uint32_t new_capacity, uint8_t *dst)
840
9.12k
{
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
9.12k
    if (new_capacity >= table->hpack_capacity)
844
8.99k
        return dst;
845
846
    /* update state */
847
132
    table->hpack_capacity = new_capacity;
848
165
    while (table->num_entries != 0 && table->hpack_size > table->hpack_capacity)
849
33
        header_table_evict_one(table);
850
851
    /* encode Dynamic Table Size Update */
852
132
    *dst = 0x20;
853
132
    dst = h2o_hpack_encode_int(dst, table->hpack_capacity, 5);
854
855
132
    return dst;
856
9.12k
}
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
18.2k
{
861
18.2k
    int is_token = h2o_iovec_is_token(name);
862
18.2k
    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
18.2k
    {
866
18.2k
        size_t header_table_index = header_table->entry_start_index, n;
867
28.2k
        for (n = header_table->num_entries; n != 0; --n) {
868
20.2k
            struct st_h2o_hpack_header_table_entry_t *entry = header_table->entries + header_table_index;
869
20.2k
            if (is_token) {
870
20.2k
                if (name != entry->name)
871
9.96k
                    goto Next;
872
20.2k
            } 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.2k
            if (!h2o_memis(value->base, value->len, entry->value->base, entry->value->len))
880
18
                goto Next;
881
            /* name and value matched! */
882
10.2k
            *dst = 0x80;
883
10.2k
            dst = h2o_hpack_encode_int(dst, header_table->num_entries - n + HEADER_TABLE_OFFSET, 7);
884
10.2k
            return dst;
885
9.97k
        Next:
886
9.97k
            ++header_table_index;
887
9.97k
            if (header_table_index == header_table->entry_capacity)
888
2.83k
                header_table_index = 0;
889
9.97k
        }
890
18.2k
    }
891
892
7.99k
    if (!dont_compress && is_token)
893
7.99k
        dont_compress = ((const h2o_token_t *)name)->flags.dont_compress;
894
7.99k
    if (dont_compress)
895
0
        dont_compress = value->len < 20;
896
897
7.99k
    if (name_index != 0) {
898
        /* literal header field with indexing (indexed name). */
899
7.99k
        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
7.99k
        } else {
904
7.99k
            *dst = 0x40;
905
7.99k
            dst = h2o_hpack_encode_int(dst, name_index, 6);
906
7.99k
        }
907
7.99k
    } 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
7.99k
    if (dont_compress == 1) {
913
        /* bypass huffman encoding */
914
0
        dst += encode_as_is(dst, value->base, value->len);
915
7.99k
    } 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
7.99k
        dst += h2o_hpack_encode_string(dst, value->base, value->len);
920
7.99k
        struct st_h2o_hpack_header_table_entry_t *entry =
921
7.99k
            header_table_add(header_table, name->len + value->len + HEADER_TABLE_ENTRY_SIZE_OFFSET, 32);
922
7.99k
        if (entry != NULL) {
923
7.05k
            if (is_token) {
924
7.05k
                entry->name = (h2o_iovec_t *)name;
925
7.05k
            } 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
7.05k
            entry->value = alloc_buf(NULL, value->len);
931
7.05k
            entry->value->base[value->len] = '\0';
932
7.05k
            memcpy(entry->value->base, value->base, value->len);
933
7.05k
        }
934
7.99k
    }
935
936
7.99k
    return dst;
937
18.2k
}
938
939
static uint8_t *encode_header(h2o_hpack_header_table_t *header_table, uint8_t *dst, const h2o_header_t *header)
940
9.12k
{
941
9.12k
    return do_encode_header(header_table, dst, header->name, &header->value, header->flags.dont_compress);
942
9.12k
}
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
9.12k
{
947
9.12k
    return do_encode_header(header_table, dst, &token->buf, value, token->flags.dont_compress);
948
9.12k
}
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
9.12k
{
1000
9.12k
    return name_len + value_len + 1 + H2O_HPACK_ENCODE_INT_MAX_LENGTH * 2;
1001
9.12k
}
1002
1003
static size_t calc_headers_capacity(const h2o_header_t *headers, size_t num_headers)
1004
9.12k
{
1005
9.12k
    const h2o_header_t *header;
1006
9.12k
    size_t capacity = 0;
1007
18.2k
    for (header = headers; num_headers != 0; ++header, --num_headers)
1008
9.12k
        capacity += calc_capacity(header->name->len, header->value.len);
1009
9.12k
    return capacity;
1010
9.12k
}
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
9.12k
{
1015
    /* try to fit all data into single frame, using the preallocated space for the frame header */
1016
9.12k
    size_t payload_size = (*buf)->size - start_at - H2O_HTTP2_FRAME_HEADER_SIZE;
1017
9.12k
    if (payload_size <= max_frame_size) {
1018
9.12k
        h2o_http2_encode_frame_header((uint8_t *)((*buf)->bytes + start_at), payload_size, type,
1019
9.12k
                                      H2O_HTTP2_FRAME_FLAG_END_HEADERS | flags, stream_id);
1020
9.12k
        return;
1021
9.12k
    }
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
9.12k
{
1141
9.12k
    size_t capacity = calc_headers_capacity(headers, num_headers);
1142
9.12k
    capacity += H2O_HTTP2_FRAME_HEADER_SIZE; /* for the first header */
1143
9.12k
    capacity += DYNAMIC_TABLE_SIZE_UPDATE_MAX_SIZE;
1144
9.12k
    capacity += STATUS_HEADER_MAX_SIZE; /* for :status: */
1145
9.12k
#ifndef H2O_UNITTEST
1146
9.12k
    if (server_name != NULL && server_name->len) {
1147
9.12k
        capacity += 5 + server_name->len; /* for Server: */
1148
9.12k
    }
1149
9.12k
#endif
1150
9.12k
    if (content_length != SIZE_MAX)
1151
8.39k
        capacity += CONTENT_LENGTH_HEADER_MAX_SIZE; /* for content-length: UINT64_MAX (with huffman compression applied) */
1152
1153
9.12k
    size_t start_at = (*buf)->size;
1154
9.12k
    uint8_t *dst = (void *)(h2o_buffer_reserve(buf, capacity).base + H2O_HTTP2_FRAME_HEADER_SIZE); /* skip frame header */
1155
1156
    /* encode */
1157
9.12k
    dst = header_table_adjust_size(header_table, hpack_capacity, dst);
1158
9.12k
    dst = encode_status(dst, status);
1159
9.12k
#ifndef H2O_UNITTEST
1160
    /* TODO keep some kind of reference to the indexed Server header, and reuse it */
1161
9.12k
    if (server_name != NULL && server_name->len) {
1162
9.12k
        dst = encode_header_token(header_table, dst, H2O_TOKEN_SERVER, server_name);
1163
9.12k
    }
1164
9.12k
#endif
1165
18.2k
    for (size_t i = 0; i != num_headers; ++i)
1166
9.12k
        dst = encode_header(header_table, dst, headers + i);
1167
9.12k
    if (content_length != SIZE_MAX)
1168
8.39k
        dst = encode_content_length(dst, content_length);
1169
9.12k
    (*buf)->size = (char *)dst - (*buf)->bytes;
1170
9.12k
    size_t headers_size = (*buf)->size - start_at - H2O_HTTP2_FRAME_HEADER_SIZE;
1171
1172
    /* setup the frame headers */
1173
9.12k
    fixup_frame_headers(buf, start_at, H2O_HTTP2_FRAME_TYPE_HEADERS, stream_id, max_frame_size,
1174
9.12k
                        is_end_stream ? H2O_HTTP2_FRAME_FLAG_END_STREAM : 0);
1175
1176
9.12k
    return headers_size;
1177
9.12k
}
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
}