Coverage Report

Created: 2025-11-24 06:34

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
547k
#define HEADER_TABLE_OFFSET 62
30
40.3k
#define HEADER_TABLE_ENTRY_SIZE_OFFSET 32
31
7.58k
#define DYNAMIC_TABLE_SIZE_UPDATE_MAX_SIZE 5
32
7.58k
#define STATUS_HEADER_MAX_SIZE 5
33
#define CONTENT_LENGTH_HEADER_MAX_SIZE                                                                                             \
34
6.94k
    (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
41.0k
{
40
41.0k
    return &h2o_hpack_static_table[0].value <= value &&
41
41.0k
           value <= &h2o_hpack_static_table[sizeof(h2o_hpack_static_table) / sizeof(h2o_hpack_static_table[0]) - 1].value;
42
41.0k
}
43
44
static h2o_iovec_t *alloc_buf(h2o_mem_pool_t *pool, size_t len)
45
145k
{
46
145k
    h2o_iovec_t *buf = h2o_mem_alloc_shared(pool, sizeof(h2o_iovec_t) + len + 1, NULL);
47
145k
    buf->base = (char *)buf + sizeof(h2o_iovec_t);
48
145k
    buf->len = len;
49
145k
    return buf;
50
145k
}
51
52
int64_t h2o_hpack_decode_int(const uint8_t **src, const uint8_t *src_end, unsigned prefix_bits)
53
1.16M
{
54
1.16M
    uint64_t value;
55
1.16M
    unsigned shift;
56
1.16M
    uint8_t prefix_max = (1 << prefix_bits) - 1;
57
58
1.16M
    if (*src >= src_end)
59
5
        return H2O_HTTP2_ERROR_INCOMPLETE;
60
61
1.16M
    value = *(*src)++ & prefix_max;
62
1.16M
    if (value != prefix_max)
63
1.12M
        return (int64_t)value;
64
65
    /* decode upto 8 octets (excluding prefix), that are guaranteed not to cause overflow */
66
39.9k
    value = prefix_max;
67
62.0k
    for (shift = 0; shift < 56; shift += 7) {
68
61.2k
        if (*src == src_end)
69
146
            return H2O_HTTP2_ERROR_INCOMPLETE;
70
61.0k
        value += (uint64_t)(**src & 127) << shift;
71
61.0k
        if ((*(*src)++ & 128) == 0)
72
38.9k
            return (int64_t)value;
73
61.0k
    }
74
    /* handling the 9th octet */
75
840
    if (*src == src_end)
76
8
        return H2O_HTTP2_ERROR_INCOMPLETE;
77
832
    if ((**src & 128) != 0)
78
64
        return H2O_HTTP2_ERROR_COMPRESSION;
79
768
    value += (uint64_t)(*(*src)++ & 127) << shift;
80
768
    if (value > (uint64_t)INT64_MAX)
81
6
        return H2O_HTTP2_ERROR_COMPRESSION;
82
762
    return value;
83
768
}
84
85
static char *huffdecode4(char *dst, uint8_t in, uint8_t *state, int *maybe_eos, uint8_t *seen_char_types)
86
1.79M
{
87
1.79M
    const nghttp2_huff_decode *entry = huff_decode_table[*state] + in;
88
89
1.79M
    if ((entry->flags & NGHTTP2_HUFF_FAIL) != 0)
90
30
        return NULL;
91
1.79M
    if ((entry->flags & NGHTTP2_HUFF_SYM) != 0) {
92
1.15M
        *dst++ = entry->sym;
93
1.15M
        *seen_char_types |= (entry->flags & NGHTTP2_HUFF_INVALID_CHARS);
94
1.15M
    }
95
1.79M
    *state = entry->state;
96
1.79M
    *maybe_eos = (entry->flags & NGHTTP2_HUFF_ACCEPTED) != 0;
97
98
1.79M
    return dst;
99
1.79M
}
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
153k
{
111
153k
    if (len != 0 && (s[0] == 0x20 || s[0] == 0x09 || s[len - 1] == 0x20 || s[len - 1] == 0x09))
112
3.48k
        return 0;
113
149k
    return 1;
114
153k
}
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
46.7k
{
119
46.7k
    char *dst = _dst;
120
46.7k
    const uint8_t *src_end = src + len;
121
46.7k
    uint8_t state = 0, seen_char_types = 0;
122
46.7k
    int maybe_eos = 1;
123
124
    /* decode */
125
942k
    for (; src < src_end; src++) {
126
895k
        if ((dst = huffdecode4(dst, *src >> 4, &state, &maybe_eos, &seen_char_types)) == NULL)
127
10
            return SIZE_MAX;
128
895k
        if ((dst = huffdecode4(dst, *src & 0xf, &state, &maybe_eos, &seen_char_types)) == NULL)
129
20
            return SIZE_MAX;
130
895k
    }
131
46.6k
    if (!maybe_eos)
132
257
        return SIZE_MAX;
133
134
    /* validate */
135
46.4k
    if (is_name) {
136
18.5k
        if (dst == _dst) {
137
812
            *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_NAME;
138
17.7k
        } else {
139
            /* pseudo-headers are checked later in `decode_header` */
140
17.7k
            if ((seen_char_types & NGHTTP2_HUFF_INVALID_FOR_HEADER_NAME) != 0 && _dst[0] != ':') {
141
12.6k
                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
12.6k
                } else {
145
12.6k
                    *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_NAME;
146
12.6k
                }
147
12.6k
            }
148
17.7k
        }
149
27.8k
    } else {
150
27.8k
        if ((seen_char_types & NGHTTP2_HUFF_INVALID_FOR_HEADER_VALUE) != 0 || !header_value_valid_as_whole(_dst, dst - _dst))
151
1.01k
            *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_VALUE;
152
27.8k
    }
153
154
46.4k
    return dst - _dst;
155
46.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
85.9k
{
164
    /* all printable chars, except upper case and separator characters */
165
85.9k
    static const char valid_h2_header_name_char[] = {
166
85.9k
        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
85.9k
        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
85.9k
        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
85.9k
        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
85.9k
        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
85.9k
        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
85.9k
        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
85.9k
        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
85.9k
    };
175
176
85.9k
    if (len == 0) {
177
37.9k
        *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_NAME;
178
47.9k
    } else {
179
514k
        for (; len != 0; ++s, --len) {
180
467k
            unsigned char ch = (unsigned char)*s;
181
467k
            if (!valid_h2_header_name_char[ch]) {
182
124k
                if (ch - 'A' < 26U) {
183
174
                    *err_desc = h2o_hpack_err_found_upper_case_in_header_name;
184
174
                    return 0;
185
174
                }
186
123k
                *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_NAME;
187
123k
            }
188
467k
        }
189
47.9k
    }
190
85.7k
    return 1;
191
85.9k
}
192
193
void h2o_hpack_validate_header_value(unsigned *soft_errors, const char *s, size_t len)
194
125k
{
195
    /* surrounding whitespace RFC 9113 8.2.1 */
196
125k
    if (!header_value_valid_as_whole(s, len))
197
2.88k
        goto Invalid;
198
199
    /* all printable chars + horizontal tab (RFC 7230 3.2) */
200
122k
    static const char valid_h2_field_value_char[] = {
201
122k
        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
122k
        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
122k
        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
122k
        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
122k
        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
122k
        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
122k
        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
122k
        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
122k
    };
210
211
465k
    for (; len != 0; ++s, --len) {
212
376k
        unsigned char ch = (unsigned char)*s;
213
376k
        if (!valid_h2_field_value_char[ch])
214
33.7k
            goto Invalid;
215
376k
    }
216
88.9k
    return;
217
218
88.9k
Invalid:
219
36.6k
    *soft_errors |= H2O_HPACK_SOFT_ERROR_BIT_INVALID_VALUE;
220
36.6k
}
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
142k
{
225
142k
    h2o_iovec_t *ret;
226
142k
    int is_huffman;
227
142k
    int64_t len;
228
229
142k
    if (*src >= src_end)
230
412
        return NULL;
231
232
141k
    is_huffman = (**src & 0x80) != 0;
233
141k
    if ((len = h2o_hpack_decode_int(src, src_end, 7)) < 0)
234
24
        return NULL;
235
236
141k
    if (is_huffman) {
237
13.9k
        if (len > src_end - *src)
238
447
            return NULL;
239
13.4k
        ret = alloc_buf(pool, len * 2); /* max compression ratio is >= 0.5 */
240
13.4k
        if ((ret->len = h2o_hpack_decode_huffman(ret->base, soft_errors, *src, len, is_header_name, err_desc)) == SIZE_MAX)
241
139
            return NULL;
242
13.3k
        ret->base[ret->len] = '\0';
243
127k
    } else {
244
127k
        if (len > src_end - *src)
245
1.22k
            return NULL;
246
126k
        if (is_header_name) {
247
            /* pseudo-headers are checked later in `decode_header` */
248
55.4k
            if ((len == 0 || **src != (uint8_t)':') && !h2o_hpack_validate_header_name(soft_errors, (char *)*src, len, err_desc))
249
93
                return NULL;
250
71.1k
        } else {
251
71.1k
            h2o_hpack_validate_header_value(soft_errors, (char *)*src, len);
252
71.1k
        }
253
126k
        ret = alloc_buf(pool, len);
254
126k
        memcpy(ret->base, *src, len);
255
126k
        ret->base[len] = '\0';
256
126k
    }
257
139k
    *src += len;
258
259
139k
    return ret;
260
141k
}
261
262
static void header_table_evict_one(h2o_hpack_header_table_t *table)
263
7.99k
{
264
7.99k
    struct st_h2o_hpack_header_table_entry_t *entry;
265
7.99k
    assert(table->num_entries != 0);
266
267
7.99k
    entry = h2o_hpack_header_table_get(table, --table->num_entries);
268
7.99k
    table->hpack_size -= entry->name->len + entry->value->len + HEADER_TABLE_ENTRY_SIZE_OFFSET;
269
7.99k
    if (!h2o_iovec_is_token(entry->name))
270
1.71k
        h2o_mem_release_shared(entry->name);
271
7.99k
    if (!value_is_part_of_static_table(entry->value))
272
7.99k
        h2o_mem_release_shared(entry->value);
273
7.99k
    memset(entry, 0, sizeof(*entry));
274
7.99k
}
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
32.3k
{
279
    /* adjust the size */
280
34.9k
    while (table->num_entries != 0 && table->hpack_size + size_add > table->hpack_capacity)
281
2.58k
        header_table_evict_one(table);
282
32.3k
    while (max_num_entries <= table->num_entries)
283
0
        header_table_evict_one(table);
284
32.3k
    if (table->num_entries == 0) {
285
17.0k
        assert(table->hpack_size == 0);
286
17.0k
        if (size_add > table->hpack_capacity)
287
9.09k
            return NULL;
288
17.0k
    }
289
23.2k
    table->hpack_size += size_add;
290
291
    /* grow the entries if full */
292
23.2k
    if (table->num_entries == table->entry_capacity) {
293
6.65k
        size_t new_capacity = table->num_entries * 2;
294
6.65k
        if (new_capacity < 16)
295
6.39k
            new_capacity = 16;
296
6.65k
        struct st_h2o_hpack_header_table_entry_t *new_entries =
297
6.65k
            h2o_mem_alloc(new_capacity * sizeof(struct st_h2o_hpack_header_table_entry_t));
298
6.65k
        if (table->num_entries != 0) {
299
260
            size_t src_index = table->entry_start_index, dst_index = 0;
300
7.29k
            do {
301
7.29k
                new_entries[dst_index] = table->entries[src_index];
302
7.29k
                ++dst_index;
303
7.29k
                src_index = (src_index + 1) % table->entry_capacity;
304
7.29k
            } while (dst_index != table->num_entries);
305
260
        }
306
6.65k
        memset(new_entries + table->num_entries, 0, sizeof(*new_entries) * (new_capacity - table->num_entries));
307
6.65k
        free(table->entries);
308
6.65k
        table->entries = new_entries;
309
6.65k
        table->entry_capacity = new_capacity;
310
6.65k
        table->entry_start_index = 0;
311
6.65k
    }
312
313
23.2k
    ++table->num_entries;
314
23.2k
    table->entry_start_index = (table->entry_start_index + table->entry_capacity - 1) % table->entry_capacity;
315
23.2k
    return table->entries + table->entry_start_index;
316
32.3k
}
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
291k
{
321
291k
    h2o_hpack_header_table_t *hpack_header_table = _hpack_header_table;
322
291k
    h2o_iovec_t *name = NULL, *value = NULL;
323
291k
    int64_t index = 0;
324
291k
    int value_is_indexed = 0, do_index = 0;
325
326
320k
Redo:
327
320k
    if (*src >= src_end)
328
65
        return H2O_HTTP2_ERROR_COMPRESSION;
329
330
    /* determine the mode and handle accordingly */
331
320k
    if (**src >= 128) {
332
        /* indexed header field representation */
333
205k
        if ((index = h2o_hpack_decode_int(src, src_end, 7)) <= 0)
334
75
            return H2O_HTTP2_ERROR_COMPRESSION;
335
204k
        value_is_indexed = 1;
336
204k
    } else if (**src >= 64) {
337
        /* literal header field with incremental handling */
338
26.9k
        if (**src == 64) {
339
6.23k
            ++*src;
340
20.7k
        } else if ((index = h2o_hpack_decode_int(src, src_end, 6)) <= 0) {
341
14
            return H2O_HTTP2_ERROR_COMPRESSION;
342
14
        }
343
26.9k
        do_index = 1;
344
88.2k
    } else if (**src < 32) {
345
        /* literal header field without indexing / never indexed */
346
58.8k
        if ((**src & 0xf) == 0) {
347
50.9k
            ++*src;
348
50.9k
        } else if ((index = h2o_hpack_decode_int(src, src_end, 4)) <= 0) {
349
12
            return H2O_HTTP2_ERROR_COMPRESSION;
350
12
        }
351
58.8k
    } else {
352
        /* size update */
353
29.3k
        int64_t new_capacity;
354
29.3k
        if ((new_capacity = h2o_hpack_decode_int(src, src_end, 5)) < 0) {
355
24
            return H2O_HTTP2_ERROR_COMPRESSION;
356
24
        }
357
29.3k
        if (new_capacity > hpack_header_table->hpack_max_capacity) {
358
204
            return H2O_HTTP2_ERROR_COMPRESSION;
359
204
        }
360
29.1k
        hpack_header_table->hpack_capacity = (size_t)new_capacity;
361
34.5k
        while (hpack_header_table->num_entries != 0 && hpack_header_table->hpack_size > hpack_header_table->hpack_capacity) {
362
5.38k
            header_table_evict_one(hpack_header_table);
363
5.38k
        }
364
29.1k
        goto Redo;
365
29.3k
    }
366
367
    /* determine the header */
368
290k
    unsigned soft_errors = 0;
369
290k
    if (index > 0) {
370
        /* existing name (and value?) */
371
233k
        if (index < HEADER_TABLE_OFFSET) {
372
80.3k
            name = (h2o_iovec_t *)h2o_hpack_static_table[index - 1].name;
373
80.3k
            if (value_is_indexed)
374
52.8k
                value = (h2o_iovec_t *)&h2o_hpack_static_table[index - 1].value;
375
153k
        } else if (index - HEADER_TABLE_OFFSET < hpack_header_table->num_entries) {
376
152k
            struct st_h2o_hpack_header_table_entry_t *entry =
377
152k
                h2o_hpack_header_table_get(hpack_header_table, index - HEADER_TABLE_OFFSET);
378
152k
            soft_errors = entry->soft_errors;
379
152k
            name = entry->name;
380
152k
            if (!h2o_iovec_is_token(name))
381
63.6k
                h2o_mem_link_shared(pool, name);
382
152k
            if (value_is_indexed) {
383
151k
                value = entry->value;
384
151k
                h2o_mem_link_shared(pool, value);
385
151k
            }
386
152k
        } else {
387
911
            return H2O_HTTP2_ERROR_COMPRESSION;
388
911
        }
389
233k
    } else {
390
        /* non-existing name */
391
57.1k
        const h2o_token_t *name_token;
392
57.1k
        if ((name = decode_string(pool, &soft_errors, src, src_end, 1, err_desc)) == NULL) {
393
356
            if (*err_desc == h2o_hpack_err_found_upper_case_in_header_name)
394
93
                return H2O_HTTP2_ERROR_PROTOCOL;
395
263
            return H2O_HTTP2_ERROR_COMPRESSION;
396
356
        }
397
        /* predefined header names should be interned */
398
56.7k
        if ((name_token = h2o_lookup_token(name->base, name->len)) != NULL)
399
5.97k
            name = (h2o_iovec_t *)&name_token->buf;
400
56.7k
    }
401
402
    /* determine the value (if necessary) */
403
289k
    if (!value_is_indexed) {
404
85.1k
        soft_errors &= ~H2O_HPACK_SOFT_ERROR_BIT_INVALID_VALUE;
405
85.1k
        if ((value = decode_string(pool, &soft_errors, src, src_end, 0, err_desc)) == NULL)
406
1.98k
            return H2O_HTTP2_ERROR_COMPRESSION;
407
85.1k
    }
408
409
    /* add the decoded header to the header table if necessary */
410
287k
    if (do_index) {
411
25.9k
        struct st_h2o_hpack_header_table_entry_t *entry =
412
25.9k
            header_table_add(hpack_header_table, name->len + value->len + HEADER_TABLE_ENTRY_SIZE_OFFSET, SIZE_MAX);
413
25.9k
        if (entry != NULL) {
414
17.8k
            entry->soft_errors = soft_errors;
415
17.8k
            entry->name = name;
416
17.8k
            if (!h2o_iovec_is_token(entry->name))
417
3.91k
                h2o_mem_addref_shared(entry->name);
418
17.8k
            entry->value = value;
419
17.8k
            if (!value_is_part_of_static_table(entry->value))
420
17.8k
                h2o_mem_addref_shared(entry->value);
421
17.8k
        }
422
25.9k
    }
423
424
287k
    *_name = name;
425
287k
    *_value = *value;
426
287k
    if (soft_errors != 0) {
427
149k
        *err_desc = (soft_errors & H2O_HPACK_SOFT_ERROR_BIT_INVALID_NAME) != 0
428
149k
                        ? h2o_hpack_soft_err_found_invalid_char_in_header_name
429
149k
                        : h2o_hpack_soft_err_found_invalid_char_in_header_value;
430
149k
        return H2O_HTTP2_ERROR_INVALID_HEADER_CHAR;
431
149k
    } else {
432
137k
        return 0;
433
137k
    }
434
287k
}
435
436
static uint8_t *encode_status(uint8_t *dst, int status)
437
7.58k
{
438
    /* see also: STATUS_HEADER_MAX_SIZE */
439
440
7.58k
    assert(100 <= status && status <= 999);
441
442
7.58k
    switch (status) {
443
0
#define COMMON_CODE(code, st)                                                                                                      \
444
7.13k
    case st:                                                                                                                       \
445
7.13k
        *dst++ = 0x80 | code;                                                                                                      \
446
7.13k
        break
447
645
        COMMON_CODE(8, 200);
448
0
        COMMON_CODE(9, 204);
449
0
        COMMON_CODE(10, 206);
450
0
        COMMON_CODE(11, 304);
451
2.62k
        COMMON_CODE(12, 400);
452
3.86k
        COMMON_CODE(13, 404);
453
0
        COMMON_CODE(14, 500);
454
0
#undef COMMON_CODE
455
450
    default:
456
        /* use literal header field without indexing - indexed name */
457
450
        *dst++ = 8;
458
450
        *dst++ = 3;
459
450
        sprintf((char *)dst, "%d", status);
460
450
        dst += 3;
461
450
        break;
462
7.58k
    }
463
464
7.58k
    return dst;
465
7.58k
}
466
467
static uint8_t *encode_content_length(uint8_t *dst, size_t value)
468
6.94k
{
469
6.94k
    char buf[32], *p = buf + sizeof(buf);
470
6.94k
    size_t l;
471
472
10.0k
    do {
473
10.0k
        *--p = '0' + value % 10;
474
10.0k
    } while ((value /= 10) != 0);
475
6.94k
    l = buf + sizeof(buf) - p;
476
6.94k
    *dst++ = 0x0f;
477
6.94k
    *dst++ = 0x0d;
478
6.94k
    *dst++ = (uint8_t)l;
479
6.94k
    memcpy(dst, p, l);
480
6.94k
    dst += l;
481
482
6.94k
    return dst;
483
6.94k
}
484
485
void h2o_hpack_dispose_header_table(h2o_hpack_header_table_t *header_table)
486
22.9k
{
487
22.9k
    if (header_table->num_entries != 0) {
488
5.42k
        size_t index = header_table->entry_start_index;
489
15.2k
        do {
490
15.2k
            struct st_h2o_hpack_header_table_entry_t *entry = header_table->entries + index;
491
15.2k
            if (!h2o_iovec_is_token(entry->name))
492
2.19k
                h2o_mem_release_shared(entry->name);
493
15.2k
            if (!value_is_part_of_static_table(entry->value))
494
15.2k
                h2o_mem_release_shared(entry->value);
495
15.2k
            index = (index + 1) % header_table->entry_capacity;
496
15.2k
        } while (--header_table->num_entries != 0);
497
5.42k
    }
498
22.9k
    free(header_table->entries);
499
22.9k
}
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
22.0k
{
507
22.0k
    const uint8_t *src_end = src + len;
508
509
22.0k
    *content_length = SIZE_MAX;
510
511
978k
    while (src != src_end) {
512
964k
        h2o_iovec_t *name, value;
513
964k
        const char *decode_err = NULL;
514
964k
        int ret = decode_cb(pool, decode_ctx, &name, &value, &src, src_end, &decode_err);
515
964k
        if (ret != 0) {
516
197k
            if (ret == H2O_HTTP2_ERROR_INVALID_HEADER_CHAR) {
517
                /* this is a soft error, we continue parsing, but register only the first error */
518
190k
                if (*err_desc == NULL) {
519
6.18k
                    *err_desc = decode_err;
520
6.18k
                }
521
190k
            } else {
522
6.95k
                *err_desc = decode_err;
523
6.95k
                return ret;
524
6.95k
            }
525
197k
        }
526
957k
        if (name->base[0] == ':') {
527
39.5k
            if (pseudo_header_exists_map != NULL) {
528
                /* FIXME validate the chars in the value (e.g. reject SP in path) */
529
39.2k
                if (name == &H2O_TOKEN_AUTHORITY->buf) {
530
7.45k
                    if (authority->base != NULL) {
531
8
                        *err_desc = h2o_hpack_err_invalid_pseudo_header;
532
8
                        return H2O_HTTP2_ERROR_PROTOCOL;
533
8
                    }
534
7.44k
                    *authority = value;
535
7.44k
                    *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_AUTHORITY_EXISTS;
536
31.7k
                } else if (name == &H2O_TOKEN_METHOD->buf) {
537
11.2k
                    if (method->base != NULL) {
538
6
                        *err_desc = h2o_hpack_err_invalid_pseudo_header;
539
6
                        return H2O_HTTP2_ERROR_PROTOCOL;
540
6
                    }
541
11.2k
                    *method = value;
542
11.2k
                    *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_METHOD_EXISTS;
543
20.5k
                } else if (name == &H2O_TOKEN_PROTOCOL->buf) {
544
11
                    if (protocol->base != NULL)
545
2
                        return H2O_HTTP2_ERROR_PROTOCOL;
546
9
                    *protocol = value;
547
9
                    *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_PROTOCOL_EXISTS;
548
20.5k
                } else if (name == &H2O_TOKEN_PATH->buf) {
549
10.1k
                    if (path->base != NULL) {
550
6
                        *err_desc = h2o_hpack_err_invalid_pseudo_header;
551
6
                        return H2O_HTTP2_ERROR_PROTOCOL;
552
6
                    }
553
10.1k
                    if (value.len == 0) {
554
3
                        *err_desc = h2o_hpack_err_invalid_pseudo_header;
555
3
                        return H2O_HTTP2_ERROR_PROTOCOL;
556
3
                    }
557
10.1k
                    *path = value;
558
10.1k
                    *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_PATH_EXISTS;
559
10.3k
                } else if (name == &H2O_TOKEN_SCHEME->buf) {
560
10.3k
                    if (*scheme != NULL) {
561
7
                        *err_desc = h2o_hpack_err_invalid_pseudo_header;
562
7
                        return H2O_HTTP2_ERROR_PROTOCOL;
563
7
                    }
564
10.3k
                    if (h2o_memis(value.base, value.len, H2O_STRLIT("https"))) {
565
1.70k
                        *scheme = &H2O_URL_SCHEME_HTTPS;
566
8.65k
                    } else if (h2o_memis(value.base, value.len, H2O_STRLIT("masque"))) {
567
3
                        *scheme = &H2O_URL_SCHEME_MASQUE;
568
8.64k
                    } else {
569
                        /* draft-16 8.1.2.3 suggests quote: ":scheme is not restricted to http and https schemed URIs" */
570
8.64k
                        *scheme = &H2O_URL_SCHEME_HTTP;
571
8.64k
                    }
572
10.3k
                    *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_SCHEME_EXISTS;
573
10.3k
                } else {
574
29
                    return H2O_HTTP2_ERROR_PROTOCOL;
575
29
                }
576
39.2k
            } else {
577
310
                *err_desc = h2o_hpack_err_invalid_pseudo_header;
578
310
                return H2O_HTTP2_ERROR_PROTOCOL;
579
310
            }
580
917k
        } else {
581
917k
            pseudo_header_exists_map = NULL;
582
917k
            if (h2o_iovec_is_token(name)) {
583
758k
                h2o_token_t *token = H2O_STRUCT_FROM_MEMBER(h2o_token_t, buf, name);
584
758k
                if (token->flags.is_hpack_special) {
585
66.6k
                    if (token == H2O_TOKEN_CONTENT_LENGTH) {
586
6.84k
                        if ((*content_length = h2o_strtosize(value.base, value.len)) == SIZE_MAX) {
587
101
                            *err_desc = h2o_hpack_err_invalid_content_length_header;
588
101
                            return H2O_HTTP2_ERROR_PROTOCOL;
589
101
                        }
590
6.74k
                        goto Next;
591
59.7k
                    } else if (token == H2O_TOKEN_EXPECT) {
592
6.27k
                        *expect = value;
593
6.27k
                        goto Next;
594
53.4k
                    } else if (token == H2O_TOKEN_HOST && authority != NULL) {
595
                        /* HTTP2 allows the use of host header (in place of :authority) */
596
2.28k
                        if (authority->base == NULL)
597
372
                            *authority = value;
598
2.28k
                        goto Next;
599
51.2k
                    } else if (token == H2O_TOKEN_TE && h2o_lcstris(value.base, value.len, H2O_STRLIT("trailers"))) {
600
                        /* do not reject */
601
50.3k
                    } 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
49.8k
                        h2o_cache_digests_load_header(digests, value.base, value.len);
604
49.8k
                    } else if (token == H2O_TOKEN_DATAGRAM_FLOW_ID) {
605
439
                        if (datagram_flow_id != NULL)
606
249
                            *datagram_flow_id = value;
607
439
                        goto Next;
608
439
                    } else {
609
                        /* rest of the header fields that are marked as special are rejected */
610
70
                        *err_desc = h2o_hpack_err_unexpected_connection_specific_header;
611
70
                        return H2O_HTTP2_ERROR_PROTOCOL;
612
70
                    }
613
66.6k
                }
614
742k
                h2o_add_header(pool, headers, token, NULL, value.base, value.len);
615
742k
            } else {
616
159k
                h2o_add_header_by_str(pool, headers, name->base, name->len, 0, NULL, value.base, value.len);
617
159k
            }
618
917k
        }
619
956k
    Next:;
620
956k
    }
621
622
14.5k
    if (*err_desc != NULL)
623
3.27k
        return H2O_HTTP2_ERROR_INVALID_HEADER_CHAR;
624
11.2k
    return 0;
625
14.5k
}
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
35.4k
{
725
35.4k
    return value < (1 << prefix_bits) - 1;
726
35.4k
}
727
728
uint8_t *h2o_hpack_encode_int(uint8_t *dst, int64_t value, unsigned prefix_bits)
729
29.0k
{
730
29.0k
    if (encode_int_is_onebyte(value, prefix_bits)) {
731
25.6k
        *dst++ |= value;
732
25.6k
    } else {
733
        /* see also: MAX_ENCODE_INT_LENGTH */
734
3.40k
        assert(value >= 0);
735
3.40k
        value -= (1 << prefix_bits) - 1;
736
3.40k
        *dst++ |= (1 << prefix_bits) - 1;
737
3.41k
        for (; value >= 128; value >>= 7) {
738
16
            *dst++ = 0x80 | value;
739
16
        }
740
3.40k
        *dst++ = value;
741
3.40k
    }
742
29.0k
    return dst;
743
29.0k
}
744
745
size_t h2o_hpack_encode_huffman(uint8_t *_dst, const uint8_t *src, size_t len)
746
10.9k
{
747
10.9k
    uint8_t *dst = _dst, *dst_end = dst + len;
748
10.9k
    const uint8_t *src_end = src + len;
749
10.9k
    uint64_t bits = 0;
750
10.9k
    int bits_left = 40;
751
752
247k
    while (src != src_end) {
753
236k
        const nghttp2_huff_sym *sym = huff_sym_table + *src++;
754
236k
        bits |= (uint64_t)sym->code << (bits_left - sym->nbits);
755
236k
        bits_left -= sym->nbits;
756
404k
        while (bits_left <= 32) {
757
168k
            *dst++ = bits >> 32;
758
168k
            bits <<= 8;
759
168k
            bits_left += 8;
760
168k
            if (dst == dst_end) {
761
0
                return SIZE_MAX;
762
0
            }
763
168k
        }
764
236k
    }
765
766
10.9k
    if (bits_left != 40) {
767
10.2k
        bits |= ((uint64_t)1 << bits_left) - 1;
768
10.2k
        *dst++ = bits >> 32;
769
10.2k
    }
770
10.9k
    if (dst == dst_end) {
771
1.29k
        return SIZE_MAX;
772
1.29k
    }
773
774
9.62k
    return dst - _dst;
775
10.9k
}
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
6.38k
{
789
6.38k
    if (H2O_LIKELY(len != 0)) {
790
        /* try to encode using huffman */
791
6.38k
        size_t hufflen = h2o_hpack_encode_huffman(dst + 1, (const uint8_t *)s, len);
792
6.38k
        if (H2O_LIKELY(hufflen != SIZE_MAX)) {
793
6.38k
            size_t head_len;
794
6.38k
            if (H2O_LIKELY(encode_int_is_onebyte((uint32_t)hufflen, 7))) {
795
6.38k
                dst[0] = (uint8_t)(0x80 | hufflen);
796
6.38k
                head_len = 1;
797
6.38k
            } 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
6.38k
            return head_len + hufflen;
805
6.38k
        }
806
6.38k
    }
807
0
    return encode_as_is(dst, s, len);
808
6.38k
}
809
810
static uint8_t *header_table_adjust_size(h2o_hpack_header_table_t *table, uint32_t new_capacity, uint8_t *dst)
811
7.58k
{
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
7.58k
    if (new_capacity >= table->hpack_capacity)
815
7.48k
        return dst;
816
817
    /* update state */
818
102
    table->hpack_capacity = new_capacity;
819
132
    while (table->num_entries != 0 && table->hpack_size > table->hpack_capacity)
820
30
        header_table_evict_one(table);
821
822
    /* encode Dynamic Table Size Update */
823
102
    *dst = 0x20;
824
102
    dst = h2o_hpack_encode_int(dst, table->hpack_capacity, 5);
825
826
102
    return dst;
827
7.58k
}
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
15.1k
{
832
15.1k
    int is_token = h2o_iovec_is_token(name);
833
15.1k
    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
15.1k
    {
837
15.1k
        size_t header_table_index = header_table->entry_start_index, n;
838
22.9k
        for (n = header_table->num_entries; n != 0; --n) {
839
16.5k
            struct st_h2o_hpack_header_table_entry_t *entry = header_table->entries + header_table_index;
840
16.5k
            if (is_token) {
841
16.5k
                if (name != entry->name)
842
7.72k
                    goto Next;
843
16.5k
            } 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
8.80k
            if (!h2o_memis(value->base, value->len, entry->value->base, entry->value->len))
851
21
                goto Next;
852
            /* name and value matched! */
853
8.78k
            *dst = 0x80;
854
8.78k
            dst = h2o_hpack_encode_int(dst, header_table->num_entries - n + HEADER_TABLE_OFFSET, 7);
855
8.78k
            return dst;
856
7.74k
        Next:
857
7.74k
            ++header_table_index;
858
7.74k
            if (header_table_index == header_table->entry_capacity)
859
2.41k
                header_table_index = 0;
860
7.74k
        }
861
15.1k
    }
862
863
6.38k
    if (!dont_compress && is_token)
864
6.38k
        dont_compress = ((const h2o_token_t *)name)->flags.dont_compress;
865
6.38k
    if (dont_compress)
866
0
        dont_compress = value->len < 20;
867
868
6.38k
    if (name_index != 0) {
869
        /* literal header field with indexing (indexed name). */
870
6.38k
        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
6.38k
        } else {
875
6.38k
            *dst = 0x40;
876
6.38k
            dst = h2o_hpack_encode_int(dst, name_index, 6);
877
6.38k
        }
878
6.38k
    } 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
6.38k
    if (dont_compress == 1) {
884
        /* bypass huffman encoding */
885
0
        dst += encode_as_is(dst, value->base, value->len);
886
6.38k
    } 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
6.38k
        dst += h2o_hpack_encode_string(dst, value->base, value->len);
891
6.38k
        struct st_h2o_hpack_header_table_entry_t *entry =
892
6.38k
            header_table_add(header_table, name->len + value->len + HEADER_TABLE_ENTRY_SIZE_OFFSET, 32);
893
6.38k
        if (entry != NULL) {
894
5.42k
            if (is_token) {
895
5.42k
                entry->name = (h2o_iovec_t *)name;
896
5.42k
            } 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
5.42k
            entry->value = alloc_buf(NULL, value->len);
902
5.42k
            entry->value->base[value->len] = '\0';
903
5.42k
            memcpy(entry->value->base, value->base, value->len);
904
5.42k
        }
905
6.38k
    }
906
907
6.38k
    return dst;
908
15.1k
}
909
910
static uint8_t *encode_header(h2o_hpack_header_table_t *header_table, uint8_t *dst, const h2o_header_t *header)
911
7.58k
{
912
7.58k
    return do_encode_header(header_table, dst, header->name, &header->value, header->flags.dont_compress);
913
7.58k
}
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
7.58k
{
918
7.58k
    return do_encode_header(header_table, dst, &token->buf, value, token->flags.dont_compress);
919
7.58k
}
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
7.58k
{
971
7.58k
    return name_len + value_len + 1 + H2O_HPACK_ENCODE_INT_MAX_LENGTH * 2;
972
7.58k
}
973
974
static size_t calc_headers_capacity(const h2o_header_t *headers, size_t num_headers)
975
7.58k
{
976
7.58k
    const h2o_header_t *header;
977
7.58k
    size_t capacity = 0;
978
15.1k
    for (header = headers; num_headers != 0; ++header, --num_headers)
979
7.58k
        capacity += calc_capacity(header->name->len, header->value.len);
980
7.58k
    return capacity;
981
7.58k
}
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
7.58k
{
986
    /* try to fit all data into single frame, using the preallocated space for the frame header */
987
7.58k
    size_t payload_size = (*buf)->size - start_at - H2O_HTTP2_FRAME_HEADER_SIZE;
988
7.58k
    if (payload_size <= max_frame_size) {
989
7.58k
        h2o_http2_encode_frame_header((uint8_t *)((*buf)->bytes + start_at), payload_size, type,
990
7.58k
                                      H2O_HTTP2_FRAME_FLAG_END_HEADERS | flags, stream_id);
991
7.58k
        return;
992
7.58k
    }
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
7.58k
{
1112
7.58k
    size_t capacity = calc_headers_capacity(headers, num_headers);
1113
7.58k
    capacity += H2O_HTTP2_FRAME_HEADER_SIZE; /* for the first header */
1114
7.58k
    capacity += DYNAMIC_TABLE_SIZE_UPDATE_MAX_SIZE;
1115
7.58k
    capacity += STATUS_HEADER_MAX_SIZE; /* for :status: */
1116
7.58k
#ifndef H2O_UNITTEST
1117
7.58k
    if (server_name != NULL && server_name->len) {
1118
7.58k
        capacity += 5 + server_name->len; /* for Server: */
1119
7.58k
    }
1120
7.58k
#endif
1121
7.58k
    if (content_length != SIZE_MAX)
1122
6.94k
        capacity += CONTENT_LENGTH_HEADER_MAX_SIZE; /* for content-length: UINT64_MAX (with huffman compression applied) */
1123
1124
7.58k
    size_t start_at = (*buf)->size;
1125
7.58k
    uint8_t *dst = (void *)(h2o_buffer_reserve(buf, capacity).base + H2O_HTTP2_FRAME_HEADER_SIZE); /* skip frame header */
1126
1127
    /* encode */
1128
7.58k
    dst = header_table_adjust_size(header_table, hpack_capacity, dst);
1129
7.58k
    dst = encode_status(dst, status);
1130
7.58k
#ifndef H2O_UNITTEST
1131
    /* TODO keep some kind of reference to the indexed Server header, and reuse it */
1132
7.58k
    if (server_name != NULL && server_name->len) {
1133
7.58k
        dst = encode_header_token(header_table, dst, H2O_TOKEN_SERVER, server_name);
1134
7.58k
    }
1135
7.58k
#endif
1136
15.1k
    for (size_t i = 0; i != num_headers; ++i)
1137
7.58k
        dst = encode_header(header_table, dst, headers + i);
1138
7.58k
    if (content_length != SIZE_MAX)
1139
6.94k
        dst = encode_content_length(dst, content_length);
1140
7.58k
    (*buf)->size = (char *)dst - (*buf)->bytes;
1141
7.58k
    size_t headers_size = (*buf)->size - start_at - H2O_HTTP2_FRAME_HEADER_SIZE;
1142
1143
    /* setup the frame headers */
1144
7.58k
    fixup_frame_headers(buf, start_at, H2O_HTTP2_FRAME_TYPE_HEADERS, stream_id, max_frame_size,
1145
7.58k
                        is_end_stream ? H2O_HTTP2_FRAME_FLAG_END_STREAM : 0);
1146
1147
7.58k
    return headers_size;
1148
7.58k
}
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
}