Coverage Report

Created: 2025-07-11 06:26

/src/h2o/lib/handler/headers_util.c
Line
Count
Source (jump to first uncovered line)
1
#include "h2o.h"
2
#include "h2o/configurator.h"
3
4
static h2o_header_t *find_header(h2o_headers_t *headers, h2o_iovec_t *name)
5
0
{
6
0
    ssize_t index;
7
8
0
    if (h2o_iovec_is_token(name)) {
9
0
        index = h2o_find_header(headers, (void *)name, -1);
10
0
    } else {
11
0
        index = h2o_find_header_by_str(headers, name->base, name->len, -1);
12
0
    }
13
0
    if (index == -1)
14
0
        return NULL;
15
0
    return headers->entries + index;
16
0
}
17
18
static int is_in_list(const char *base, size_t len, h2o_headers_command_t *cmd)
19
0
{
20
0
    size_t i;
21
0
    h2o_iovec_t name = h2o_iovec_init(base, len);
22
0
    for (i = 0; i != cmd->num_args; ++i) {
23
0
        if (h2o_iovec_is_token(cmd->args[i].name)) {
24
0
            if (cmd->args[i].name->base == name.base) {
25
0
                return 1;
26
0
            }
27
0
        } else {
28
0
            if (h2o_memis(cmd->args[i].name->base, cmd->args[i].name->len, name.base, name.len))
29
0
                return 1;
30
0
        }
31
0
    }
32
0
    return 0;
33
0
}
34
35
static void filter_cookie(h2o_mem_pool_t *pool, char **base, size_t *len, h2o_headers_command_t *cmd)
36
0
{
37
0
    h2o_iovec_t iter = h2o_iovec_init(*base, *len), token_value;
38
0
    const char *token;
39
0
    size_t token_len;
40
0
    char dst[*len * 2];
41
0
    size_t dst_len = 0;
42
43
0
    do {
44
0
        if ((token = h2o_next_token(&iter, ';', ';', &token_len, &token_value)) == NULL)
45
0
            break;
46
0
        int found = is_in_list(token, token_len, cmd);
47
0
        if ((cmd->cmd == H2O_HEADERS_CMD_COOKIE_UNSETUNLESS && found) || (cmd->cmd == H2O_HEADERS_CMD_COOKIE_UNSET && !found)) {
48
0
            if (dst_len != 0) {
49
0
                memcpy(dst + dst_len, H2O_STRLIT("; "));
50
0
                dst_len += 2;
51
0
            }
52
0
            memcpy(dst + dst_len, token, token_len);
53
0
            dst_len += token_len;
54
0
            if (token_value.len > 0) {
55
0
                memcpy(dst + dst_len, H2O_STRLIT("="));
56
0
                dst_len++;
57
0
                memcpy(dst + dst_len, token_value.base, token_value.len);
58
0
                dst_len += token_value.len;
59
0
            }
60
0
        }
61
0
    } while (1);
62
63
0
    if (dst_len > *len)
64
0
        *base = h2o_mem_alloc_pool(pool, *dst, dst_len);
65
66
0
    memcpy(*base, dst, dst_len);
67
0
    *len = dst_len;
68
0
}
69
70
static void cookie_cmd(h2o_mem_pool_t *pool, h2o_headers_t *headers, h2o_headers_command_t *cmd)
71
0
{
72
0
    ssize_t header_index;
73
0
    for (header_index = -1; (header_index = h2o_find_header(headers, H2O_TOKEN_COOKIE, header_index)) != -1;) {
74
0
        h2o_header_t *header = headers->entries + header_index;
75
0
        filter_cookie(pool, &header->value.base, &header->value.len, cmd);
76
0
        if (header->value.len == 0)
77
0
            h2o_delete_header(headers, header_index);
78
0
    }
79
0
}
80
81
static void remove_header_unless(h2o_headers_t *headers, h2o_headers_command_t *cmd)
82
0
{
83
0
    size_t src, dst = 0;
84
85
0
    for (src = 0; src != headers->size; ++src) {
86
0
        if (!is_in_list(headers->entries[src].name->base, headers->entries[src].name->len, cmd))
87
0
            continue;
88
        /* not matched */
89
0
        if (dst != src)
90
0
            headers->entries[dst] = headers->entries[src];
91
0
        ++dst;
92
0
    }
93
0
    headers->size = dst;
94
0
}
95
96
static void remove_header(h2o_headers_t *headers, h2o_headers_command_t *cmd)
97
0
{
98
0
    size_t src, dst = 0;
99
100
0
    for (src = 0; src != headers->size; ++src) {
101
0
        if (h2o_iovec_is_token(cmd->args[0].name)) {
102
0
            if (headers->entries[src].name == cmd->args[0].name)
103
0
                continue;
104
0
        } else {
105
0
            if (h2o_memis(headers->entries[src].name->base, headers->entries[src].name->len, cmd->args[0].name->base,
106
0
                          cmd->args[0].name->len))
107
0
                continue;
108
0
        }
109
        /* not matched */
110
0
        if (dst != src)
111
0
            headers->entries[dst] = headers->entries[src];
112
0
        ++dst;
113
0
    }
114
0
    headers->size = dst;
115
0
}
116
117
static void dispose_h2o_headers_command(void *_cmds)
118
0
{
119
0
    h2o_headers_command_t *cmds = _cmds;
120
0
    size_t i;
121
0
    for (i = 0; cmds[i].cmd != H2O_HEADERS_CMD_NULL; ++i)
122
0
        free(cmds[i].args);
123
0
}
124
125
void h2o_headers_append_command(h2o_headers_command_t **cmds, int cmd, h2o_headers_command_arg_t *args, size_t num_args,
126
                                h2o_headers_command_when_t when)
127
0
{
128
0
    h2o_headers_command_t *new_cmds;
129
0
    size_t i, cnt;
130
131
0
    if (*cmds != NULL) {
132
0
        for (cnt = 0; (*cmds)[cnt].cmd != H2O_HEADERS_CMD_NULL; ++cnt)
133
0
            ;
134
0
    } else {
135
0
        cnt = 0;
136
0
    }
137
138
0
    new_cmds = h2o_mem_alloc_shared(NULL, (cnt + 2) * sizeof(*new_cmds), dispose_h2o_headers_command);
139
0
    if (*cmds != NULL)
140
0
        memcpy(new_cmds, *cmds, cnt * sizeof(*new_cmds));
141
0
    new_cmds[cnt] = (h2o_headers_command_t){};
142
0
    new_cmds[cnt].cmd = cmd;
143
0
    new_cmds[cnt].when = when;
144
0
    new_cmds[cnt].args = h2o_mem_alloc(sizeof(*new_cmds->args) * num_args);
145
0
    for (i = 0; i < num_args; i++)
146
0
        new_cmds[cnt].args[i] = args[i];
147
0
    new_cmds[cnt].num_args = num_args;
148
0
    new_cmds[cnt + 1] = (h2o_headers_command_t){H2O_HEADERS_CMD_NULL};
149
150
0
    if (*cmds != NULL) {
151
0
        (*cmds)[0] = (h2o_headers_command_t){H2O_HEADERS_CMD_NULL};
152
0
        h2o_mem_release_shared(*cmds);
153
0
    }
154
0
    *cmds = new_cmds;
155
0
}
156
157
void h2o_rewrite_headers(h2o_mem_pool_t *pool, h2o_headers_t *headers, h2o_headers_command_t *cmd)
158
0
{
159
0
    h2o_header_t *target;
160
161
0
    switch (cmd->cmd) {
162
0
    case H2O_HEADERS_CMD_ADD:
163
0
        goto AddHeader;
164
0
    case H2O_HEADERS_CMD_APPEND:
165
0
        assert(cmd->num_args == 1);
166
0
        if ((target = find_header(headers, cmd->args[0].name)) == NULL)
167
0
            goto AddHeader;
168
0
        goto AppendToken;
169
0
    case H2O_HEADERS_CMD_MERGE:
170
0
        assert(cmd->num_args == 1);
171
0
        if ((target = find_header(headers, cmd->args[0].name)) == NULL)
172
0
            goto AddHeader;
173
0
        if (h2o_contains_token(target->value.base, target->value.len, cmd->args[0].value.base, cmd->args[0].value.len, ','))
174
0
            return;
175
0
        goto AppendToken;
176
0
    case H2O_HEADERS_CMD_SET:
177
0
        remove_header(headers, cmd);
178
0
        goto AddHeader;
179
0
    case H2O_HEADERS_CMD_SETIFEMPTY:
180
0
        assert(cmd->num_args == 1);
181
0
        if (find_header(headers, cmd->args[0].name) != NULL)
182
0
            return;
183
0
        goto AddHeader;
184
0
    case H2O_HEADERS_CMD_UNSET:
185
0
        remove_header(headers, cmd);
186
0
        return;
187
0
    case H2O_HEADERS_CMD_UNSETUNLESS:
188
0
        remove_header_unless(headers, cmd);
189
0
        return;
190
0
    case H2O_HEADERS_CMD_COOKIE_UNSET:
191
0
    case H2O_HEADERS_CMD_COOKIE_UNSETUNLESS:
192
0
        cookie_cmd(pool, headers, cmd);
193
0
        return;
194
0
    }
195
196
0
    assert(!"FIXME");
197
0
    return;
198
199
0
AddHeader:
200
0
    assert(cmd->num_args == 1);
201
0
    if (h2o_iovec_is_token(cmd->args[0].name)) {
202
0
        h2o_add_header(pool, headers, (void *)cmd->args[0].name, NULL, cmd->args[0].value.base, cmd->args[0].value.len);
203
0
    } else {
204
0
        h2o_add_header_by_str(pool, headers, cmd->args[0].name->base, cmd->args[0].name->len, 0, NULL, cmd->args[0].value.base,
205
0
                              cmd->args[0].value.len);
206
0
    }
207
0
    return;
208
209
0
AppendToken:
210
0
    assert(cmd->num_args == 1);
211
0
    if (target->value.len != 0) {
212
0
        h2o_iovec_t v;
213
0
        v.len = target->value.len + 2 + cmd->args[0].value.len;
214
0
        v.base = h2o_mem_alloc_pool(pool, char, v.len);
215
0
        memcpy(v.base, target->value.base, target->value.len);
216
0
        v.base[target->value.len] = ',';
217
0
        v.base[target->value.len + 1] = ' ';
218
0
        memcpy(v.base + target->value.len + 2, cmd->args[0].value.base, cmd->args[0].value.len);
219
0
        target->value = v;
220
0
    } else {
221
0
        target->value = cmd->args[0].value;
222
0
    }
223
0
    return;
224
0
}