Coverage Report

Created: 2026-10-17 07:02

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
254k
#define HEADER_TABLE_OFFSET 62
30
43.5k
#define HEADER_TABLE_ENTRY_SIZE_OFFSET 32
31
9.68k
#define DYNAMIC_TABLE_SIZE_UPDATE_MAX_SIZE 5
32
9.68k
#define STATUS_HEADER_MAX_SIZE 5
33
#define CONTENT_LENGTH_HEADER_MAX_SIZE                                                                                             \
34
8.99k
    (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
44.7k
{
40
44.7k
    return &h2o_hpack_static_table[0].value <= value &&
41
44.7k
           value <= &h2o_hpack_static_table[sizeof(h2o_hpack_static_table) / sizeof(h2o_hpack_static_table[0]) - 1].value;
42
44.7k
}
43
44
static h2o_iovec_t *alloc_buf(h2o_mem_pool_t *pool, size_t len)
45
134k
{
46
134k
    h2o_iovec_t *buf = h2o_mem_alloc_shared(pool, sizeof(h2o_iovec_t) + len + 1, NULL);
47
134k
    buf->base = (char *)buf + sizeof(h2o_iovec_t);
48
134k
    buf->len = len;
49
134k
    return buf;
50
134k
}
51
52
int64_t h2o_hpack_decode_int(const uint8_t **src, const uint8_t *src_end, unsigned prefix_bits)
53
562k
{
54
562k
    uint64_t value;
55
562k
    unsigned shift;
56
562k
    uint8_t prefix_max = (1 << prefix_bits) - 1;
57
58
562k
    if (*src >= src_end)
59
2
        return H2O_HTTP2_ERROR_INCOMPLETE;
60
61
562k
    value = *(*src)++ & prefix_max;
62
562k
    if (value != prefix_max)
63
523k
        return (int64_t)value;
64
65
    /* decode upto 8 octets (excluding prefix), that are guaranteed not to cause overflow */
66
38.3k
    value = prefix_max;
67
63.5k
    for (shift = 0; shift < 56; shift += 7) {
68
62.7k
        if (*src == src_end)
69
188
            return H2O_HTTP2_ERROR_INCOMPLETE;
70
62.5k
        value += (uint64_t)(**src & 127) << shift;
71
62.5k
        if ((*(*src)++ & 128) == 0)
72
37.4k
            return (int64_t)value;
73
62.5k
    }
74
    /* handling the 9th octet */
75
807
    if (*src == src_end)
76
15
        return H2O_HTTP2_ERROR_INCOMPLETE;
77
792
    if ((**src & 128) != 0)
78
74
        return H2O_HTTP2_ERROR_COMPRESSION;
79
718
    value += (uint64_t)(*(*src)++ & 127) << shift;
80
718
    if (value > (uint64_t)INT64_MAX)
81
7
        return H2O_HTTP2_ERROR_COMPRESSION;
82
711
    return value;
83
718
}
84
85
static char *huffdecode4(char *dst, uint8_t in, uint8_t *state, int *maybe_eos, uint8_t *seen_char_types)
86
1.78M
{
87
1.78M
    const nghttp2_huff_decode *entry = huff_decode_table[*state] + in;
88
89
1.78M
    if ((entry->flags & NGHTTP2_HUFF_FAIL) != 0)
90
16
        return NULL;
91
1.78M
    if ((entry->flags & NGHTTP2_HUFF_SYM) != 0) {
92
1.17M
        *dst++ = entry->sym;
93
1.17M
        *seen_char_types |= (entry->flags & NGHTTP2_HUFF_INVALID_CHARS);
94
1.17M
    }
95
1.78M
    *state = entry->state;
96
1.78M
    *maybe_eos = (entry->flags & NGHTTP2_HUFF_ACCEPTED) != 0;
97
98
1.78M
    return dst;
99
1.78M
}
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
133k
{
112
133k
    if (len != 0 && (s[0] == 0x20 || s[0] == 0x09 || s[len - 1] == 0x20 || s[len - 1] == 0x09))
113
4.20k
        return 0;
114
128k
    return 1;
115
133k
}
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.9k
{
120
40.9k
    char *dst = _dst;
121
40.9k
    const uint8_t *src_end = src + len;
122
40.9k
    uint8_t state = 0, seen_char_types = 0;
123
40.9k
    int maybe_eos = 1;
124
125
    /* decode */
126
932k
    for (; src < src_end; src++) {
127
891k
        if ((dst = huffdecode4(dst, *src >> 4, &state, &maybe_eos, &seen_char_types)) == NULL)
128
9
            return SIZE_MAX;
129
891k
        if ((dst = huffdecode4(dst, *src & 0xf, &state, &maybe_eos, &seen_char_types)) == NULL)
130
7
            return SIZE_MAX;
131
891k
    }
132
40.9k
    if (!maybe_eos)
133
224
        return SIZE_MAX;
134
135
    /* validate */
136
40.7k
    if (is_name) {
137
15.6k
        if (dst == _dst) {
138
1.15k
            *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.67k
                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.67k
                } else {
146
9.67k
                    *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_NAME;
147
9.67k
                }
148
9.67k
            }
149
14.4k
        }
150
25.0k
    } else {
151
25.0k
        if ((seen_char_types & NGHTTP2_HUFF_INVALID_FOR_HEADER_VALUE) != 0 || !header_value_valid_as_whole(_dst, dst - _dst))
152
1.77k
            *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_VALUE;
153
25.0k
    }
154
155
40.7k
    return dst - _dst;
156
40.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
69.0k
{
165
    /* all printable chars, except upper case and separator characters */
166
69.0k
    static const char valid_h2_header_name_char[] = {
167
69.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
69.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
69.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
69.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
69.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
69.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
69.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
69.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
69.0k
    };
176
177
69.0k
    if (len == 0) {
178
26.2k
        *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_NAME;
179
42.8k
    } else {
180
490k
        for (; len != 0; ++s, --len) {
181
447k
            unsigned char ch = (unsigned char)*s;
182
447k
            if (!valid_h2_header_name_char[ch]) {
183
110k
                if (ch - 'A' < 26U) {
184
158
                    *err_desc = h2o_hpack_err_found_upper_case_in_header_name;
185
158
                    return 0;
186
158
                }
187
110k
                *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_NAME;
188
110k
            }
189
447k
        }
190
42.8k
    }
191
68.9k
    return 1;
192
69.0k
}
193
194
void h2o_hpack_validate_header_value(unsigned *soft_errors, const char *s, size_t len)
195
108k
{
196
    /* surrounding whitespace RFC 9113 8.2.1 */
197
108k
    if (!header_value_valid_as_whole(s, len))
198
2.98k
        goto Invalid;
199
200
    /* all printable chars + horizontal tab (RFC 7230 3.2) */
201
105k
    static const char valid_h2_field_value_char[] = {
202
105k
        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
105k
        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
105k
        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
105k
        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
105k
        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
105k
        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
105k
        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
105k
        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
105k
    };
211
212
400k
    for (; len != 0; ++s, --len) {
213
325k
        unsigned char ch = (unsigned char)*s;
214
325k
        if (!valid_h2_field_value_char[ch])
215
30.5k
            goto Invalid;
216
325k
    }
217
74.9k
    return;
218
219
74.9k
Invalid:
220
33.5k
    *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_VALUE;
221
33.5k
}
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
130k
{
226
130k
    h2o_iovec_t *ret;
227
130k
    int is_huffman;
228
130k
    int64_t len;
229
230
130k
    if (*src >= src_end)
231
666
        return NULL;
232
233
129k
    is_huffman = (**src & 0x80) != 0;
234
129k
    if ((len = h2o_hpack_decode_int(src, src_end, 7)) < 0)
235
36
        return NULL;
236
237
129k
    if (is_huffman) {
238
16.3k
        if (len > src_end - *src)
239
489
            return NULL;
240
15.8k
        ret = alloc_buf(pool, len * 2); /* max compression ratio is >= 0.5 */
241
15.8k
        if ((ret->len = h2o_hpack_decode_huffman(ret->base, soft_errors, *src, len, is_header_name, err_desc)) == SIZE_MAX)
242
118
            return NULL;
243
15.7k
        ret->base[ret->len] = '\0';
244
113k
    } else {
245
113k
        if (len > src_end - *src)
246
1.32k
            return NULL;
247
111k
        if (is_header_name) {
248
            /* pseudo-headers are checked later in `decode_header` */
249
47.6k
            if ((len == 0 || **src != (uint8_t)':') && !h2o_hpack_validate_header_name(soft_errors, (char *)*src, len, err_desc))
250
71
                return NULL;
251
64.0k
        } else {
252
64.0k
            h2o_hpack_validate_header_value(soft_errors, (char *)*src, len);
253
64.0k
        }
254
111k
        ret = alloc_buf(pool, len);
255
111k
        memcpy(ret->base, *src, len);
256
111k
        ret->base[len] = '\0';
257
111k
    }
258
127k
    *src += len;
259
260
127k
    return ret;
261
129k
}
262
263
static void header_table_evict_one(h2o_hpack_header_table_t *table)
264
9.06k
{
265
9.06k
    struct st_h2o_hpack_header_table_entry_t *entry;
266
9.06k
    assert(table->num_entries != 0);
267
268
9.06k
    entry = h2o_hpack_header_table_get(table, --table->num_entries);
269
9.06k
    table->hpack_size -= entry->name->len + entry->value->len + HEADER_TABLE_ENTRY_SIZE_OFFSET;
270
9.06k
    if (!h2o_iovec_is_token(entry->name))
271
1.69k
        h2o_mem_release_shared(entry->name);
272
9.06k
    if (!value_is_part_of_static_table(entry->value))
273
9.06k
        h2o_mem_release_shared(entry->value);
274
9.06k
    memset(entry, 0, sizeof(*entry));
275
9.06k
}
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
34.5k
{
280
    /* adjust the size */
281
38.2k
    while (table->num_entries != 0 && table->hpack_size + size_add > table->hpack_capacity)
282
3.70k
        header_table_evict_one(table);
283
34.5k
    while (max_num_entries <= table->num_entries)
284
0
        header_table_evict_one(table);
285
34.5k
    if (table->num_entries == 0) {
286
18.7k
        assert(table->hpack_size == 0);
287
18.7k
        if (size_add > table->hpack_capacity)
288
8.79k
            return NULL;
289
18.7k
    }
290
25.7k
    table->hpack_size += size_add;
291
292
    /* grow the entries if full */
293
25.7k
    if (table->num_entries == table->entry_capacity) {
294
7.54k
        size_t new_capacity = table->num_entries * 2;
295
7.54k
        if (new_capacity < 16)
296
7.31k
            new_capacity = 16;
297
7.54k
        struct st_h2o_hpack_header_table_entry_t *new_entries =
298
7.54k
            h2o_mem_alloc(new_capacity * sizeof(struct st_h2o_hpack_header_table_entry_t));
299
7.54k
        if (table->num_entries != 0) {
300
231
            size_t src_index = table->entry_start_index, dst_index = 0;
301
6.72k
            do {
302
6.72k
                new_entries[dst_index] = table->entries[src_index];
303
6.72k
                ++dst_index;
304
6.72k
                src_index = (src_index + 1) % table->entry_capacity;
305
6.72k
            } while (dst_index != table->num_entries);
306
231
        }
307
7.54k
        memset(new_entries + table->num_entries, 0, sizeof(*new_entries) * (new_capacity - table->num_entries));
308
7.54k
        free(table->entries);
309
7.54k
        table->entries = new_entries;
310
7.54k
        table->entry_capacity = new_capacity;
311
7.54k
        table->entry_start_index = 0;
312
7.54k
    }
313
314
25.7k
    ++table->num_entries;
315
25.7k
    table->entry_start_index = (table->entry_start_index + table->entry_capacity - 1) % table->entry_capacity;
316
25.7k
    return table->entries + table->entry_start_index;
317
34.5k
}
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
189k
{
322
189k
    h2o_hpack_header_table_t *hpack_header_table = _hpack_header_table;
323
189k
    h2o_iovec_t *name = NULL, *value = NULL;
324
189k
    int64_t index = 0;
325
189k
    int value_is_indexed = 0, do_index = 0;
326
327
221k
Redo:
328
221k
    if (*src >= src_end)
329
106
        return H2O_HTTP2_ERROR_COMPRESSION;
330
331
    /* determine the mode and handle accordingly */
332
221k
    if (**src >= 128) {
333
        /* indexed header field representation */
334
108k
        if ((index = h2o_hpack_decode_int(src, src_end, 7)) <= 0)
335
79
            return H2O_HTTP2_ERROR_COMPRESSION;
336
108k
        value_is_indexed = 1;
337
113k
    } else if (**src >= 64) {
338
        /* literal header field with incremental handling */
339
27.6k
        if (**src == 64) {
340
5.77k
            ++*src;
341
21.8k
        } else if ((index = h2o_hpack_decode_int(src, src_end, 6)) <= 0) {
342
10
            return H2O_HTTP2_ERROR_COMPRESSION;
343
10
        }
344
27.6k
        do_index = 1;
345
86.0k
    } else if (**src < 32) {
346
        /* literal header field without indexing / never indexed */
347
53.6k
        if ((**src & 0xf) == 0) {
348
43.7k
            ++*src;
349
43.7k
        } else if ((index = h2o_hpack_decode_int(src, src_end, 4)) <= 0) {
350
23
            return H2O_HTTP2_ERROR_COMPRESSION;
351
23
        }
352
53.6k
    } else {
353
        /* size update */
354
32.4k
        int64_t new_capacity;
355
32.4k
        if ((new_capacity = h2o_hpack_decode_int(src, src_end, 5)) < 0) {
356
34
            return H2O_HTTP2_ERROR_COMPRESSION;
357
34
        }
358
32.3k
        if (new_capacity > hpack_header_table->hpack_max_capacity) {
359
239
            return H2O_HTTP2_ERROR_COMPRESSION;
360
239
        }
361
32.1k
        hpack_header_table->hpack_capacity = (size_t)new_capacity;
362
37.4k
        while (hpack_header_table->num_entries != 0 && hpack_header_table->hpack_size > hpack_header_table->hpack_capacity) {
363
5.34k
            header_table_evict_one(hpack_header_table);
364
5.34k
        }
365
32.1k
        goto Redo;
366
32.3k
    }
367
368
    /* determine the header */
369
189k
    unsigned soft_errors = 0;
370
189k
    if (index > 0) {
371
        /* existing name (and value?) */
372
139k
        if (index < HEADER_TABLE_OFFSET) {
373
87.7k
            name = (h2o_iovec_t *)h2o_hpack_static_table[index - 1].name;
374
87.7k
            if (value_is_indexed)
375
57.2k
                value = (h2o_iovec_t *)&h2o_hpack_static_table[index - 1].value;
376
87.7k
        } else if (index - HEADER_TABLE_OFFSET < hpack_header_table->num_entries) {
377
51.1k
            struct st_h2o_hpack_header_table_entry_t *entry =
378
51.1k
                h2o_hpack_header_table_get(hpack_header_table, index - HEADER_TABLE_OFFSET);
379
51.1k
            soft_errors = entry->soft_errors;
380
51.1k
            name = entry->name;
381
51.1k
            if (!h2o_iovec_is_token(name))
382
10.3k
                h2o_mem_link_shared(pool, name);
383
51.1k
            if (value_is_indexed) {
384
50.2k
                value = entry->value;
385
50.2k
                h2o_mem_link_shared(pool, value);
386
50.2k
            }
387
51.1k
        } else {
388
883
            return H2O_HTTP2_ERROR_COMPRESSION;
389
883
        }
390
139k
    } else {
391
        /* non-existing name */
392
49.4k
        const h2o_token_t *name_token;
393
49.4k
        if ((name = decode_string(pool, &soft_errors, src, src_end, 1, err_desc)) == NULL) {
394
380
            if (*err_desc == h2o_hpack_err_found_upper_case_in_header_name)
395
71
                return H2O_HTTP2_ERROR_PROTOCOL;
396
309
            return H2O_HTTP2_ERROR_COMPRESSION;
397
380
        }
398
        /* predefined header names should be interned */
399
49.1k
        if ((name_token = h2o_lookup_token(name->base, name->len)) != NULL)
400
5.92k
            name = (h2o_iovec_t *)&name_token->buf;
401
49.1k
    }
402
403
    /* determine the value (if necessary) */
404
188k
    if (!value_is_indexed) {
405
80.5k
        soft_errors &= ~H2O_HPACK_SOFT_ERROR_BIT_INVALID_VALUE;
406
80.5k
        if ((value = decode_string(pool, &soft_errors, src, src_end, 0, err_desc)) == NULL)
407
2.32k
            return H2O_HTTP2_ERROR_COMPRESSION;
408
80.5k
    }
409
410
    /* add the decoded header to the header table if necessary */
411
185k
    if (do_index) {
412
26.5k
        struct st_h2o_hpack_header_table_entry_t *entry =
413
26.5k
            header_table_add(hpack_header_table, name->len + value->len + HEADER_TABLE_ENTRY_SIZE_OFFSET, SIZE_MAX);
414
26.5k
        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
3.81k
                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
26.5k
    }
424
425
185k
    *_name = name;
426
185k
    *_value = *value;
427
185k
    if (soft_errors != 0) {
428
69.8k
        *err_desc = (soft_errors & H2O_HPACK_SOFT_ERROR_BIT_INVALID_NAME) != 0
429
69.8k
                        ? h2o_hpack_soft_err_found_invalid_char_in_header_name
430
69.8k
                        : h2o_hpack_soft_err_found_invalid_char_in_header_value;
431
69.8k
        return H2O_HTTP2_ERROR_INVALID_HEADER_CHAR;
432
115k
    } else {
433
115k
        return 0;
434
115k
    }
435
185k
}
436
437
static uint8_t *encode_status(uint8_t *dst, int status)
438
9.68k
{
439
    /* see also: STATUS_HEADER_MAX_SIZE */
440
441
9.68k
    assert(100 <= status && status <= 999);
442
443
9.68k
    switch (status) {
444
0
#define COMMON_CODE(code, st)                                                                                                      \
445
9.13k
    case st:                                                                                                                       \
446
9.13k
        *dst++ = 0x80 | code;                                                                                                      \
447
9.13k
        break
448
692
        COMMON_CODE(8, 200);
449
0
        COMMON_CODE(9, 204);
450
0
        COMMON_CODE(10, 206);
451
0
        COMMON_CODE(11, 304);
452
3.17k
        COMMON_CODE(12, 400);
453
5.26k
        COMMON_CODE(13, 404);
454
0
        COMMON_CODE(14, 500);
455
0
#undef COMMON_CODE
456
550
    default:
457
        /* use literal header field without indexing - indexed name */
458
550
        *dst++ = 8;
459
550
        *dst++ = 3;
460
550
        sprintf((char *)dst, "%d", status);
461
550
        dst += 3;
462
550
        break;
463
9.68k
    }
464
465
9.68k
    return dst;
466
9.68k
}
467
468
static uint8_t *encode_content_length(uint8_t *dst, size_t value)
469
8.99k
{
470
8.99k
    char buf[32], *p = buf + sizeof(buf);
471
8.99k
    size_t l;
472
473
12.6k
    do {
474
12.6k
        *--p = '0' + value % 10;
475
12.6k
    } while ((value /= 10) != 0);
476
8.99k
    l = buf + sizeof(buf) - p;
477
8.99k
    *dst++ = 0x0f;
478
8.99k
    *dst++ = 0x0d;
479
8.99k
    *dst++ = (uint8_t)l;
480
8.99k
    memcpy(dst, p, l);
481
8.99k
    dst += l;
482
483
8.99k
    return dst;
484
8.99k
}
485
486
void h2o_hpack_dispose_header_table(h2o_hpack_header_table_t *header_table)
487
26.3k
{
488
26.3k
    if (header_table->num_entries != 0) {
489
6.32k
        size_t index = header_table->entry_start_index;
490
16.6k
        do {
491
16.6k
            struct st_h2o_hpack_header_table_entry_t *entry = header_table->entries + index;
492
16.6k
            if (!h2o_iovec_is_token(entry->name))
493
2.11k
                h2o_mem_release_shared(entry->name);
494
16.6k
            if (!value_is_part_of_static_table(entry->value))
495
16.6k
                h2o_mem_release_shared(entry->value);
496
16.6k
            index = (index + 1) % header_table->entry_capacity;
497
16.6k
        } while (--header_table->num_entries != 0);
498
6.32k
    }
499
26.3k
    free(header_table->entries);
500
26.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
25.8k
{
508
25.8k
    const uint8_t *src_end = src + len;
509
25.8k
    size_t num_headers_decoded = 0;
510
511
25.8k
    *content_length = SIZE_MAX;
512
513
400k
    while (src != src_end) {
514
382k
        h2o_iovec_t *name, value;
515
382k
        const char *decode_err = NULL;
516
382k
        int ret = decode_cb(pool, decode_ctx, &name, &value, &src, src_end, &decode_err);
517
382k
        if (ret != 0) {
518
108k
            if (ret == H2O_HTTP2_ERROR_INVALID_HEADER_CHAR) {
519
                /* this is a soft error, we continue parsing, but register only the first error */
520
101k
                if (*err_desc == NULL) {
521
6.84k
                    *err_desc = decode_err;
522
6.84k
                }
523
101k
            } else {
524
7.30k
                *err_desc = decode_err;
525
7.30k
                return ret;
526
7.30k
            }
527
108k
        }
528
375k
        ++num_headers_decoded;
529
375k
        if (num_headers_decoded > H2O_HPACK_MAX_HEADERS_HARD_LIMIT) {
530
31
            *err_desc = h2o_hpack_err_headers_too_long;
531
31
            return H2O_HTTP2_ERROR_COMPRESSION;
532
31
        }
533
375k
        if (name->base[0] == ':') {
534
48.5k
            if (pseudo_header_exists_map != NULL) {
535
                /* FIXME validate the chars in the value (e.g. reject SP in path) */
536
48.3k
                if (name == &H2O_TOKEN_AUTHORITY->buf) {
537
9.14k
                    if (authority->base != NULL) {
538
8
                        *err_desc = h2o_hpack_err_invalid_pseudo_header;
539
8
                        return H2O_HTTP2_ERROR_PROTOCOL;
540
8
                    }
541
9.13k
                    *authority = value;
542
9.13k
                    *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_AUTHORITY_EXISTS;
543
39.1k
                } else if (name == &H2O_TOKEN_METHOD->buf) {
544
13.7k
                    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.7k
                    *method = value;
549
13.7k
                    *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_METHOD_EXISTS;
550
25.4k
                } 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
25.4k
                } else if (name == &H2O_TOKEN_PATH->buf) {
556
12.5k
                    if (path->base != NULL) {
557
8
                        *err_desc = h2o_hpack_err_invalid_pseudo_header;
558
8
                        return H2O_HTTP2_ERROR_PROTOCOL;
559
8
                    }
560
12.5k
                    if (value.len == 0) {
561
4
                        *err_desc = h2o_hpack_err_invalid_pseudo_header;
562
4
                        return H2O_HTTP2_ERROR_PROTOCOL;
563
4
                    }
564
12.5k
                    *path = value;
565
12.5k
                    *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_PATH_EXISTS;
566
12.8k
                } else if (name == &H2O_TOKEN_SCHEME->buf) {
567
12.8k
                    if (*scheme != NULL) {
568
14
                        *err_desc = h2o_hpack_err_invalid_pseudo_header;
569
14
                        return H2O_HTTP2_ERROR_PROTOCOL;
570
14
                    }
571
12.7k
                    if (h2o_memis(value.base, value.len, H2O_STRLIT("https"))) {
572
1.69k
                        *scheme = &H2O_URL_SCHEME_HTTPS;
573
11.1k
                    } else if (h2o_memis(value.base, value.len, H2O_STRLIT("masque"))) {
574
3
                        *scheme = &H2O_URL_SCHEME_MASQUE;
575
11.0k
                    } else {
576
                        /* draft-16 8.1.2.3 suggests quote: ":scheme is not restricted to http and https schemed URIs" */
577
11.0k
                        *scheme = &H2O_URL_SCHEME_HTTP;
578
11.0k
                    }
579
12.7k
                    *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_SCHEME_EXISTS;
580
12.7k
                } else {
581
35
                    return H2O_HTTP2_ERROR_PROTOCOL;
582
35
                }
583
48.3k
            } else {
584
256
                *err_desc = h2o_hpack_err_invalid_pseudo_header;
585
256
                return H2O_HTTP2_ERROR_PROTOCOL;
586
256
            }
587
326k
        } else {
588
326k
            pseudo_header_exists_map = NULL;
589
326k
            if (h2o_iovec_is_token(name)) {
590
241k
                h2o_token_t *token = H2O_STRUCT_FROM_MEMBER(h2o_token_t, buf, name);
591
241k
                if (token->flags.is_hpack_special) {
592
32.5k
                    if (token == H2O_TOKEN_CONTENT_LENGTH) {
593
6.90k
                        if ((*content_length = h2o_strtosize(value.base, value.len)) == SIZE_MAX) {
594
115
                            *err_desc = h2o_hpack_err_invalid_content_length_header;
595
115
                            return H2O_HTTP2_ERROR_PROTOCOL;
596
115
                        }
597
6.79k
                        goto Next;
598
25.6k
                    } else if (token == H2O_TOKEN_EXPECT) {
599
5.39k
                        *expect = value;
600
5.39k
                        goto Next;
601
20.2k
                    } 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
470
                            *authority = value;
605
1.95k
                        goto Next;
606
18.2k
                    } else if (token == H2O_TOKEN_TE && h2o_lcstris(value.base, value.len, H2O_STRLIT("trailers"))) {
607
                        /* do not reject */
608
17.2k
                    } 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.6k
                        h2o_cache_digests_load_header(digests, value.base, value.len);
611
16.6k
                    } else if (token == H2O_TOKEN_DATAGRAM_FLOW_ID) {
612
557
                        if (datagram_flow_id != NULL)
613
86
                            *datagram_flow_id = value;
614
557
                        goto Next;
615
557
                    } else {
616
                        /* rest of the header fields that are marked as special are rejected */
617
75
                        *err_desc = h2o_hpack_err_unexpected_connection_specific_header;
618
75
                        return H2O_HTTP2_ERROR_PROTOCOL;
619
75
                    }
620
32.5k
                }
621
226k
                if (headers->size < H2O_MAX_HEADERS) {
622
118k
                    h2o_add_header(pool, headers, token, NULL, value.base, value.len);
623
118k
                } else if (*err_desc == NULL) {
624
65
                    *err_desc = h2o_hpack_err_headers_too_long;
625
65
                }
626
226k
            } else {
627
85.9k
                if (headers->size < H2O_MAX_HEADERS) {
628
43.1k
                    h2o_add_header_by_str(pool, headers, name->base, name->len, 0, NULL, value.base, value.len);
629
43.1k
                } else if (*err_desc == NULL) {
630
6
                    *err_desc = h2o_hpack_err_headers_too_long;
631
6
                }
632
85.9k
            }
633
326k
        }
634
375k
    Next:;
635
375k
    }
636
637
17.9k
    if (*err_desc != NULL)
638
3.98k
        return H2O_HTTP2_ERROR_INVALID_HEADER_CHAR;
639
13.9k
    return 0;
640
17.9k
}
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
43.5k
{
754
43.5k
    return value < (1 << prefix_bits) - 1;
755
43.5k
}
756
757
uint8_t *h2o_hpack_encode_int(uint8_t *dst, int64_t value, unsigned prefix_bits)
758
35.5k
{
759
35.5k
    if (encode_int_is_onebyte(value, prefix_bits)) {
760
31.9k
        *dst++ |= value;
761
31.9k
    } else {
762
        /* see also: MAX_ENCODE_INT_LENGTH */
763
3.58k
        assert(value >= 0);
764
3.58k
        value -= (1 << prefix_bits) - 1;
765
3.58k
        *dst++ |= (1 << prefix_bits) - 1;
766
3.61k
        for (; value >= 128; value >>= 7) {
767
27
            *dst++ = 0x80 | value;
768
27
        }
769
3.58k
        *dst++ = value;
770
3.58k
    }
771
35.5k
    return dst;
772
35.5k
}
773
774
size_t h2o_hpack_encode_huffman(uint8_t *_dst, const uint8_t *src, size_t len)
775
12.6k
{
776
12.6k
    uint8_t *dst = _dst, *dst_end = dst + len;
777
12.6k
    const uint8_t *src_end = src + len;
778
12.6k
    uint64_t bits = 0;
779
12.6k
    int bits_left = 40;
780
781
289k
    while (src != src_end) {
782
276k
        const nghttp2_huff_sym *sym = huff_sym_table + *src++;
783
276k
        bits |= (uint64_t)sym->code << (bits_left - sym->nbits);
784
276k
        bits_left -= sym->nbits;
785
472k
        while (bits_left <= 32) {
786
196k
            *dst++ = bits >> 32;
787
196k
            bits <<= 8;
788
196k
            bits_left += 8;
789
196k
            if (dst == dst_end) {
790
0
                return SIZE_MAX;
791
0
            }
792
196k
        }
793
276k
    }
794
795
12.6k
    if (bits_left != 40) {
796
12.6k
        bits |= ((uint64_t)1 << bits_left) - 1;
797
12.6k
        *dst++ = bits >> 32;
798
12.6k
    }
799
12.6k
    if (dst == dst_end) {
800
1.36k
        return SIZE_MAX;
801
1.36k
    }
802
803
11.2k
    return dst - _dst;
804
12.6k
}
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.68k
{
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.68k
    if (new_capacity >= table->hpack_capacity)
844
9.54k
        return dst;
845
846
    /* update state */
847
138
    table->hpack_capacity = new_capacity;
848
164
    while (table->num_entries != 0 && table->hpack_size > table->hpack_capacity)
849
26
        header_table_evict_one(table);
850
851
    /* encode Dynamic Table Size Update */
852
138
    *dst = 0x20;
853
138
    dst = h2o_hpack_encode_int(dst, table->hpack_capacity, 5);
854
855
138
    return dst;
856
9.68k
}
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
19.3k
{
861
19.3k
    int is_token = h2o_iovec_is_token(name);
862
19.3k
    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
19.3k
    {
866
19.3k
        size_t header_table_index = header_table->entry_start_index, n;
867
29.4k
        for (n = header_table->num_entries; n != 0; --n) {
868
21.4k
            struct st_h2o_hpack_header_table_entry_t *entry = header_table->entries + header_table_index;
869
21.4k
            if (is_token) {
870
21.4k
                if (name != entry->name)
871
10.0k
                    goto Next;
872
21.4k
            } 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
11.3k
            if (!h2o_memis(value->base, value->len, entry->value->base, entry->value->len))
880
24
                goto Next;
881
            /* name and value matched! */
882
11.3k
            *dst = 0x80;
883
11.3k
            dst = h2o_hpack_encode_int(dst, header_table->num_entries - n + HEADER_TABLE_OFFSET, 7);
884
11.3k
            return dst;
885
10.0k
        Next:
886
10.0k
            ++header_table_index;
887
10.0k
            if (header_table_index == header_table->entry_capacity)
888
2.83k
                header_table_index = 0;
889
10.0k
        }
890
19.3k
    }
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
6.72k
            if (is_token) {
924
6.72k
                entry->name = (h2o_iovec_t *)name;
925
6.72k
            } 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
6.72k
            entry->value = alloc_buf(NULL, value->len);
931
6.72k
            entry->value->base[value->len] = '\0';
932
6.72k
            memcpy(entry->value->base, value->base, value->len);
933
6.72k
        }
934
7.99k
    }
935
936
7.99k
    return dst;
937
19.3k
}
938
939
static uint8_t *encode_header(h2o_hpack_header_table_t *header_table, uint8_t *dst, const h2o_header_t *header)
940
9.68k
{
941
9.68k
    return do_encode_header(header_table, dst, header->name, &header->value, header->flags.dont_compress);
942
9.68k
}
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.68k
{
947
9.68k
    return do_encode_header(header_table, dst, &token->buf, value, token->flags.dont_compress);
948
9.68k
}
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.68k
{
1000
9.68k
    return name_len + value_len + 1 + H2O_HPACK_ENCODE_INT_MAX_LENGTH * 2;
1001
9.68k
}
1002
1003
static size_t calc_headers_capacity(const h2o_header_t *headers, size_t num_headers)
1004
9.68k
{
1005
9.68k
    const h2o_header_t *header;
1006
9.68k
    size_t capacity = 0;
1007
19.3k
    for (header = headers; num_headers != 0; ++header, --num_headers)
1008
9.68k
        capacity += calc_capacity(header->name->len, header->value.len);
1009
9.68k
    return capacity;
1010
9.68k
}
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.68k
{
1015
    /* try to fit all data into single frame, using the preallocated space for the frame header */
1016
9.68k
    size_t payload_size = (*buf)->size - start_at - H2O_HTTP2_FRAME_HEADER_SIZE;
1017
9.68k
    if (payload_size <= max_frame_size) {
1018
9.68k
        h2o_http2_encode_frame_header((uint8_t *)((*buf)->bytes + start_at), payload_size, type,
1019
9.68k
                                      H2O_HTTP2_FRAME_FLAG_END_HEADERS | flags, stream_id);
1020
9.68k
        return;
1021
9.68k
    }
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.68k
{
1141
9.68k
    size_t capacity = calc_headers_capacity(headers, num_headers);
1142
9.68k
    capacity += H2O_HTTP2_FRAME_HEADER_SIZE; /* for the first header */
1143
9.68k
    capacity += DYNAMIC_TABLE_SIZE_UPDATE_MAX_SIZE;
1144
9.68k
    capacity += STATUS_HEADER_MAX_SIZE; /* for :status: */
1145
9.68k
#ifndef H2O_UNITTEST
1146
9.68k
    if (server_name != NULL && server_name->len) {
1147
9.68k
        capacity += 5 + server_name->len; /* for Server: */
1148
9.68k
    }
1149
9.68k
#endif
1150
9.68k
    if (content_length != SIZE_MAX)
1151
8.99k
        capacity += CONTENT_LENGTH_HEADER_MAX_SIZE; /* for content-length: UINT64_MAX (with huffman compression applied) */
1152
1153
9.68k
    size_t start_at = (*buf)->size;
1154
9.68k
    uint8_t *dst = (void *)(h2o_buffer_reserve(buf, capacity).base + H2O_HTTP2_FRAME_HEADER_SIZE); /* skip frame header */
1155
1156
    /* encode */
1157
9.68k
    dst = header_table_adjust_size(header_table, hpack_capacity, dst);
1158
9.68k
    dst = encode_status(dst, status);
1159
9.68k
#ifndef H2O_UNITTEST
1160
    /* TODO keep some kind of reference to the indexed Server header, and reuse it */
1161
9.68k
    if (server_name != NULL && server_name->len) {
1162
9.68k
        dst = encode_header_token(header_table, dst, H2O_TOKEN_SERVER, server_name);
1163
9.68k
    }
1164
9.68k
#endif
1165
19.3k
    for (size_t i = 0; i != num_headers; ++i)
1166
9.68k
        dst = encode_header(header_table, dst, headers + i);
1167
9.68k
    if (content_length != SIZE_MAX)
1168
8.99k
        dst = encode_content_length(dst, content_length);
1169
9.68k
    (*buf)->size = (char *)dst - (*buf)->bytes;
1170
9.68k
    size_t headers_size = (*buf)->size - start_at - H2O_HTTP2_FRAME_HEADER_SIZE;
1171
1172
    /* setup the frame headers */
1173
9.68k
    fixup_frame_headers(buf, start_at, H2O_HTTP2_FRAME_TYPE_HEADERS, stream_id, max_frame_size,
1174
9.68k
                        is_end_stream ? H2O_HTTP2_FRAME_FLAG_END_STREAM : 0);
1175
1176
9.68k
    return headers_size;
1177
9.68k
}
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
}