1 /*
2 * Copyright (c) 2014-2016 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 <inttypes.h>
23 #include <limits.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <netinet/udp.h>
30 #include "h2o.h"
31 #include "h2o/configurator.h"
32 #include "h2o/http1.h"
33 #include "h2o/http2.h"
34 #include "h2o/http3_server.h"
35
create_hostconf(h2o_globalconf_t * globalconf)36 static h2o_hostconf_t *create_hostconf(h2o_globalconf_t *globalconf)
37 {
38 h2o_hostconf_t *hostconf = h2o_mem_alloc(sizeof(*hostconf));
39 *hostconf = (h2o_hostconf_t){globalconf};
40 hostconf->http2.push_preload = 1; /* enabled by default */
41 h2o_config_init_pathconf(&hostconf->fallback_path, globalconf, NULL, globalconf->mimemap);
42 hostconf->mimemap = globalconf->mimemap;
43 h2o_mem_addref_shared(hostconf->mimemap);
44 return hostconf;
45 }
46
destroy_hostconf(h2o_hostconf_t * hostconf)47 static void destroy_hostconf(h2o_hostconf_t *hostconf)
48 {
49 size_t i;
50
51 if (hostconf->authority.hostport.base != hostconf->authority.host.base)
52 free(hostconf->authority.hostport.base);
53 free(hostconf->authority.host.base);
54 for (i = 0; i != hostconf->paths.size; ++i) {
55 h2o_pathconf_t *pathconf = hostconf->paths.entries[i];
56 h2o_config_dispose_pathconf(pathconf);
57 free(pathconf);
58 }
59 free(hostconf->paths.entries);
60 h2o_config_dispose_pathconf(&hostconf->fallback_path);
61 h2o_mem_release_shared(hostconf->mimemap);
62
63 free(hostconf);
64 }
65
on_dispose_envconf(void * _envconf)66 static void on_dispose_envconf(void *_envconf)
67 {
68 h2o_envconf_t *envconf = _envconf;
69 size_t i;
70
71 if (envconf->parent != NULL)
72 h2o_mem_release_shared(envconf->parent);
73
74 for (i = 0; i != envconf->unsets.size; ++i)
75 h2o_mem_release_shared(envconf->unsets.entries[i].base);
76 free(envconf->unsets.entries);
77 for (i = 0; i != envconf->sets.size; ++i)
78 h2o_mem_release_shared(envconf->sets.entries[i].base);
79 free(envconf->sets.entries);
80 }
81
h2o_config_create_envconf(h2o_envconf_t * parent)82 h2o_envconf_t *h2o_config_create_envconf(h2o_envconf_t *parent)
83 {
84 h2o_envconf_t *envconf = h2o_mem_alloc_shared(NULL, sizeof(*envconf), on_dispose_envconf);
85 *envconf = (h2o_envconf_t){NULL};
86
87 if (parent != NULL) {
88 envconf->parent = parent;
89 h2o_mem_addref_shared(parent);
90 }
91 return envconf;
92 }
93
h2o_config_setenv(h2o_envconf_t * envconf,const char * name,const char * value)94 void h2o_config_setenv(h2o_envconf_t *envconf, const char *name, const char *value)
95 {
96 size_t name_len = strlen(name), i;
97 h2o_iovec_t *value_slot;
98
99 /* remove from the list of unsets */
100 for (i = 0; i != envconf->unsets.size; ++i) {
101 if (h2o_memis(envconf->unsets.entries[i].base, envconf->unsets.entries[i].len, name, name_len)) {
102 h2o_mem_release_shared(envconf->unsets.entries[i].base);
103 h2o_vector_erase(&envconf->unsets, i);
104 break;
105 }
106 }
107 /* find the slot */
108 for (i = 0; i != envconf->sets.size; i += 2) {
109 if (h2o_memis(envconf->sets.entries[i].base, envconf->sets.entries[i].len, name, name_len)) {
110 value_slot = envconf->sets.entries + i + 1;
111 h2o_mem_release_shared(value_slot->base);
112 goto SetValue;
113 }
114 }
115 /* name not found in existing sets */
116 h2o_vector_reserve(NULL, &envconf->sets, envconf->sets.size + 2);
117 envconf->sets.entries[envconf->sets.size++] = h2o_strdup_shared(NULL, name, name_len);
118 value_slot = envconf->sets.entries + envconf->sets.size++;
119 SetValue:
120 *value_slot = h2o_strdup_shared(NULL, value, SIZE_MAX);
121 }
122
h2o_config_unsetenv(h2o_envconf_t * envconf,const char * name)123 void h2o_config_unsetenv(h2o_envconf_t *envconf, const char *name)
124 {
125 size_t i, name_len = strlen(name);
126
127 /* do nothing if already set */
128 for (i = 0; i != envconf->unsets.size; ++i)
129 if (h2o_memis(envconf->unsets.entries[i].base, envconf->unsets.entries[i].len, name, name_len))
130 return;
131 /* register */
132 h2o_vector_reserve(NULL, &envconf->unsets, envconf->unsets.size + 1);
133 envconf->unsets.entries[envconf->unsets.size++] = h2o_strdup_shared(NULL, name, name_len);
134 }
135
h2o_config_init_pathconf(h2o_pathconf_t * pathconf,h2o_globalconf_t * globalconf,const char * path,h2o_mimemap_t * mimemap)136 void h2o_config_init_pathconf(h2o_pathconf_t *pathconf, h2o_globalconf_t *globalconf, const char *path, h2o_mimemap_t *mimemap)
137 {
138 memset(pathconf, 0, sizeof(*pathconf));
139 pathconf->global = globalconf;
140 if (path != NULL)
141 pathconf->path = h2o_strdup(NULL, path, SIZE_MAX);
142 h2o_mem_addref_shared(mimemap);
143 pathconf->mimemap = mimemap;
144 pathconf->error_log.emit_request_errors = 1;
145 }
146
h2o_config_dispose_pathconf(h2o_pathconf_t * pathconf)147 void h2o_config_dispose_pathconf(h2o_pathconf_t *pathconf)
148 {
149 #define DESTROY_LIST(type, list) \
150 do { \
151 size_t i; \
152 for (i = 0; i != list.size; ++i) { \
153 type *e = list.entries[i]; \
154 if (e->dispose != NULL) \
155 e->dispose(e); \
156 free(e); \
157 } \
158 free(list.entries); \
159 } while (0)
160 DESTROY_LIST(h2o_handler_t, pathconf->handlers);
161 DESTROY_LIST(h2o_filter_t, pathconf->_filters);
162 DESTROY_LIST(h2o_logger_t, pathconf->_loggers);
163 #undef DESTROY_LIST
164
165 free(pathconf->path.base);
166 if (pathconf->mimemap != NULL)
167 h2o_mem_release_shared(pathconf->mimemap);
168 if (pathconf->env != NULL)
169 h2o_mem_release_shared(pathconf->env);
170 }
171
h2o_config_init(h2o_globalconf_t * config)172 void h2o_config_init(h2o_globalconf_t *config)
173 {
174 memset(config, 0, sizeof(*config));
175 config->hosts = h2o_mem_alloc(sizeof(config->hosts[0]));
176 config->hosts[0] = NULL;
177 h2o_linklist_init_anchor(&config->configurators);
178 config->server_name = h2o_iovec_init(H2O_STRLIT("h2o/" H2O_VERSION));
179 config->max_request_entity_size = H2O_DEFAULT_MAX_REQUEST_ENTITY_SIZE;
180 config->max_delegations = H2O_DEFAULT_MAX_DELEGATIONS;
181 config->handshake_timeout = H2O_DEFAULT_HANDSHAKE_TIMEOUT;
182 config->http1.req_timeout = H2O_DEFAULT_HTTP1_REQ_TIMEOUT;
183 config->http1.req_io_timeout = H2O_DEFAULT_HTTP1_REQ_IO_TIMEOUT;
184 config->http1.upgrade_to_http2 = H2O_DEFAULT_HTTP1_UPGRADE_TO_HTTP2;
185 config->http1.callbacks = H2O_HTTP1_CALLBACKS;
186 config->http2.idle_timeout = H2O_DEFAULT_HTTP2_IDLE_TIMEOUT;
187 config->http2.graceful_shutdown_timeout = H2O_DEFAULT_HTTP2_GRACEFUL_SHUTDOWN_TIMEOUT;
188 config->proxy.io_timeout = H2O_DEFAULT_PROXY_IO_TIMEOUT;
189 config->proxy.connect_timeout = H2O_DEFAULT_PROXY_IO_TIMEOUT;
190 config->proxy.first_byte_timeout = H2O_DEFAULT_PROXY_IO_TIMEOUT;
191 config->proxy.emit_x_forwarded_headers = 1;
192 config->proxy.emit_via_header = 1;
193 config->proxy.emit_missing_date_header = 1;
194 config->http2.max_concurrent_requests_per_connection = H2O_HTTP2_SETTINGS_HOST_MAX_CONCURRENT_STREAMS;
195 config->http2.max_concurrent_streaming_requests_per_connection = H2O_HTTP2_SETTINGS_HOST_MAX_CONCURRENT_STREAMING_REQUESTS;
196 config->http2.max_streams_for_priority = 16;
197 config->http2.active_stream_window_size = H2O_DEFAULT_HTTP2_ACTIVE_STREAM_WINDOW_SIZE;
198 config->http2.latency_optimization.min_rtt = 50; // milliseconds
199 config->http2.latency_optimization.max_additional_delay = 10;
200 config->http2.latency_optimization.max_cwnd = 65535;
201 config->http2.callbacks = H2O_HTTP2_CALLBACKS;
202 config->http3.idle_timeout = quicly_spec_context.transport_params.max_idle_timeout;
203 config->http3.active_stream_window_size = H2O_DEFAULT_HTTP3_ACTIVE_STREAM_WINDOW_SIZE;
204 config->http3.allow_delayed_ack = 1;
205 config->http3.use_gso = 1;
206 config->http3.callbacks = H2O_HTTP3_SERVER_CALLBACKS;
207 config->send_informational_mode = H2O_SEND_INFORMATIONAL_MODE_EXCEPT_H1;
208 config->mimemap = h2o_mimemap_create();
209 h2o_socketpool_init_global(&config->proxy.global_socketpool, SIZE_MAX);
210
211 h2o_configurator__init_core(config);
212
213 config->fallback_host = create_hostconf(config);
214 config->fallback_host->authority.port = 65535;
215 config->fallback_host->authority.host = h2o_strdup(NULL, H2O_STRLIT("*"));
216 config->fallback_host->authority.hostport = h2o_strdup(NULL, H2O_STRLIT("*"));
217 }
218
h2o_config_register_path(h2o_hostconf_t * hostconf,const char * path,int flags)219 h2o_pathconf_t *h2o_config_register_path(h2o_hostconf_t *hostconf, const char *path, int flags)
220 {
221 h2o_pathconf_t *pathconf = h2o_mem_alloc(sizeof(*pathconf));
222 h2o_config_init_pathconf(pathconf, hostconf->global, path, hostconf->mimemap);
223
224 h2o_vector_reserve(NULL, &hostconf->paths, hostconf->paths.size + 1);
225 hostconf->paths.entries[hostconf->paths.size++] = pathconf;
226
227 return pathconf;
228 }
229
h2o_config_register_status_handler(h2o_globalconf_t * config,h2o_status_handler_t * status_handler)230 void h2o_config_register_status_handler(h2o_globalconf_t *config, h2o_status_handler_t *status_handler)
231 {
232 /* check if the status handler is already registered */
233 size_t i;
234 for (i = 0; i != config->statuses.size; ++i)
235 if (config->statuses.entries[i] == status_handler)
236 return;
237 /* register the new handler */
238 h2o_vector_reserve(NULL, &config->statuses, config->statuses.size + 1);
239 config->statuses.entries[config->statuses.size++] = status_handler;
240 }
241
h2o_config_register_host(h2o_globalconf_t * config,h2o_iovec_t host,uint16_t port)242 h2o_hostconf_t *h2o_config_register_host(h2o_globalconf_t *config, h2o_iovec_t host, uint16_t port)
243 {
244 h2o_hostconf_t *hostconf = NULL;
245 h2o_iovec_t host_lc;
246
247 assert(host.len != 0);
248
249 /* convert hostname to lowercase */
250 host_lc = h2o_strdup(NULL, host.base, host.len);
251 h2o_strtolower(host_lc.base, host_lc.len);
252
253 { /* return NULL if given authority is already registered */
254 h2o_hostconf_t **p;
255 for (p = config->hosts; *p != NULL; ++p)
256 if (h2o_memis((*p)->authority.host.base, (*p)->authority.host.len, host_lc.base, host_lc.len) &&
257 (*p)->authority.port == port)
258 goto Exit;
259 }
260
261 /* create hostconf */
262 hostconf = create_hostconf(config);
263 hostconf->authority.host = host_lc;
264 host_lc = (h2o_iovec_t){NULL};
265 hostconf->authority.port = port;
266 if (hostconf->authority.port == 65535) {
267 hostconf->authority.hostport = hostconf->authority.host;
268 } else {
269 hostconf->authority.hostport.base = h2o_mem_alloc(hostconf->authority.host.len + sizeof("[]:" H2O_UINT16_LONGEST_STR));
270 if (strchr(hostconf->authority.host.base, ':') != NULL) {
271 hostconf->authority.hostport.len =
272 sprintf(hostconf->authority.hostport.base, "[%s]:%" PRIu16, hostconf->authority.host.base, port);
273 } else {
274 hostconf->authority.hostport.len =
275 sprintf(hostconf->authority.hostport.base, "%s:%" PRIu16, hostconf->authority.host.base, port);
276 }
277 }
278
279 /* append to the list */
280 h2o_append_to_null_terminated_list((void *)&config->hosts, hostconf);
281
282 Exit:
283 free(host_lc.base);
284 return hostconf;
285 }
286
h2o_config_dispose(h2o_globalconf_t * config)287 void h2o_config_dispose(h2o_globalconf_t *config)
288 {
289 size_t i;
290
291 for (i = 0; config->hosts[i] != NULL; ++i) {
292 h2o_hostconf_t *hostconf = config->hosts[i];
293 destroy_hostconf(hostconf);
294 }
295 free(config->hosts);
296
297 destroy_hostconf(config->fallback_host);
298
299 h2o_socketpool_dispose(&config->proxy.global_socketpool);
300 h2o_mem_release_shared(config->mimemap);
301 h2o_configurator__dispose_configurators(config);
302 }
303
h2o_create_handler(h2o_pathconf_t * conf,size_t sz)304 h2o_handler_t *h2o_create_handler(h2o_pathconf_t *conf, size_t sz)
305 {
306 h2o_handler_t *handler = h2o_mem_alloc(sz);
307
308 memset(handler, 0, sz);
309 handler->_config_slot = conf->global->_num_config_slots++;
310
311 h2o_vector_reserve(NULL, &conf->handlers, conf->handlers.size + 1);
312 conf->handlers.entries[conf->handlers.size++] = handler;
313
314 return handler;
315 }
316
h2o_create_filter(h2o_pathconf_t * conf,size_t sz)317 h2o_filter_t *h2o_create_filter(h2o_pathconf_t *conf, size_t sz)
318 {
319 h2o_filter_t *filter = h2o_mem_alloc(sz);
320
321 memset(filter, 0, sz);
322 filter->_config_slot = conf->global->_num_config_slots++;
323
324 h2o_vector_reserve(NULL, &conf->_filters, conf->_filters.size + 1);
325 memmove(conf->_filters.entries + 1, conf->_filters.entries, conf->_filters.size * sizeof(conf->_filters.entries[0]));
326 conf->_filters.entries[0] = filter;
327 ++conf->_filters.size;
328
329 return filter;
330 }
331
h2o_create_logger(h2o_pathconf_t * conf,size_t sz)332 h2o_logger_t *h2o_create_logger(h2o_pathconf_t *conf, size_t sz)
333 {
334 h2o_logger_t *logger = h2o_mem_alloc(sz);
335
336 memset(logger, 0, sz);
337 logger->_config_slot = conf->global->_num_config_slots++;
338
339 h2o_vector_reserve(NULL, &conf->_loggers, conf->_loggers.size + 1);
340 conf->_loggers.entries[conf->_loggers.size++] = logger;
341
342 return logger;
343 }
344