Coverage Report

Created: 2026-04-06 06:11

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