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 
add_header(h2o_mem_pool_t * pool,h2o_headers_t * headers,h2o_iovec_t * name,const char * orig_name,const char * value,size_t value_len,h2o_header_flags_t flags)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 {
29     h2o_header_t *slot;
30 
31     h2o_vector_reserve(pool, headers, headers->size + 1);
32     slot = headers->entries + headers->size++;
33 
34     slot->name = name;
35     slot->value.base = (char *)value;
36     slot->value.len = value_len;
37     slot->orig_name = orig_name ? h2o_strdup(pool, orig_name, name->len).base : NULL;
38     slot->flags = flags;
39     return headers->size - 1;
40 }
41 
alloc_and_init_iovec(h2o_mem_pool_t * pool,const char * base,size_t len)42 static inline h2o_iovec_t *alloc_and_init_iovec(h2o_mem_pool_t *pool, const char *base, size_t len)
43 {
44     h2o_iovec_t *iov = h2o_mem_alloc_pool(pool, *iov, 1);
45     iov->base = (char *)base;
46     iov->len = len;
47     return iov;
48 }
49 
h2o_find_header(const h2o_headers_t * headers,const h2o_token_t * token,ssize_t cursor)50 ssize_t h2o_find_header(const h2o_headers_t *headers, const h2o_token_t *token, ssize_t cursor)
51 {
52     for (++cursor; cursor < headers->size; ++cursor) {
53         if (headers->entries[cursor].name == &token->buf) {
54             return cursor;
55         }
56     }
57     return -1;
58 }
59 
h2o_find_header_by_str(const h2o_headers_t * headers,const char * name,size_t name_len,ssize_t cursor)60 ssize_t h2o_find_header_by_str(const h2o_headers_t *headers, const char *name, size_t name_len, ssize_t cursor)
61 {
62     for (++cursor; cursor < headers->size; ++cursor) {
63         h2o_header_t *t = headers->entries + cursor;
64         if (h2o_memis(t->name->base, t->name->len, name, name_len)) {
65             return cursor;
66         }
67     }
68     return -1;
69 }
70 
h2o_add_header(h2o_mem_pool_t * pool,h2o_headers_t * headers,const h2o_token_t * token,const char * orig_name,const char * value,size_t value_len)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 {
74     return add_header(pool, headers, (h2o_iovec_t *)&token->buf, orig_name, value, value_len, (h2o_header_flags_t){0});
75 }
76 
h2o_add_header_by_str(h2o_mem_pool_t * pool,h2o_headers_t * headers,const char * lowercase_name,size_t lowercase_name_len,int maybe_token,const char * orig_name,const char * value,size_t value_len)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 {
80     if (maybe_token) {
81         const h2o_token_t *token = h2o_lookup_token(lowercase_name, lowercase_name_len);
82         if (token != NULL) {
83             return add_header(pool, headers, (h2o_iovec_t *)token, orig_name, value, value_len, (h2o_header_flags_t){0});
84         }
85     }
86     return add_header(pool, headers, alloc_and_init_iovec(pool, lowercase_name, lowercase_name_len), orig_name, value, value_len,
87                       (h2o_header_flags_t){0});
88 }
89 
h2o_set_header(h2o_mem_pool_t * pool,h2o_headers_t * headers,const h2o_token_t * token,const char * value,size_t value_len,int overwrite_if_exists)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 {
93     ssize_t cursor = h2o_find_header(headers, token, -1);
94     if (cursor != -1) {
95         if (overwrite_if_exists) {
96             headers->entries[cursor].value = h2o_iovec_init(value, value_len);
97         }
98         return cursor;
99     } else {
100         return h2o_add_header(pool, headers, token, NULL, value, value_len);
101     }
102 }
103 
h2o_set_header_by_str(h2o_mem_pool_t * pool,h2o_headers_t * headers,const char * lowercase_name,size_t lowercase_name_len,int maybe_token,const char * value,size_t value_len,int overwrite_if_exists)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 {
107     ssize_t cursor;
108 
109     if (maybe_token) {
110         const h2o_token_t *token = h2o_lookup_token(lowercase_name, lowercase_name_len);
111         if (token != NULL) {
112             return h2o_set_header(pool, headers, token, value, value_len, overwrite_if_exists);
113         }
114     }
115 
116     cursor = h2o_find_header_by_str(headers, lowercase_name, lowercase_name_len, -1);
117     if (cursor != -1) {
118         if (overwrite_if_exists) {
119             headers->entries[cursor].value = h2o_iovec_init(value, value_len);
120         }
121         return cursor;
122     } else {
123         return add_header(pool, headers, alloc_and_init_iovec(pool, lowercase_name, lowercase_name_len), NULL, value, value_len,
124                           (h2o_header_flags_t){0});
125     }
126 }
127 
h2o_set_header_token(h2o_mem_pool_t * pool,h2o_headers_t * headers,const h2o_token_t * token,const char * value,size_t value_len)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 {
131     ssize_t found = -1;
132     size_t i;
133     for (i = 0; i != headers->size; ++i) {
134         if (headers->entries[i].name == &token->buf) {
135             if (h2o_contains_token(headers->entries[i].value.base, headers->entries[i].value.len, value, value_len, ','))
136                 return -1;
137             found = i;
138         }
139     }
140     if (found != -1) {
141         h2o_header_t *dest = headers->entries + found;
142         dest->value = h2o_concat(pool, dest->value, h2o_iovec_init(H2O_STRLIT(", ")), h2o_iovec_init(value, value_len));
143         return found;
144     } else {
145         return h2o_add_header(pool, headers, token, NULL, value, value_len);
146     }
147 }
148 
h2o_delete_header(h2o_headers_t * headers,ssize_t cursor)149 ssize_t h2o_delete_header(h2o_headers_t *headers, ssize_t cursor)
150 {
151     assert(cursor != -1);
152 
153     --headers->size;
154     memmove(headers->entries + cursor, headers->entries + cursor + 1, sizeof(h2o_header_t) * (headers->size - cursor));
155 
156     return cursor;
157 }
158