Coverage Report

Created: 2026-04-28 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/h2o/lib/core/headers.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2014 DeNA Co., Ltd.
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 <stdio.h>
24
#include "h2o.h"
25
26
static ssize_t add_header(h2o_mem_pool_t *pool, h2o_headers_t *headers, h2o_iovec_t *name, const char *orig_name, const char *value,
27
                          size_t value_len, h2o_header_flags_t flags)
28
1.55M
{
29
1.55M
    h2o_header_t *slot;
30
31
1.55M
    h2o_vector_reserve(pool, headers, headers->size + 1);
32
1.55M
    slot = headers->entries + headers->size++;
33
34
1.55M
    slot->name = name;
35
1.55M
    slot->value.base = (char *)value;
36
1.55M
    slot->value.len = value_len;
37
1.55M
    slot->orig_name = orig_name ? h2o_strdup(pool, orig_name, name->len).base : NULL;
38
1.55M
    slot->flags = flags;
39
1.55M
    return headers->size - 1;
40
1.55M
}
41
42
static inline h2o_iovec_t *alloc_and_init_iovec(h2o_mem_pool_t *pool, const char *base, size_t len)
43
228k
{
44
228k
    h2o_iovec_t *iov = h2o_mem_alloc_pool(pool, *iov, 1);
45
228k
    iov->base = (char *)base;
46
228k
    iov->len = len;
47
228k
    return iov;
48
228k
}
49
50
ssize_t h2o_find_header(const h2o_headers_t *headers, const h2o_token_t *token, ssize_t cursor)
51
14.3k
{
52
563k
    for (++cursor; cursor < headers->size; ++cursor) {
53
550k
        if (headers->entries[cursor].name == &token->buf) {
54
1.13k
            return cursor;
55
1.13k
        }
56
550k
    }
57
13.2k
    return -1;
58
14.3k
}
59
60
ssize_t h2o_find_header_by_str(const h2o_headers_t *headers, const char *name, size_t name_len, ssize_t cursor)
61
0
{
62
0
    for (++cursor; cursor < headers->size; ++cursor) {
63
0
        h2o_header_t *t = headers->entries + cursor;
64
0
        if (h2o_memis(t->name->base, t->name->len, name, name_len)) {
65
0
            return cursor;
66
0
        }
67
0
    }
68
0
    return -1;
69
0
}
70
71
ssize_t h2o_add_header(h2o_mem_pool_t *pool, h2o_headers_t *headers, const h2o_token_t *token, const char *orig_name,
72
                       const char *value, size_t value_len)
73
1.32M
{
74
1.32M
    return add_header(pool, headers, (h2o_iovec_t *)&token->buf, orig_name, value, value_len, (h2o_header_flags_t){0});
75
1.32M
}
76
77
ssize_t h2o_add_header_by_str(h2o_mem_pool_t *pool, h2o_headers_t *headers, const char *lowercase_name, size_t lowercase_name_len,
78
                              int maybe_token, const char *orig_name, const char *value, size_t value_len)
79
228k
{
80
228k
    if (maybe_token) {
81
0
        const h2o_token_t *token = h2o_lookup_token(lowercase_name, lowercase_name_len);
82
0
        if (token != NULL) {
83
0
            return add_header(pool, headers, (h2o_iovec_t *)token, orig_name, value, value_len, (h2o_header_flags_t){0});
84
0
        }
85
0
    }
86
228k
    return add_header(pool, headers, alloc_and_init_iovec(pool, lowercase_name, lowercase_name_len), orig_name, value, value_len,
87
228k
                      (h2o_header_flags_t){0});
88
228k
}
89
90
ssize_t h2o_set_header(h2o_mem_pool_t *pool, h2o_headers_t *headers, const h2o_token_t *token, const char *value, size_t value_len,
91
                       int overwrite_if_exists)
92
0
{
93
0
    ssize_t cursor = h2o_find_header(headers, token, -1);
94
0
    if (cursor != -1) {
95
0
        if (overwrite_if_exists) {
96
0
            headers->entries[cursor].value = h2o_iovec_init(value, value_len);
97
0
        }
98
0
        return cursor;
99
0
    } else {
100
0
        return h2o_add_header(pool, headers, token, NULL, value, value_len);
101
0
    }
102
0
}
103
104
ssize_t h2o_set_header_by_str(h2o_mem_pool_t *pool, h2o_headers_t *headers, const char *lowercase_name, size_t lowercase_name_len,
105
                              int maybe_token, const char *value, size_t value_len, int overwrite_if_exists)
106
0
{
107
0
    ssize_t cursor;
108
109
0
    if (maybe_token) {
110
0
        const h2o_token_t *token = h2o_lookup_token(lowercase_name, lowercase_name_len);
111
0
        if (token != NULL) {
112
0
            return h2o_set_header(pool, headers, token, value, value_len, overwrite_if_exists);
113
0
        }
114
0
    }
115
116
0
    cursor = h2o_find_header_by_str(headers, lowercase_name, lowercase_name_len, -1);
117
0
    if (cursor != -1) {
118
0
        if (overwrite_if_exists) {
119
0
            headers->entries[cursor].value = h2o_iovec_init(value, value_len);
120
0
        }
121
0
        return cursor;
122
0
    } else {
123
0
        return add_header(pool, headers, alloc_and_init_iovec(pool, lowercase_name, lowercase_name_len), NULL, value, value_len,
124
0
                          (h2o_header_flags_t){0});
125
0
    }
126
0
}
127
128
ssize_t h2o_set_header_token(h2o_mem_pool_t *pool, h2o_headers_t *headers, const h2o_token_t *token, const char *value,
129
                             size_t value_len)
130
0
{
131
0
    ssize_t found = -1;
132
0
    size_t i;
133
0
    for (i = 0; i != headers->size; ++i) {
134
0
        if (headers->entries[i].name == &token->buf) {
135
0
            if (h2o_contains_token(headers->entries[i].value.base, headers->entries[i].value.len, value, value_len, ','))
136
0
                return -1;
137
0
            found = i;
138
0
        }
139
0
    }
140
0
    if (found != -1) {
141
0
        h2o_header_t *dest = headers->entries + found;
142
0
        dest->value = h2o_concat(pool, dest->value, h2o_iovec_init(H2O_STRLIT(", ")), h2o_iovec_init(value, value_len));
143
0
        return found;
144
0
    } else {
145
0
        return h2o_add_header(pool, headers, token, NULL, value, value_len);
146
0
    }
147
0
}
148
149
ssize_t h2o_delete_header(h2o_headers_t *headers, ssize_t cursor)
150
0
{
151
0
    assert(cursor != -1);
152
153
0
    --headers->size;
154
0
    memmove(headers->entries + cursor, headers->entries + cursor + 1, sizeof(h2o_header_t) * (headers->size - cursor));
155
156
0
    return cursor;
157
0
}