diff options
Diffstat (limited to 'web/server/h2o/libh2o/lib/core')
-rw-r--r-- | web/server/h2o/libh2o/lib/core/config.c | 325 | ||||
-rw-r--r-- | web/server/h2o/libh2o/lib/core/configurator.c | 1102 | ||||
-rw-r--r-- | web/server/h2o/libh2o/lib/core/context.c | 201 | ||||
-rw-r--r-- | web/server/h2o/libh2o/lib/core/headers.c | 155 | ||||
-rw-r--r-- | web/server/h2o/libh2o/lib/core/logconf.c | 793 | ||||
-rw-r--r-- | web/server/h2o/libh2o/lib/core/proxy.c | 610 | ||||
-rw-r--r-- | web/server/h2o/libh2o/lib/core/request.c | 696 | ||||
-rw-r--r-- | web/server/h2o/libh2o/lib/core/token.c | 28 | ||||
-rw-r--r-- | web/server/h2o/libh2o/lib/core/token_table.h | 408 | ||||
-rw-r--r-- | web/server/h2o/libh2o/lib/core/util.c | 562 |
10 files changed, 0 insertions, 4880 deletions
diff --git a/web/server/h2o/libh2o/lib/core/config.c b/web/server/h2o/libh2o/lib/core/config.c deleted file mode 100644 index ce1d32018..000000000 --- a/web/server/h2o/libh2o/lib/core/config.c +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (c) 2014-2016 DeNA Co., Ltd. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#include <inttypes.h> -#include <limits.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "h2o.h" -#include "h2o/configurator.h" -#include "h2o/http1.h" -#include "h2o/http2.h" - -static h2o_hostconf_t *create_hostconf(h2o_globalconf_t *globalconf) -{ - h2o_hostconf_t *hostconf = h2o_mem_alloc(sizeof(*hostconf)); - *hostconf = (h2o_hostconf_t){globalconf}; - hostconf->http2.push_preload = 1; /* enabled by default */ - h2o_config_init_pathconf(&hostconf->fallback_path, globalconf, NULL, globalconf->mimemap); - hostconf->mimemap = globalconf->mimemap; - h2o_mem_addref_shared(hostconf->mimemap); - return hostconf; -} - -static void destroy_hostconf(h2o_hostconf_t *hostconf) -{ - size_t i; - - if (hostconf->authority.hostport.base != hostconf->authority.host.base) - free(hostconf->authority.hostport.base); - free(hostconf->authority.host.base); - for (i = 0; i != hostconf->paths.size; ++i) { - h2o_pathconf_t *pathconf = hostconf->paths.entries + i; - h2o_config_dispose_pathconf(pathconf); - } - free(hostconf->paths.entries); - h2o_config_dispose_pathconf(&hostconf->fallback_path); - h2o_mem_release_shared(hostconf->mimemap); - - free(hostconf); -} - -static void on_dispose_envconf(void *_envconf) -{ - h2o_envconf_t *envconf = _envconf; - size_t i; - - if (envconf->parent != NULL) - h2o_mem_release_shared(envconf->parent); - - for (i = 0; i != envconf->unsets.size; ++i) - h2o_mem_release_shared(envconf->unsets.entries[i].base); - free(envconf->unsets.entries); - for (i = 0; i != envconf->sets.size; ++i) - h2o_mem_release_shared(envconf->sets.entries[i].base); - free(envconf->sets.entries); -} - -h2o_envconf_t *h2o_config_create_envconf(h2o_envconf_t *parent) -{ - h2o_envconf_t *envconf = h2o_mem_alloc_shared(NULL, sizeof(*envconf), on_dispose_envconf); - *envconf = (h2o_envconf_t){NULL}; - - if (parent != NULL) { - envconf->parent = parent; - h2o_mem_addref_shared(parent); - } - return envconf; -} - -void h2o_config_setenv(h2o_envconf_t *envconf, const char *name, const char *value) -{ - size_t name_len = strlen(name), i; - h2o_iovec_t *value_slot; - - /* remove from the list of unsets */ - for (i = 0; i != envconf->unsets.size; ++i) { - if (h2o_memis(envconf->unsets.entries[i].base, envconf->unsets.entries[i].len, name, name_len)) { - h2o_mem_release_shared(envconf->unsets.entries[i].base); - h2o_vector_erase(&envconf->unsets, i); - break; - } - } - /* find the slot */ - for (i = 0; i != envconf->sets.size; i += 2) { - if (h2o_memis(envconf->sets.entries[i].base, envconf->sets.entries[i].len, name, name_len)) { - value_slot = envconf->sets.entries + i + 1; - h2o_mem_release_shared(value_slot->base); - goto SetValue; - } - } - /* name not found in existing sets */ - h2o_vector_reserve(NULL, &envconf->sets, envconf->sets.size + 2); - envconf->sets.entries[envconf->sets.size++] = h2o_strdup_shared(NULL, name, name_len); - value_slot = envconf->sets.entries + envconf->sets.size++; -SetValue: - *value_slot = h2o_strdup_shared(NULL, value, SIZE_MAX); -} - -void h2o_config_unsetenv(h2o_envconf_t *envconf, const char *name) -{ - size_t i, name_len = strlen(name); - - /* do nothing if already set */ - for (i = 0; i != envconf->unsets.size; ++i) - if (h2o_memis(envconf->unsets.entries[i].base, envconf->unsets.entries[i].len, name, name_len)) - return; - /* register */ - h2o_vector_reserve(NULL, &envconf->unsets, envconf->unsets.size + 1); - envconf->unsets.entries[envconf->unsets.size++] = h2o_strdup_shared(NULL, name, name_len); -} - -void h2o_config_init_pathconf(h2o_pathconf_t *pathconf, h2o_globalconf_t *globalconf, const char *path, h2o_mimemap_t *mimemap) -{ - memset(pathconf, 0, sizeof(*pathconf)); - pathconf->global = globalconf; - h2o_chunked_register(pathconf); - if (path != NULL) - pathconf->path = h2o_strdup(NULL, path, SIZE_MAX); - h2o_mem_addref_shared(mimemap); - pathconf->mimemap = mimemap; - pathconf->error_log.emit_request_errors = 1; -} - -void h2o_config_dispose_pathconf(h2o_pathconf_t *pathconf) -{ -#define DESTROY_LIST(type, list) \ - do { \ - size_t i; \ - for (i = 0; i != list.size; ++i) { \ - type *e = list.entries[i]; \ - if (e->dispose != NULL) \ - e->dispose(e); \ - free(e); \ - } \ - free(list.entries); \ - } while (0) - DESTROY_LIST(h2o_handler_t, pathconf->handlers); - DESTROY_LIST(h2o_filter_t, pathconf->filters); - DESTROY_LIST(h2o_logger_t, pathconf->loggers); -#undef DESTROY_LIST - - free(pathconf->path.base); - if (pathconf->mimemap != NULL) - h2o_mem_release_shared(pathconf->mimemap); - if (pathconf->env != NULL) - h2o_mem_release_shared(pathconf->env); -} - -void h2o_config_init(h2o_globalconf_t *config) -{ - memset(config, 0, sizeof(*config)); - config->hosts = h2o_mem_alloc(sizeof(config->hosts[0])); - config->hosts[0] = NULL; - h2o_linklist_init_anchor(&config->configurators); - config->server_name = h2o_iovec_init(H2O_STRLIT("h2o/" H2O_VERSION)); - config->max_request_entity_size = H2O_DEFAULT_MAX_REQUEST_ENTITY_SIZE; - config->max_delegations = H2O_DEFAULT_MAX_DELEGATIONS; - config->handshake_timeout = H2O_DEFAULT_HANDSHAKE_TIMEOUT; - config->http1.req_timeout = H2O_DEFAULT_HTTP1_REQ_TIMEOUT; - config->http1.upgrade_to_http2 = H2O_DEFAULT_HTTP1_UPGRADE_TO_HTTP2; - config->http1.callbacks = H2O_HTTP1_CALLBACKS; - config->http2.idle_timeout = H2O_DEFAULT_HTTP2_IDLE_TIMEOUT; - config->http2.graceful_shutdown_timeout = H2O_DEFAULT_HTTP2_GRACEFUL_SHUTDOWN_TIMEOUT; - config->proxy.io_timeout = H2O_DEFAULT_PROXY_IO_TIMEOUT; - config->proxy.emit_x_forwarded_headers = 1; - config->proxy.emit_via_header = 1; - config->http2.max_concurrent_requests_per_connection = H2O_HTTP2_SETTINGS_HOST.max_concurrent_streams; - config->http2.max_streams_for_priority = 16; - config->http2.latency_optimization.min_rtt = 50; // milliseconds - config->http2.latency_optimization.max_additional_delay = 10; - config->http2.latency_optimization.max_cwnd = 65535; - config->http2.callbacks = H2O_HTTP2_CALLBACKS; - config->mimemap = h2o_mimemap_create(); - - h2o_configurator__init_core(config); -} - -h2o_pathconf_t *h2o_config_register_path(h2o_hostconf_t *hostconf, const char *path, int flags) -{ - h2o_pathconf_t *pathconf; - - h2o_vector_reserve(NULL, &hostconf->paths, hostconf->paths.size + 1); - pathconf = hostconf->paths.entries + hostconf->paths.size++; - - h2o_config_init_pathconf(pathconf, hostconf->global, path, hostconf->mimemap); - - return pathconf; -} - -void h2o_config_register_status_handler(h2o_globalconf_t *config, h2o_status_handler_t status_handler) -{ - h2o_vector_reserve(NULL, &config->statuses, config->statuses.size + 1); - config->statuses.entries[config->statuses.size++] = status_handler; -} - -void h2o_config_register_simple_status_handler(h2o_globalconf_t *config, h2o_iovec_t name, final_status_handler_cb status_handler) -{ - h2o_status_handler_t *sh; - - h2o_vector_reserve(NULL, &config->statuses, config->statuses.size + 1); - sh = &config->statuses.entries[config->statuses.size++]; - memset(sh, 0, sizeof(*sh)); - sh->name = h2o_strdup(NULL, name.base, name.len); - sh->final = status_handler; -} - -h2o_hostconf_t *h2o_config_register_host(h2o_globalconf_t *config, h2o_iovec_t host, uint16_t port) -{ - h2o_hostconf_t *hostconf = NULL; - h2o_iovec_t host_lc; - - assert(host.len != 0); - - /* convert hostname to lowercase */ - host_lc = h2o_strdup(NULL, host.base, host.len); - h2o_strtolower(host_lc.base, host_lc.len); - - { /* return NULL if given authority is already registered */ - h2o_hostconf_t **p; - for (p = config->hosts; *p != NULL; ++p) - if (h2o_memis((*p)->authority.host.base, (*p)->authority.host.len, host_lc.base, host_lc.len) && - (*p)->authority.port == port) - goto Exit; - } - - /* create hostconf */ - hostconf = create_hostconf(config); - hostconf->authority.host = host_lc; - host_lc = (h2o_iovec_t){NULL}; - hostconf->authority.port = port; - if (hostconf->authority.port == 65535) { - hostconf->authority.hostport = hostconf->authority.host; - } else { - hostconf->authority.hostport.base = h2o_mem_alloc(hostconf->authority.host.len + sizeof("[]:" H2O_UINT16_LONGEST_STR)); - if (strchr(hostconf->authority.host.base, ':') != NULL) { - hostconf->authority.hostport.len = - sprintf(hostconf->authority.hostport.base, "[%s]:%" PRIu16, hostconf->authority.host.base, port); - } else { - hostconf->authority.hostport.len = - sprintf(hostconf->authority.hostport.base, "%s:%" PRIu16, hostconf->authority.host.base, port); - } - } - - /* append to the list */ - h2o_append_to_null_terminated_list((void *)&config->hosts, hostconf); - -Exit: - free(host_lc.base); - return hostconf; -} - -void h2o_config_dispose(h2o_globalconf_t *config) -{ - size_t i; - - for (i = 0; config->hosts[i] != NULL; ++i) { - h2o_hostconf_t *hostconf = config->hosts[i]; - destroy_hostconf(hostconf); - } - free(config->hosts); - - h2o_mem_release_shared(config->mimemap); - h2o_configurator__dispose_configurators(config); -} - -h2o_handler_t *h2o_create_handler(h2o_pathconf_t *conf, size_t sz) -{ - h2o_handler_t *handler = h2o_mem_alloc(sz); - - memset(handler, 0, sz); - handler->_config_slot = conf->global->_num_config_slots++; - - h2o_vector_reserve(NULL, &conf->handlers, conf->handlers.size + 1); - conf->handlers.entries[conf->handlers.size++] = handler; - - return handler; -} - -h2o_filter_t *h2o_create_filter(h2o_pathconf_t *conf, size_t sz) -{ - h2o_filter_t *filter = h2o_mem_alloc(sz); - - memset(filter, 0, sz); - filter->_config_slot = conf->global->_num_config_slots++; - - h2o_vector_reserve(NULL, &conf->filters, conf->filters.size + 1); - memmove(conf->filters.entries + 1, conf->filters.entries, conf->filters.size * sizeof(conf->filters.entries[0])); - conf->filters.entries[0] = filter; - ++conf->filters.size; - - return filter; -} - -h2o_logger_t *h2o_create_logger(h2o_pathconf_t *conf, size_t sz) -{ - h2o_logger_t *logger = h2o_mem_alloc(sz); - - memset(logger, 0, sz); - logger->_config_slot = conf->global->_num_config_slots++; - - h2o_vector_reserve(NULL, &conf->loggers, conf->loggers.size + 1); - conf->loggers.entries[conf->loggers.size++] = logger; - - return logger; -} diff --git a/web/server/h2o/libh2o/lib/core/configurator.c b/web/server/h2o/libh2o/lib/core/configurator.c deleted file mode 100644 index 891770cc2..000000000 --- a/web/server/h2o/libh2o/lib/core/configurator.c +++ /dev/null @@ -1,1102 +0,0 @@ -/* - * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Fastly, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <inttypes.h> -#include "h2o.h" -#include "h2o/configurator.h" - -struct st_core_config_vars_t { - struct { - unsigned reprioritize_blocking_assets : 1; - unsigned push_preload : 1; - h2o_casper_conf_t casper; - } http2; - struct { - unsigned emit_request_errors : 1; - } error_log; -}; - -struct st_core_configurator_t { - h2o_configurator_t super; - struct st_core_config_vars_t *vars, _vars_stack[H2O_CONFIGURATOR_NUM_LEVELS + 1]; -}; - -static h2o_configurator_context_t *create_context(h2o_configurator_context_t *parent, int is_custom_handler) -{ - h2o_configurator_context_t *ctx = h2o_mem_alloc(sizeof(*ctx)); - if (parent == NULL) { - *ctx = (h2o_configurator_context_t){NULL}; - return ctx; - } - *ctx = *parent; - if (ctx->env != NULL) - h2o_mem_addref_shared(ctx->env); - ctx->parent = parent; - return ctx; -} - -static void destroy_context(h2o_configurator_context_t *ctx) -{ - if (ctx->env != NULL) { - if (ctx->pathconf != NULL) - ctx->pathconf->env = ctx->env; - else - h2o_mem_release_shared(ctx->env); - } - free(ctx); -} - -static int on_core_enter(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_core_configurator_t *self = (void *)_self; - - ++self->vars; - self->vars[0] = self->vars[-1]; - return 0; -} - -static int on_core_exit(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_core_configurator_t *self = (void *)_self; - - if (ctx->hostconf != NULL && ctx->pathconf == NULL) { - /* exitting from host-level configuration */ - ctx->hostconf->http2.reprioritize_blocking_assets = self->vars->http2.reprioritize_blocking_assets; - ctx->hostconf->http2.push_preload = self->vars->http2.push_preload; - ctx->hostconf->http2.casper = self->vars->http2.casper; - } else if (ctx->pathconf != NULL) { - /* exitting from path or extension-level configuration */ - ctx->pathconf->error_log.emit_request_errors = self->vars->error_log.emit_request_errors; - } - - --self->vars; - return 0; -} - -static void destroy_configurator(h2o_configurator_t *configurator) -{ - if (configurator->dispose != NULL) - configurator->dispose(configurator); - free(configurator->commands.entries); - free(configurator); -} - -static int setup_configurators(h2o_configurator_context_t *ctx, int is_enter, yoml_t *node) -{ - h2o_linklist_t *n; - - for (n = ctx->globalconf->configurators.next; n != &ctx->globalconf->configurators; n = n->next) { - h2o_configurator_t *c = H2O_STRUCT_FROM_MEMBER(h2o_configurator_t, _link, n); - if (is_enter) { - if (c->enter != NULL && c->enter(c, ctx, node) != 0) - return -1; - } else { - if (c->exit != NULL && c->exit(c, ctx, node) != 0) - return -1; - } - } - - return 0; -} - -static int config_timeout(h2o_configurator_command_t *cmd, yoml_t *node, uint64_t *slot) -{ - uint64_t timeout_in_secs; - - if (h2o_configurator_scanf(cmd, node, "%" SCNu64, &timeout_in_secs) != 0) - return -1; - - *slot = timeout_in_secs * 1000; - return 0; -} - -int h2o_configurator_apply_commands(h2o_configurator_context_t *ctx, yoml_t *node, int flags_mask, const char **ignore_commands) -{ - struct st_cmd_value_t { - h2o_configurator_command_t *cmd; - yoml_t *value; - }; - H2O_VECTOR(struct st_cmd_value_t) deferred = {NULL}, semi_deferred = {NULL}; - int ret = -1; - - if (node != NULL && node->type != YOML_TYPE_MAPPING) { - h2o_configurator_errprintf(NULL, node, "node must be a MAPPING"); - goto Exit; - } - - /* call on_enter of every configurator */ - if (setup_configurators(ctx, 1, node) != 0) - goto Exit; - - /* handle the configuration commands */ - if (node != NULL) { - size_t i; - for (i = 0; i != node->data.mapping.size; ++i) { - yoml_t *key = node->data.mapping.elements[i].key, *value = node->data.mapping.elements[i].value; - h2o_configurator_command_t *cmd; - /* obtain the target command */ - if (key->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(NULL, key, "command must be a string"); - goto Exit; - } - if (ignore_commands != NULL) { - size_t i; - for (i = 0; ignore_commands[i] != NULL; ++i) - if (strcmp(ignore_commands[i], key->data.scalar) == 0) - goto SkipCommand; - } - if ((cmd = h2o_configurator_get_command(ctx->globalconf, key->data.scalar)) == NULL) { - h2o_configurator_errprintf(NULL, key, "unknown command: %s", key->data.scalar); - goto Exit; - } - if ((cmd->flags & flags_mask) == 0) { - h2o_configurator_errprintf(cmd, key, "the command cannot be used at this level"); - goto Exit; - } - /* check value type */ - if ((cmd->flags & (H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR | H2O_CONFIGURATOR_FLAG_EXPECT_SEQUENCE | - H2O_CONFIGURATOR_FLAG_EXPECT_MAPPING)) != 0) { - switch (value->type) { - case YOML_TYPE_SCALAR: - if ((cmd->flags & H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR) == 0) { - h2o_configurator_errprintf(cmd, value, "argument cannot be a scalar"); - goto Exit; - } - break; - case YOML_TYPE_SEQUENCE: - if ((cmd->flags & H2O_CONFIGURATOR_FLAG_EXPECT_SEQUENCE) == 0) { - h2o_configurator_errprintf(cmd, value, "argument cannot be a sequence"); - goto Exit; - } - break; - case YOML_TYPE_MAPPING: - if ((cmd->flags & H2O_CONFIGURATOR_FLAG_EXPECT_MAPPING) == 0) { - h2o_configurator_errprintf(cmd, value, "argument cannot be a mapping"); - goto Exit; - } - break; - default: - assert(!"unreachable"); - break; - } - } - /* handle the command (or keep it for later execution) */ - if ((cmd->flags & H2O_CONFIGURATOR_FLAG_SEMI_DEFERRED) != 0) { - h2o_vector_reserve(NULL, &semi_deferred, semi_deferred.size + 1); - semi_deferred.entries[semi_deferred.size++] = (struct st_cmd_value_t){cmd, value}; - } else if ((cmd->flags & H2O_CONFIGURATOR_FLAG_DEFERRED) != 0) { - h2o_vector_reserve(NULL, &deferred, deferred.size + 1); - deferred.entries[deferred.size++] = (struct st_cmd_value_t){cmd, value}; - } else { - if (cmd->cb(cmd, ctx, value) != 0) - goto Exit; - } - SkipCommand:; - } - for (i = 0; i != semi_deferred.size; ++i) { - struct st_cmd_value_t *pair = semi_deferred.entries + i; - if (pair->cmd->cb(pair->cmd, ctx, pair->value) != 0) - goto Exit; - } - for (i = 0; i != deferred.size; ++i) { - struct st_cmd_value_t *pair = deferred.entries + i; - if (pair->cmd->cb(pair->cmd, ctx, pair->value) != 0) - goto Exit; - } - } - - /* call on_exit of every configurator */ - if (setup_configurators(ctx, 0, node) != 0) - goto Exit; - - ret = 0; -Exit: - free(deferred.entries); - free(semi_deferred.entries); - return ret; -} - -static int sort_from_longer_paths(const yoml_mapping_element_t *x, const yoml_mapping_element_t *y) -{ - size_t xlen = strlen(x->key->data.scalar), ylen = strlen(y->key->data.scalar); - if (xlen < ylen) - return 1; - else if (xlen > ylen) - return -1; - /* apply strcmp for stable sort */ - return strcmp(x->key->data.scalar, y->key->data.scalar); -} - -static yoml_t *convert_path_config_node(h2o_configurator_command_t *cmd, yoml_t *node) -{ - size_t i, j; - - switch (node->type) { - case YOML_TYPE_MAPPING: - break; - case YOML_TYPE_SEQUENCE: { - /* convert to mapping */ - yoml_t *map = h2o_mem_alloc(sizeof(yoml_t)); - *map = (yoml_t){YOML_TYPE_MAPPING}; - if (node->filename != NULL) - map->filename = h2o_strdup(NULL, node->filename, SIZE_MAX).base; - map->line = node->line; - map->column = node->column; - if (node->anchor != NULL) - map->anchor = h2o_strdup(NULL, node->anchor, SIZE_MAX).base; - map->_refcnt = 1; - - for (i = 0; i != node->data.sequence.size; ++i) { - yoml_t *elem = node->data.sequence.elements[i]; - if (elem->type != YOML_TYPE_MAPPING) { - yoml_free(map, NULL); - goto Error; - } - for (j = 0; j != elem->data.mapping.size; ++j) { - yoml_t *elemkey = elem->data.mapping.elements[j].key; - yoml_t *elemvalue = elem->data.mapping.elements[j].value; - map = h2o_mem_realloc(map, offsetof(yoml_t, data.mapping.elements) + - sizeof(yoml_mapping_element_t) * (map->data.mapping.size + 1)); - map->data.mapping.elements[map->data.mapping.size].key = elemkey; - map->data.mapping.elements[map->data.mapping.size].value = elemvalue; - ++map->data.mapping.size; - ++elemkey->_refcnt; - ++elemvalue->_refcnt; - } - } - return map; - } break; - default: - Error: - h2o_configurator_errprintf(cmd, node, "value must be a mapping or sequence of mapping"); - return NULL; - } - - ++node->_refcnt; - return node; -} - -static int config_path(h2o_configurator_context_t *parent_ctx, h2o_pathconf_t *pathconf, yoml_t *node) -{ - h2o_configurator_context_t *path_ctx = create_context(parent_ctx, 0); - path_ctx->pathconf = pathconf; - path_ctx->mimemap = &pathconf->mimemap; - - int ret = h2o_configurator_apply_commands(path_ctx, node, H2O_CONFIGURATOR_FLAG_PATH, NULL); - - destroy_context(path_ctx); - return ret; -} - -static int on_config_paths(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - size_t i; - - /* sort by the length of the path (descending) */ - for (i = 0; i != node->data.mapping.size; ++i) { - yoml_t *key = node->data.mapping.elements[i].key; - if (key->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, key, "key (representing the virtual path) must be a string"); - return -1; - } - } - qsort(node->data.mapping.elements, node->data.mapping.size, sizeof(node->data.mapping.elements[0]), - (int (*)(const void *, const void *))sort_from_longer_paths); - - for (i = 0; i != node->data.mapping.size; ++i) { - yoml_t *key = node->data.mapping.elements[i].key, *value; - if ((value = convert_path_config_node(cmd, node->data.mapping.elements[i].value)) == NULL) - return -1; - h2o_pathconf_t *pathconf = h2o_config_register_path(ctx->hostconf, key->data.scalar, 0); - int cmd_ret = config_path(ctx, pathconf, value); - yoml_free(value, NULL); - if (cmd_ret != 0) - return cmd_ret; - } - - /* configure fallback path along with ordinary paths */ - return config_path(ctx, &ctx->hostconf->fallback_path, NULL); -} - -static int on_config_hosts(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - size_t i; - - if (node->data.mapping.size == 0) { - h2o_configurator_errprintf(cmd, node, "the mapping cannot be empty"); - return -1; - } - - for (i = 0; i != node->data.mapping.size; ++i) { - yoml_t *key = node->data.mapping.elements[i].key; - yoml_t *value = node->data.mapping.elements[i].value; - h2o_iovec_t hostname; - uint16_t port; - if (key->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, key, "key (representing the hostname) must be a string"); - return -1; - } - if (h2o_url_parse_hostport(key->data.scalar, strlen(key->data.scalar), &hostname, &port) == NULL) { - h2o_configurator_errprintf(cmd, key, "invalid key (must be either `host` or `host:port`)"); - return -1; - } - assert(hostname.len != 0); - if ((hostname.base[0] == '*' && !(hostname.len == 1 || hostname.base[1] == '.')) || - memchr(hostname.base + 1, '*', hostname.len - 1) != NULL) { - h2o_configurator_errprintf(cmd, key, "wildcard (*) can only be used at the start of the hostname"); - return -1; - } - h2o_configurator_context_t *host_ctx = create_context(ctx, 0); - if ((host_ctx->hostconf = h2o_config_register_host(host_ctx->globalconf, hostname, port)) == NULL) { - h2o_configurator_errprintf(cmd, key, "duplicate host entry"); - destroy_context(host_ctx); - return -1; - } - host_ctx->mimemap = &host_ctx->hostconf->mimemap; - int cmd_ret = h2o_configurator_apply_commands(host_ctx, value, H2O_CONFIGURATOR_FLAG_HOST, NULL); - destroy_context(host_ctx); - if (cmd_ret != 0) - return -1; - if (yoml_get(value, "paths") == NULL) { - h2o_configurator_errprintf(NULL, value, "mandatory configuration directive `paths` is missing"); - return -1; - } - } - - return 0; -} - -static int on_config_limit_request_body(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - return h2o_configurator_scanf(cmd, node, "%zu", &ctx->globalconf->max_request_entity_size); -} - -static int on_config_max_delegations(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - return h2o_configurator_scanf(cmd, node, "%u", &ctx->globalconf->max_delegations); -} - -static int on_config_handshake_timeout(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - return config_timeout(cmd, node, &ctx->globalconf->handshake_timeout); -} - -static int on_config_http1_request_timeout(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - return config_timeout(cmd, node, &ctx->globalconf->http1.req_timeout); -} - -static int on_config_http1_upgrade_to_http2(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); - if (ret == -1) - return -1; - ctx->globalconf->http1.upgrade_to_http2 = (int)ret; - return 0; -} - -static int on_config_http2_idle_timeout(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - return config_timeout(cmd, node, &ctx->globalconf->http2.idle_timeout); -} - -static int on_config_http2_graceful_shutdown_timeout(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - return config_timeout(cmd, node, &ctx->globalconf->http2.graceful_shutdown_timeout); -} - -static int on_config_http2_max_concurrent_requests_per_connection(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, - yoml_t *node) -{ - return h2o_configurator_scanf(cmd, node, "%zu", &ctx->globalconf->http2.max_concurrent_requests_per_connection); -} - -static int on_config_http2_latency_optimization_min_rtt(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, - yoml_t *node) -{ - return h2o_configurator_scanf(cmd, node, "%u", &ctx->globalconf->http2.latency_optimization.min_rtt); -} - -static int on_config_http2_latency_optimization_max_additional_delay(h2o_configurator_command_t *cmd, - h2o_configurator_context_t *ctx, yoml_t *node) -{ - double ratio; - if (h2o_configurator_scanf(cmd, node, "%lf", &ratio) != 0) - return -1; - if (!(0.0 < ratio)) { - h2o_configurator_errprintf(cmd, node, "ratio must be a positive number"); - return -1; - } - ctx->globalconf->http2.latency_optimization.max_additional_delay = 100 * ratio; - return 0; -} - -static int on_config_http2_latency_optimization_max_cwnd(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, - yoml_t *node) -{ - return h2o_configurator_scanf(cmd, node, "%u", &ctx->globalconf->http2.latency_optimization.max_cwnd); -} - -static int on_config_http2_reprioritize_blocking_assets(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, - yoml_t *node) -{ - struct st_core_configurator_t *self = (void *)cmd->configurator; - ssize_t on; - - if ((on = h2o_configurator_get_one_of(cmd, node, "OFF,ON")) == -1) - return -1; - self->vars->http2.reprioritize_blocking_assets = (int)on; - - return 0; -} - -static int on_config_http2_push_preload(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_core_configurator_t *self = (void *)cmd->configurator; - ssize_t on; - - if ((on = h2o_configurator_get_one_of(cmd, node, "OFF,ON")) == -1) - return -1; - self->vars->http2.push_preload = (int)on; - - return 0; -} - -static int on_config_http2_casper(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - static const h2o_casper_conf_t defaults = { - 13, /* casper_bits: default (2^13 ~= 100 assets * 1/0.01 collision probability) */ - 0 /* track blocking assets only */ - }; - - struct st_core_configurator_t *self = (void *)cmd->configurator; - - switch (node->type) { - case YOML_TYPE_SCALAR: - if (strcasecmp(node->data.scalar, "OFF") == 0) { - self->vars->http2.casper = (h2o_casper_conf_t){0}; - } else if (strcasecmp(node->data.scalar, "ON") == 0) { - self->vars->http2.casper = defaults; - } - break; - case YOML_TYPE_MAPPING: { - /* set to default */ - self->vars->http2.casper = defaults; - /* override the attributes defined */ - yoml_t *t; - if ((t = yoml_get(node, "capacity-bits")) != NULL) { - if (!(t->type == YOML_TYPE_SCALAR && sscanf(t->data.scalar, "%u", &self->vars->http2.casper.capacity_bits) == 1 && - self->vars->http2.casper.capacity_bits < 16)) { - h2o_configurator_errprintf(cmd, t, "value of `capacity-bits` must be an integer between 0 to 15"); - return -1; - } - } - if ((t = yoml_get(node, "tracking-types")) != NULL) { - if (t->type == YOML_TYPE_SCALAR && strcasecmp(t->data.scalar, "blocking-assets") == 0) { - self->vars->http2.casper.track_all_types = 0; - } else if (t->type == YOML_TYPE_SCALAR && strcasecmp(t->data.scalar, "all") == 0) { - self->vars->http2.casper.track_all_types = 1; - } else { - h2o_configurator_errprintf(cmd, t, "value of `tracking-types` must be either of: `blocking-assets` or `all`"); - return -1; - } - } - } break; - default: - h2o_configurator_errprintf(cmd, node, "value must be `OFF`,`ON` or a mapping containing the necessary attributes"); - return -1; - } - - return 0; -} - -static int assert_is_mimetype(h2o_configurator_command_t *cmd, yoml_t *node) -{ - if (node->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, node, "expected a scalar (mime-type)"); - return -1; - } - if (strchr(node->data.scalar, '/') == NULL) { - h2o_configurator_errprintf(cmd, node, "the string \"%s\" does not look like a mime-type", node->data.scalar); - return -1; - } - return 0; -} - -static int assert_is_extension(h2o_configurator_command_t *cmd, yoml_t *node) -{ - if (node->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, node, "expected a scalar (extension)"); - return -1; - } - if (node->data.scalar[0] != '.') { - h2o_configurator_errprintf(cmd, node, "given extension \"%s\" does not start with a \".\"", node->data.scalar); - return -1; - } - return 0; -} - -static int set_mimetypes(h2o_configurator_command_t *cmd, h2o_mimemap_t *mimemap, yoml_t *node) -{ - size_t i, j; - - assert(node->type == YOML_TYPE_MAPPING); - - for (i = 0; i != node->data.mapping.size; ++i) { - yoml_t *key = node->data.mapping.elements[i].key; - yoml_t *value = node->data.mapping.elements[i].value; - if (assert_is_mimetype(cmd, key) != 0) - return -1; - switch (value->type) { - case YOML_TYPE_SCALAR: - if (assert_is_extension(cmd, value) != 0) - return -1; - h2o_mimemap_define_mimetype(mimemap, value->data.scalar + 1, key->data.scalar, NULL); - break; - case YOML_TYPE_SEQUENCE: - for (j = 0; j != value->data.sequence.size; ++j) { - yoml_t *ext_node = value->data.sequence.elements[j]; - if (assert_is_extension(cmd, ext_node) != 0) - return -1; - h2o_mimemap_define_mimetype(mimemap, ext_node->data.scalar + 1, key->data.scalar, NULL); - } - break; - case YOML_TYPE_MAPPING: { - yoml_t *t; - h2o_mime_attributes_t attr; - h2o_mimemap_get_default_attributes(key->data.scalar, &attr); - if ((t = yoml_get(value, "is_compressible")) != NULL) { - if (t->type == YOML_TYPE_SCALAR && strcasecmp(t->data.scalar, "YES") == 0) { - attr.is_compressible = 1; - } else if (t->type == YOML_TYPE_SCALAR && strcasecmp(t->data.scalar, "NO") == 0) { - attr.is_compressible = 0; - } else { - h2o_configurator_errprintf(cmd, t, "`is_compressible` attribute must be either of: `YES` or `NO`"); - return -1; - } - } - if ((t = yoml_get(value, "priority")) != NULL) { - if (t->type == YOML_TYPE_SCALAR && strcasecmp(t->data.scalar, "normal") == 0) { - attr.priority = H2O_MIME_ATTRIBUTE_PRIORITY_NORMAL; - } else if (t->type == YOML_TYPE_SCALAR && strcasecmp(t->data.scalar, "highest") == 0) { - attr.priority = H2O_MIME_ATTRIBUTE_PRIORITY_HIGHEST; - } else { - h2o_configurator_errprintf(cmd, t, "`priority` attribute must be either of: `normal` or `highest`"); - return -1; - } - } - if ((t = yoml_get(value, "extensions")) == NULL) { - h2o_configurator_errprintf(cmd, value, "cannot find mandatory attribute `extensions`"); - return -1; - } - if (t->type != YOML_TYPE_SEQUENCE) { - h2o_configurator_errprintf(cmd, t, "`extensions` attribute must be a sequence of scalars"); - return -1; - } - for (j = 0; j != t->data.sequence.size; ++j) { - yoml_t *ext_node = t->data.sequence.elements[j]; - if (assert_is_extension(cmd, ext_node) != 0) - return -1; - h2o_mimemap_define_mimetype(mimemap, ext_node->data.scalar + 1, key->data.scalar, &attr); - } - } break; - default: - fprintf(stderr, "logic flaw at %s:%d\n", __FILE__, __LINE__); - abort(); - } - } - - return 0; -} - -static int on_config_mime_settypes(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - h2o_mimemap_t *newmap = h2o_mimemap_create(); - h2o_mimemap_clear_types(newmap); - h2o_mimemap_set_default_type(newmap, h2o_mimemap_get_default_type(*ctx->mimemap)->data.mimetype.base, NULL); - if (set_mimetypes(cmd, newmap, node) != 0) { - h2o_mem_release_shared(newmap); - return -1; - } - - h2o_mem_release_shared(*ctx->mimemap); - *ctx->mimemap = newmap; - return 0; -} - -static void clone_mimemap_if_clean(h2o_configurator_context_t *ctx) -{ - if (ctx->parent == NULL) - return; - if (*ctx->mimemap != *ctx->parent->mimemap) - return; - h2o_mem_release_shared(*ctx->mimemap); - /* even after release, ctx->mimemap is still retained by the parent and therefore we can use it as the argument to clone */ - *ctx->mimemap = h2o_mimemap_clone(*ctx->mimemap); -} - -static int on_config_mime_addtypes(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - clone_mimemap_if_clean(ctx); - return set_mimetypes(cmd, *ctx->mimemap, node); -} - -static int on_config_mime_removetypes(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - size_t i; - - clone_mimemap_if_clean(ctx); - for (i = 0; i != node->data.sequence.size; ++i) { - yoml_t *ext_node = node->data.sequence.elements[i]; - if (assert_is_extension(cmd, ext_node) != 0) - return -1; - h2o_mimemap_remove_type(*ctx->mimemap, ext_node->data.scalar + 1); - } - - return 0; -} - -static int on_config_mime_setdefaulttype(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - if (assert_is_mimetype(cmd, node) != 0) - return -1; - - clone_mimemap_if_clean(ctx); - h2o_mimemap_set_default_type(*ctx->mimemap, node->data.scalar, NULL); - - return 0; -} - -static int on_config_custom_handler(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - static const char *ignore_commands[] = {"extension", NULL}; - yoml_t *ext_node; - const char **exts; - h2o_mimemap_type_t *type = NULL; - - if (node->type != YOML_TYPE_MAPPING) { - h2o_configurator_errprintf(cmd, node, "argument must be a MAPPING"); - return -1; - } - if ((ext_node = yoml_get(node, "extension")) == NULL) { - h2o_configurator_errprintf(cmd, node, "mandatory key `extension` is missing"); - return -1; - } - - /* create dynamic type */ - switch (ext_node->type) { - case YOML_TYPE_SCALAR: - if (assert_is_extension(cmd, ext_node) != 0) - return -1; - exts = alloca(2 * sizeof(*exts)); - exts[0] = ext_node->data.scalar + 1; - exts[1] = NULL; - break; - case YOML_TYPE_SEQUENCE: { - exts = alloca((ext_node->data.sequence.size + 1) * sizeof(*exts)); - size_t i; - for (i = 0; i != ext_node->data.sequence.size; ++i) { - yoml_t *n = ext_node->data.sequence.elements[i]; - if (assert_is_extension(cmd, n) != 0) - return -1; - exts[i] = n->data.scalar + 1; - } - exts[i] = NULL; - } break; - default: - h2o_configurator_errprintf(cmd, ext_node, "`extensions` must be a scalar or sequence of scalar"); - return -1; - } - clone_mimemap_if_clean(ctx); - type = h2o_mimemap_define_dynamic(*ctx->mimemap, exts, ctx->globalconf); - - /* apply the configuration commands */ - h2o_configurator_context_t *ext_ctx = create_context(ctx, 1); - ext_ctx->pathconf = &type->data.dynamic.pathconf; - ext_ctx->mimemap = NULL; - int cmd_ret = h2o_configurator_apply_commands(ext_ctx, node, H2O_CONFIGURATOR_FLAG_EXTENSION, ignore_commands); - destroy_context(ext_ctx); - if (cmd_ret != 0) - return cmd_ret; - switch (type->data.dynamic.pathconf.handlers.size) { - case 1: - break; - case 0: - h2o_configurator_errprintf(cmd, node, "no handler declared for given extension"); - return -1; - default: - h2o_configurator_errprintf(cmd, node, "cannot assign more than one handler for given extension"); - return -1; - } - - return 0; -} - -static void inherit_env_if_necessary(h2o_configurator_context_t *ctx) -{ - if (ctx->env == (ctx->parent != NULL ? ctx->parent->env : NULL)) - ctx->env = h2o_config_create_envconf(ctx->env); -} - -static int on_config_setenv(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - size_t i; - - inherit_env_if_necessary(ctx); - - for (i = 0; i != node->data.mapping.size; ++i) { - yoml_t *key = node->data.mapping.elements[i].key, *value = node->data.mapping.elements[i].value; - if (key->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, key, "key must be a scalar"); - return -1; - } - if (value->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, value, "value must be a scalar"); - return -1; - } - h2o_config_setenv(ctx->env, key->data.scalar, value->data.scalar); - } - - return 0; -} - -static int on_config_unsetenv(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - inherit_env_if_necessary(ctx); - - switch (node->type) { - case YOML_TYPE_SCALAR: - h2o_config_unsetenv(ctx->env, node->data.scalar); - break; - case YOML_TYPE_SEQUENCE: { - size_t i; - for (i = 0; i != node->data.sequence.size; ++i) { - yoml_t *element = node->data.sequence.elements[i]; - if (element->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, element, "element of a sequence passed to unsetenv must be a scalar"); - return -1; - } - h2o_config_unsetenv(ctx->env, element->data.scalar); - } - } break; - default: - h2o_configurator_errprintf(cmd, node, "argument to unsetenv must be either a scalar or a sequence"); - return -1; - } - - return 0; -} - -static int on_config_server_name(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - ctx->globalconf->server_name = h2o_strdup(NULL, node->data.scalar, SIZE_MAX); - return 0; -} - -static int on_config_send_server_name(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - switch(h2o_configurator_get_one_of(cmd, node, "OFF,ON,preserve")) { - case 0: /* off */ - ctx->globalconf->server_name = h2o_iovec_init(H2O_STRLIT("")); - break; - case 1: /* on */ - break; - case 2: /* preserve */ - ctx->globalconf->server_name = h2o_iovec_init(H2O_STRLIT("")); - ctx->globalconf->proxy.preserve_server_header = 1; - break; - default: - return -1; - } - return 0; -} - -static int on_config_error_log_emit_request_errors(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_core_configurator_t *self = (void *)cmd->configurator; - ssize_t on; - - if ((on = h2o_configurator_get_one_of(cmd, node, "OFF,ON")) == -1) - return -1; - - self->vars->error_log.emit_request_errors = (int)on; - return 0; -} - -void h2o_configurator__init_core(h2o_globalconf_t *conf) -{ - /* check if already initialized */ - if (h2o_configurator_get_command(conf, "files") != NULL) - return; - - { /* `hosts` and `paths` */ - h2o_configurator_t *c = h2o_configurator_create(conf, sizeof(*c)); - h2o_configurator_define_command(c, "hosts", H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_MAPPING | - H2O_CONFIGURATOR_FLAG_DEFERRED, - on_config_hosts); - h2o_configurator_define_command(c, "paths", H2O_CONFIGURATOR_FLAG_HOST | H2O_CONFIGURATOR_FLAG_EXPECT_MAPPING | - H2O_CONFIGURATOR_FLAG_DEFERRED, - on_config_paths); - }; - - { /* setup global configurators */ - struct st_core_configurator_t *c = (void *)h2o_configurator_create(conf, sizeof(*c)); - c->super.enter = on_core_enter; - c->super.exit = on_core_exit; - c->vars = c->_vars_stack; - c->vars->http2.reprioritize_blocking_assets = 1; /* defaults to ON */ - c->vars->http2.push_preload = 1; /* defaults to ON */ - c->vars->error_log.emit_request_errors = 1; /* defaults to ON */ - h2o_configurator_define_command(&c->super, "limit-request-body", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_limit_request_body); - h2o_configurator_define_command(&c->super, "max-delegations", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_max_delegations); - h2o_configurator_define_command(&c->super, "handshake-timeout", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_handshake_timeout); - h2o_configurator_define_command(&c->super, "http1-request-timeout", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_http1_request_timeout); - h2o_configurator_define_command(&c->super, "http1-upgrade-to-http2", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_http1_upgrade_to_http2); - h2o_configurator_define_command(&c->super, "http2-idle-timeout", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_http2_idle_timeout); - h2o_configurator_define_command(&c->super, "http2-graceful-shutdown-timeout", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_http2_graceful_shutdown_timeout); - h2o_configurator_define_command(&c->super, "http2-max-concurrent-requests-per-connection", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_http2_max_concurrent_requests_per_connection); - h2o_configurator_define_command(&c->super, "http2-latency-optimization-min-rtt", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_http2_latency_optimization_min_rtt); - h2o_configurator_define_command(&c->super, "http2-latency-optimization-max-additional-delay", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_http2_latency_optimization_max_additional_delay); - h2o_configurator_define_command(&c->super, "http2-latency-optimization-max-cwnd", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_http2_latency_optimization_max_cwnd); - h2o_configurator_define_command(&c->super, "http2-reprioritize-blocking-assets", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_HOST | - H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_http2_reprioritize_blocking_assets); - h2o_configurator_define_command(&c->super, "http2-push-preload", H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_HOST | - H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_http2_push_preload); - h2o_configurator_define_command(&c->super, "http2-casper", H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_HOST, - on_config_http2_casper); - h2o_configurator_define_command(&c->super, "file.mime.settypes", - (H2O_CONFIGURATOR_FLAG_ALL_LEVELS & ~H2O_CONFIGURATOR_FLAG_EXTENSION) | - H2O_CONFIGURATOR_FLAG_EXPECT_MAPPING, - on_config_mime_settypes); - h2o_configurator_define_command(&c->super, "file.mime.addtypes", - (H2O_CONFIGURATOR_FLAG_ALL_LEVELS & ~H2O_CONFIGURATOR_FLAG_EXTENSION) | - H2O_CONFIGURATOR_FLAG_EXPECT_MAPPING, - on_config_mime_addtypes); - h2o_configurator_define_command(&c->super, "file.mime.removetypes", - (H2O_CONFIGURATOR_FLAG_ALL_LEVELS & ~H2O_CONFIGURATOR_FLAG_EXTENSION) | - H2O_CONFIGURATOR_FLAG_EXPECT_SEQUENCE, - on_config_mime_removetypes); - h2o_configurator_define_command(&c->super, "file.mime.setdefaulttype", - (H2O_CONFIGURATOR_FLAG_ALL_LEVELS & ~H2O_CONFIGURATOR_FLAG_EXTENSION) | - H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_mime_setdefaulttype); - h2o_configurator_define_command(&c->super, "file.custom-handler", - (H2O_CONFIGURATOR_FLAG_ALL_LEVELS & ~H2O_CONFIGURATOR_FLAG_EXTENSION) | - H2O_CONFIGURATOR_FLAG_SEMI_DEFERRED, - on_config_custom_handler); - h2o_configurator_define_command(&c->super, "setenv", - H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_MAPPING, on_config_setenv); - h2o_configurator_define_command(&c->super, "unsetenv", H2O_CONFIGURATOR_FLAG_ALL_LEVELS, on_config_unsetenv); - h2o_configurator_define_command(&c->super, "server-name", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, on_config_server_name); - h2o_configurator_define_command(&c->super, "send-server-name", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR | - H2O_CONFIGURATOR_FLAG_DEFERRED, - on_config_send_server_name); - h2o_configurator_define_command(&c->super, "error-log.emit-request-errors", - H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_error_log_emit_request_errors); - } -} - -void h2o_configurator__dispose_configurators(h2o_globalconf_t *conf) -{ - while (!h2o_linklist_is_empty(&conf->configurators)) { - h2o_configurator_t *c = H2O_STRUCT_FROM_MEMBER(h2o_configurator_t, _link, conf->configurators.next); - h2o_linklist_unlink(&c->_link); - if (c->dispose != NULL) - c->dispose(c); - destroy_configurator(c); - } -} - -h2o_configurator_t *h2o_configurator_create(h2o_globalconf_t *conf, size_t sz) -{ - h2o_configurator_t *c; - - assert(sz >= sizeof(*c)); - - c = h2o_mem_alloc(sz); - memset(c, 0, sz); - h2o_linklist_insert(&conf->configurators, &c->_link); - - return c; -} - -void h2o_configurator_define_command(h2o_configurator_t *configurator, const char *name, int flags, h2o_configurator_command_cb cb) -{ - h2o_configurator_command_t *cmd; - - h2o_vector_reserve(NULL, &configurator->commands, configurator->commands.size + 1); - cmd = configurator->commands.entries + configurator->commands.size++; - cmd->configurator = configurator; - cmd->flags = flags; - cmd->name = name; - cmd->cb = cb; -} - -h2o_configurator_command_t *h2o_configurator_get_command(h2o_globalconf_t *conf, const char *name) -{ - h2o_linklist_t *node; - size_t i; - - for (node = conf->configurators.next; node != &conf->configurators; node = node->next) { - h2o_configurator_t *configurator = H2O_STRUCT_FROM_MEMBER(h2o_configurator_t, _link, node); - for (i = 0; i != configurator->commands.size; ++i) { - h2o_configurator_command_t *cmd = configurator->commands.entries + i; - if (strcmp(cmd->name, name) == 0) { - return cmd; - } - } - } - - return NULL; -} - -int h2o_configurator_apply(h2o_globalconf_t *config, yoml_t *node, int dry_run) -{ - h2o_configurator_context_t *ctx = create_context(NULL, 0); - ctx->globalconf = config; - ctx->mimemap = &ctx->globalconf->mimemap; - ctx->dry_run = dry_run; - int cmd_ret = h2o_configurator_apply_commands(ctx, node, H2O_CONFIGURATOR_FLAG_GLOBAL, NULL); - destroy_context(ctx); - - if (cmd_ret != 0) - return cmd_ret; - if (config->hosts[0] == NULL) { - h2o_configurator_errprintf(NULL, node, "mandatory configuration directive `hosts` is missing"); - return -1; - } - return 0; -} - -void h2o_configurator_errprintf(h2o_configurator_command_t *cmd, yoml_t *node, const char *reason, ...) -{ - va_list args; - - fprintf(stderr, "[%s:%zu] ", node->filename ? node->filename : "-", node->line + 1); - if (cmd != NULL) - fprintf(stderr, "in command %s, ", cmd->name); - va_start(args, reason); - vfprintf(stderr, reason, args); - va_end(args); - fputc('\n', stderr); -} - -int h2o_configurator_scanf(h2o_configurator_command_t *cmd, yoml_t *node, const char *fmt, ...) -{ - va_list args; - int sscan_ret; - - if (node->type != YOML_TYPE_SCALAR) - goto Error; - va_start(args, fmt); - sscan_ret = vsscanf(node->data.scalar, fmt, args); - va_end(args); - if (sscan_ret != 1) - goto Error; - - return 0; -Error: - h2o_configurator_errprintf(cmd, node, "argument must match the format: %s", fmt); - return -1; -} - -ssize_t h2o_configurator_get_one_of(h2o_configurator_command_t *cmd, yoml_t *node, const char *candidates) -{ - const char *config_str, *cand_str; - ssize_t config_str_len, cand_index; - - if (node->type != YOML_TYPE_SCALAR) - goto Error; - - config_str = node->data.scalar; - config_str_len = strlen(config_str); - - cand_str = candidates; - for (cand_index = 0;; ++cand_index) { - if (strncasecmp(cand_str, config_str, config_str_len) == 0 && - (cand_str[config_str_len] == '\0' || cand_str[config_str_len] == ',')) { - /* found */ - return cand_index; - } - cand_str = strchr(cand_str, ','); - if (cand_str == NULL) - goto Error; - cand_str += 1; /* skip ',' */ - } -/* not reached */ - -Error: - h2o_configurator_errprintf(cmd, node, "argument must be one of: %s", candidates); - return -1; -} - -char *h2o_configurator_get_cmd_path(const char *cmd) -{ - char *root, *cmd_fullpath; - - /* just return the cmd (being strdup'ed) in case we do not need to prefix the value */ - if (cmd[0] == '/' || strchr(cmd, '/') == NULL) - goto ReturnOrig; - - /* obtain root */ - if ((root = getenv("H2O_ROOT")) == NULL) { - root = H2O_TO_STR(H2O_ROOT); - } - - /* build full-path and return */ - cmd_fullpath = h2o_mem_alloc(strlen(root) + strlen(cmd) + 2); - sprintf(cmd_fullpath, "%s/%s", root, cmd); - return cmd_fullpath; - -ReturnOrig: - return h2o_strdup(NULL, cmd, SIZE_MAX).base; -} diff --git a/web/server/h2o/libh2o/lib/core/context.c b/web/server/h2o/libh2o/lib/core/context.c deleted file mode 100644 index 8d1101381..000000000 --- a/web/server/h2o/libh2o/lib/core/context.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2014 DeNA Co., Ltd. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#include <stddef.h> -#include <stdlib.h> -#include <sys/time.h> -#include "h2o.h" -#include "h2o/memcached.h" - -void h2o_context_init_pathconf_context(h2o_context_t *ctx, h2o_pathconf_t *pathconf) -{ - /* add pathconf to the inited list (or return if already inited) */ - size_t i; - for (i = 0; i != ctx->_pathconfs_inited.size; ++i) - if (ctx->_pathconfs_inited.entries[i] == pathconf) - return; - h2o_vector_reserve(NULL, &ctx->_pathconfs_inited, ctx->_pathconfs_inited.size + 1); - ctx->_pathconfs_inited.entries[ctx->_pathconfs_inited.size++] = pathconf; - -#define DOIT(type, list) \ - do { \ - size_t i; \ - for (i = 0; i != pathconf->list.size; ++i) { \ - type *o = pathconf->list.entries[i]; \ - if (o->on_context_init != NULL) \ - o->on_context_init(o, ctx); \ - } \ - } while (0) - - DOIT(h2o_handler_t, handlers); - DOIT(h2o_filter_t, filters); - DOIT(h2o_logger_t, loggers); - -#undef DOIT -} - -void h2o_context_dispose_pathconf_context(h2o_context_t *ctx, h2o_pathconf_t *pathconf) -{ - /* nullify pathconf in the inited list (or return if already disposed) */ - size_t i; - for (i = 0; i != ctx->_pathconfs_inited.size; ++i) - if (ctx->_pathconfs_inited.entries[i] == pathconf) - break; - if (i == ctx->_pathconfs_inited.size) - return; - ctx->_pathconfs_inited.entries[i] = NULL; - -#define DOIT(type, list) \ - do { \ - size_t i; \ - for (i = 0; i != pathconf->list.size; ++i) { \ - type *o = pathconf->list.entries[i]; \ - if (o->on_context_dispose != NULL) \ - o->on_context_dispose(o, ctx); \ - } \ - } while (0) - - DOIT(h2o_handler_t, handlers); - DOIT(h2o_filter_t, filters); - DOIT(h2o_logger_t, loggers); - -#undef DOIT -} - -void h2o_context_init(h2o_context_t *ctx, h2o_loop_t *loop, h2o_globalconf_t *config) -{ - size_t i, j; - - assert(config->hosts[0] != NULL); - - memset(ctx, 0, sizeof(*ctx)); - ctx->loop = loop; - ctx->globalconf = config; - h2o_timeout_init(ctx->loop, &ctx->zero_timeout, 0); - h2o_timeout_init(ctx->loop, &ctx->one_sec_timeout, 1000); - h2o_timeout_init(ctx->loop, &ctx->hundred_ms_timeout, 100); - ctx->queue = h2o_multithread_create_queue(loop); - h2o_multithread_register_receiver(ctx->queue, &ctx->receivers.hostinfo_getaddr, h2o_hostinfo_getaddr_receiver); - ctx->filecache = h2o_filecache_create(config->filecache.capacity); - - h2o_timeout_init(ctx->loop, &ctx->handshake_timeout, config->handshake_timeout); - h2o_timeout_init(ctx->loop, &ctx->http1.req_timeout, config->http1.req_timeout); - h2o_linklist_init_anchor(&ctx->http1._conns); - h2o_timeout_init(ctx->loop, &ctx->http2.idle_timeout, config->http2.idle_timeout); - h2o_timeout_init(ctx->loop, &ctx->http2.graceful_shutdown_timeout, config->http2.graceful_shutdown_timeout); - h2o_linklist_init_anchor(&ctx->http2._conns); - ctx->proxy.client_ctx.loop = loop; - h2o_timeout_init(ctx->loop, &ctx->proxy.io_timeout, config->proxy.io_timeout); - ctx->proxy.client_ctx.getaddr_receiver = &ctx->receivers.hostinfo_getaddr; - ctx->proxy.client_ctx.io_timeout = &ctx->proxy.io_timeout; - ctx->proxy.client_ctx.ssl_ctx = config->proxy.ssl_ctx; - - ctx->_module_configs = h2o_mem_alloc(sizeof(*ctx->_module_configs) * config->_num_config_slots); - memset(ctx->_module_configs, 0, sizeof(*ctx->_module_configs) * config->_num_config_slots); - - static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - pthread_mutex_lock(&mutex); - for (i = 0; config->hosts[i] != NULL; ++i) { - h2o_hostconf_t *hostconf = config->hosts[i]; - for (j = 0; j != hostconf->paths.size; ++j) { - h2o_pathconf_t *pathconf = hostconf->paths.entries + j; - h2o_context_init_pathconf_context(ctx, pathconf); - } - h2o_context_init_pathconf_context(ctx, &hostconf->fallback_path); - } - pthread_mutex_unlock(&mutex); -} - -void h2o_context_dispose(h2o_context_t *ctx) -{ - h2o_globalconf_t *config = ctx->globalconf; - size_t i, j; - - for (i = 0; config->hosts[i] != NULL; ++i) { - h2o_hostconf_t *hostconf = config->hosts[i]; - for (j = 0; j != hostconf->paths.size; ++j) { - h2o_pathconf_t *pathconf = hostconf->paths.entries + j; - h2o_context_dispose_pathconf_context(ctx, pathconf); - } - h2o_context_dispose_pathconf_context(ctx, &hostconf->fallback_path); - } - free(ctx->_pathconfs_inited.entries); - free(ctx->_module_configs); - h2o_timeout_dispose(ctx->loop, &ctx->zero_timeout); - h2o_timeout_dispose(ctx->loop, &ctx->one_sec_timeout); - h2o_timeout_dispose(ctx->loop, &ctx->hundred_ms_timeout); - h2o_timeout_dispose(ctx->loop, &ctx->handshake_timeout); - h2o_timeout_dispose(ctx->loop, &ctx->http1.req_timeout); - h2o_timeout_dispose(ctx->loop, &ctx->http2.idle_timeout); - h2o_timeout_dispose(ctx->loop, &ctx->http2.graceful_shutdown_timeout); - h2o_timeout_dispose(ctx->loop, &ctx->proxy.io_timeout); - /* what should we do here? assert(!h2o_linklist_is_empty(&ctx->http2._conns); */ - - h2o_filecache_destroy(ctx->filecache); - ctx->filecache = NULL; - - /* clear storage */ - for (i = 0; i != ctx->storage.size; ++i) { - h2o_context_storage_item_t *item = ctx->storage.entries + i; - if (item->dispose != NULL) { - item->dispose(item->data); - } - } - free(ctx->storage.entries); - - /* TODO assert that the all the getaddrinfo threads are idle */ - h2o_multithread_unregister_receiver(ctx->queue, &ctx->receivers.hostinfo_getaddr); - h2o_multithread_destroy_queue(ctx->queue); - - if (ctx->_timestamp_cache.value != NULL) - h2o_mem_release_shared(ctx->_timestamp_cache.value); - -#if H2O_USE_LIBUV - /* make sure the handles released by h2o_timeout_dispose get freed */ - uv_run(ctx->loop, UV_RUN_NOWAIT); -#endif -} - -void h2o_context_request_shutdown(h2o_context_t *ctx) -{ - ctx->shutdown_requested = 1; - if (ctx->globalconf->http1.callbacks.request_shutdown != NULL) - ctx->globalconf->http1.callbacks.request_shutdown(ctx); - if (ctx->globalconf->http2.callbacks.request_shutdown != NULL) - ctx->globalconf->http2.callbacks.request_shutdown(ctx); -} - -void h2o_context_update_timestamp_cache(h2o_context_t *ctx) -{ - time_t prev_sec = ctx->_timestamp_cache.tv_at.tv_sec; - ctx->_timestamp_cache.uv_now_at = h2o_now(ctx->loop); - gettimeofday(&ctx->_timestamp_cache.tv_at, NULL); - if (ctx->_timestamp_cache.tv_at.tv_sec != prev_sec) { - struct tm gmt; - /* update the string cache */ - if (ctx->_timestamp_cache.value != NULL) - h2o_mem_release_shared(ctx->_timestamp_cache.value); - ctx->_timestamp_cache.value = h2o_mem_alloc_shared(NULL, sizeof(h2o_timestamp_string_t), NULL); - gmtime_r(&ctx->_timestamp_cache.tv_at.tv_sec, &gmt); - h2o_time2str_rfc1123(ctx->_timestamp_cache.value->rfc1123, &gmt); - h2o_time2str_log(ctx->_timestamp_cache.value->log, ctx->_timestamp_cache.tv_at.tv_sec); - } -} diff --git a/web/server/h2o/libh2o/lib/core/headers.c b/web/server/h2o/libh2o/lib/core/headers.c deleted file mode 100644 index d31183623..000000000 --- a/web/server/h2o/libh2o/lib/core/headers.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2014 DeNA Co., Ltd. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#include <stddef.h> -#include <stdio.h> -#include "h2o.h" - -static void 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_t *slot; - - h2o_vector_reserve(pool, headers, headers->size + 1); - slot = headers->entries + headers->size++; - - slot->name = name; - slot->value.base = (char *)value; - slot->value.len = value_len; - slot->orig_name = orig_name ? h2o_strdup(pool, orig_name, name->len).base : NULL; -} - -ssize_t h2o_find_header(const h2o_headers_t *headers, const h2o_token_t *token, ssize_t cursor) -{ - for (++cursor; cursor < headers->size; ++cursor) { - if (headers->entries[cursor].name == &token->buf) { - return cursor; - } - } - return -1; -} - -ssize_t h2o_find_header_by_str(const h2o_headers_t *headers, const char *name, size_t name_len, ssize_t cursor) -{ - for (++cursor; cursor < headers->size; ++cursor) { - h2o_header_t *t = headers->entries + cursor; - if (h2o_memis(t->name->base, t->name->len, name, name_len)) { - return cursor; - } - } - return -1; -} - -void 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) -{ - add_header(pool, headers, (h2o_iovec_t *)&token->buf, orig_name, value, value_len); -} - -void h2o_add_header_by_str(h2o_mem_pool_t *pool, h2o_headers_t *headers, const char *name, size_t name_len, int maybe_token, - const char *orig_name, const char *value, size_t value_len) -{ - h2o_iovec_t *name_buf; - - if (maybe_token) { - const h2o_token_t *token = h2o_lookup_token(name, name_len); - if (token != NULL) { - add_header(pool, headers, (h2o_iovec_t *)token, orig_name, value, value_len); - return; - } - } - name_buf = h2o_mem_alloc_pool(pool, sizeof(h2o_iovec_t)); - name_buf->base = (char *)name; - name_buf->len = name_len; - add_header(pool, headers, name_buf, orig_name, value, value_len); -} - -void 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) -{ - ssize_t cursor = h2o_find_header(headers, token, -1); - if (cursor != -1) { - if (overwrite_if_exists) { - h2o_iovec_t *slot = &headers->entries[cursor].value; - slot->base = (char *)value; - slot->len = value_len; - } - } else { - h2o_add_header(pool, headers, token, NULL, value, value_len); - } -} - -void h2o_set_header_by_str(h2o_mem_pool_t *pool, h2o_headers_t *headers, const char *name, size_t name_len, int maybe_token, - const char *value, size_t value_len, int overwrite_if_exists) -{ - ssize_t cursor; - - if (maybe_token) { - const h2o_token_t *token = h2o_lookup_token(name, name_len); - if (token != NULL) { - h2o_set_header(pool, headers, token, value, value_len, overwrite_if_exists); - return; - } - } - - cursor = h2o_find_header_by_str(headers, name, name_len, -1); - if (cursor != -1) { - if (overwrite_if_exists) { - h2o_iovec_t *slot = &headers->entries[cursor].value; - slot->base = (char *)value; - slot->len = value_len; - } - } else { - h2o_iovec_t *name_buf = h2o_mem_alloc_pool(pool, sizeof(h2o_iovec_t)); - name_buf->base = (char *)name; - name_buf->len = name_len; - add_header(pool, headers, name_buf, NULL, value, value_len); - } -} - -void 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) -{ - h2o_header_t *dest = NULL; - size_t i; - for (i = 0; i != headers->size; ++i) { - if (headers->entries[i].name == &token->buf) { - if (h2o_contains_token(headers->entries[i].value.base, headers->entries[i].value.len, value, value_len, ',')) - return; - dest = headers->entries + i; - } - } - if (dest != NULL) { - dest->value = h2o_concat(pool, dest->value, h2o_iovec_init(H2O_STRLIT(", ")), h2o_iovec_init(value, value_len)); - } else { - h2o_add_header(pool, headers, token, NULL, value, value_len); - } -} - -ssize_t h2o_delete_header(h2o_headers_t *headers, ssize_t cursor) -{ - assert(cursor != -1); - - --headers->size; - memmove(headers->entries + cursor, headers->entries + cursor + 1, sizeof(h2o_header_t) * (headers->size - cursor)); - - return cursor; -} diff --git a/web/server/h2o/libh2o/lib/core/logconf.c b/web/server/h2o/libh2o/lib/core/logconf.c deleted file mode 100644 index 4d79736cc..000000000 --- a/web/server/h2o/libh2o/lib/core/logconf.c +++ /dev/null @@ -1,793 +0,0 @@ -/* - * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include "h2o.h" - -enum { - ELEMENT_TYPE_EMPTY, /* empty element (with suffix only) */ - ELEMENT_TYPE_LOCAL_ADDR, /* %A */ - ELEMENT_TYPE_BYTES_SENT, /* %b */ - ELEMENT_TYPE_PROTOCOL, /* %H */ - ELEMENT_TYPE_REMOTE_ADDR, /* %h */ - ELEMENT_TYPE_LOGNAME, /* %l */ - ELEMENT_TYPE_METHOD, /* %m */ - ELEMENT_TYPE_LOCAL_PORT, /* %p, %{local}p */ - ELEMENT_TYPE_REMOTE_PORT, /* %{remote}p */ - ELEMENT_TYPE_ENV_VAR, /* %{..}e */ - ELEMENT_TYPE_QUERY, /* %q */ - ELEMENT_TYPE_REQUEST_LINE, /* %r */ - ELEMENT_TYPE_STATUS, /* %s */ - ELEMENT_TYPE_TIMESTAMP, /* %t */ - ELEMENT_TYPE_TIMESTAMP_STRFTIME, /* %{...}t */ - ELEMENT_TYPE_TIMESTAMP_SEC_SINCE_EPOCH, /* %{sec}t */ - ELEMENT_TYPE_TIMESTAMP_MSEC_SINCE_EPOCH, /* %{msec}t */ - ELEMENT_TYPE_TIMESTAMP_USEC_SINCE_EPOCH, /* %{usec}t */ - ELEMENT_TYPE_TIMESTAMP_MSEC_FRAC, /* %{msec_frac}t */ - ELEMENT_TYPE_TIMESTAMP_USEC_FRAC, /* %{usec_frac}t */ - ELEMENT_TYPE_URL_PATH, /* %U */ - ELEMENT_TYPE_REMOTE_USER, /* %u */ - ELEMENT_TYPE_AUTHORITY, /* %V */ - ELEMENT_TYPE_HOSTCONF, /* %v */ - ELEMENT_TYPE_IN_HEADER_TOKEN, /* %{data.header_token}i */ - ELEMENT_TYPE_IN_HEADER_STRING, /* %{data.name}i */ - ELEMENT_TYPE_OUT_HEADER_TOKEN, /* %{data.header_token}o */ - ELEMENT_TYPE_OUT_HEADER_STRING, /* %{data.name}o */ - ELEMENT_TYPE_OUT_HEADER_TOKEN_CONCATENATED, /* %{data.header_token}o */ - ELEMENT_TYPE_EXTENDED_VAR, /* %{data.name}x */ - ELEMENT_TYPE_CONNECTION_ID, /* %{connection-id}x */ - ELEMENT_TYPE_CONNECT_TIME, /* %{connect-time}x */ - ELEMENT_TYPE_REQUEST_HEADER_TIME, /* %{request-header-time}x */ - ELEMENT_TYPE_REQUEST_BODY_TIME, /* %{request-body-time}x */ - ELEMENT_TYPE_REQUEST_TOTAL_TIME, /* %{request-total-time}x */ - ELEMENT_TYPE_PROCESS_TIME, /* %{process-time}x */ - ELEMENT_TYPE_RESPONSE_TIME, /* %{response-total-time}x */ - ELEMENT_TYPE_DURATION, /* %{duration}x */ - ELEMENT_TYPE_ERROR, /* %{error}x */ - ELEMENT_TYPE_PROTOCOL_SPECIFIC, /* %{protocol-specific...}x */ - NUM_ELEMENT_TYPES -}; - -struct log_element_t { - unsigned type; - h2o_iovec_t suffix; - union { - const h2o_token_t *header_token; - h2o_iovec_t name; - size_t protocol_specific_callback_index; - } data; - unsigned magically_quoted_json : 1; /* whether to omit surrounding doublequotes when the output is null */ - unsigned original_response : 1; -}; - -struct st_h2o_logconf_t { - H2O_VECTOR(struct log_element_t) elements; - int escape; -}; - -static h2o_iovec_t strdup_lowercased(const char *s, size_t len) -{ - h2o_iovec_t v = h2o_strdup(NULL, s, len); - h2o_strtolower(v.base, v.len); - return v; -} - -static int determine_magicquote_nodes(h2o_logconf_t *logconf, char *errbuf) -{ - size_t element_index; - int quote_char = '\0'; /* the quote char being used if the state machine is within a string literal */ - int just_in = 0; /* if we just went into the string literal */ - - for (element_index = 0; element_index < logconf->elements.size; ++element_index) { - h2o_iovec_t suffix = logconf->elements.entries[element_index].suffix; - logconf->elements.entries[element_index].magically_quoted_json = just_in && suffix.len != 0 && suffix.base[0] == quote_char; - - just_in = 0; - - size_t i; - for (i = 0; i < suffix.len; ++i) { - just_in = 0; - if (quote_char != '\0') { - if (quote_char == suffix.base[i]) { - /* out of quote? */ - size_t j, num_bs = 0; - for (j = i; j != 0; ++num_bs) - if (suffix.base[--j] != '\\') - break; - if (num_bs % 2 == 0) - quote_char = '\0'; - } - } else { - if (suffix.base[i] == '"' || suffix.base[i] == '\'') { - quote_char = suffix.base[i]; - just_in = 1; - } - } - } - } - - return 1; -} - -h2o_logconf_t *h2o_logconf_compile(const char *fmt, int escape, char *errbuf) -{ - h2o_logconf_t *logconf = h2o_mem_alloc(sizeof(*logconf)); - const char *pt = fmt; - size_t fmt_len = strlen(fmt); - - *logconf = (h2o_logconf_t){{NULL}, escape}; - -#define LAST_ELEMENT() (logconf->elements.entries + logconf->elements.size - 1) -/* suffix buffer is always guaranteed to be larger than the fmt + (sizeof('\n') - 1) (so that they would be no buffer overruns) */ -#define NEW_ELEMENT(ty) \ - do { \ - h2o_vector_reserve(NULL, &logconf->elements, logconf->elements.size + 1); \ - logconf->elements.size++; \ - *LAST_ELEMENT() = (struct log_element_t){0}; \ - LAST_ELEMENT()->type = ty; \ - LAST_ELEMENT()->suffix.base = h2o_mem_alloc(fmt_len + 1); \ - } while (0) - - while (*pt != '\0') { - if (memcmp(pt, "%%", 2) == 0) { - ++pt; /* emit % */ - } else if (*pt == '%') { - ++pt; - /* handle < and > */ - int log_original = 0; - for (;; ++pt) { - if (*pt == '<') { - log_original = 1; - } else if (*pt == '>') { - log_original = 0; - } else { - break; - } - } - /* handle {...}n */ - if (*pt == '{') { - const h2o_token_t *token; - const char *quote_end = strchr(++pt, '}'); - if (quote_end == NULL) { - sprintf(errbuf, "failed to compile log format: unterminated header name starting at: \"%16s\"", pt); - goto Error; - } - const char modifier = quote_end[1]; - switch (modifier) { - case 'i': - case 'o': { - h2o_iovec_t name = strdup_lowercased(pt, quote_end - pt); - token = h2o_lookup_token(name.base, name.len); - if (token != NULL) { - free(name.base); - if (modifier == 'o' && token == H2O_TOKEN_SET_COOKIE) { - NEW_ELEMENT(ELEMENT_TYPE_OUT_HEADER_TOKEN_CONCATENATED); - LAST_ELEMENT()->data.header_token = token; - } else { - NEW_ELEMENT(modifier == 'i' ? ELEMENT_TYPE_IN_HEADER_TOKEN : ELEMENT_TYPE_OUT_HEADER_TOKEN); - LAST_ELEMENT()->data.header_token = token; - } - } else { - NEW_ELEMENT(modifier == 'i' ? ELEMENT_TYPE_IN_HEADER_STRING : ELEMENT_TYPE_OUT_HEADER_STRING); - LAST_ELEMENT()->data.name = name; - } - LAST_ELEMENT()->original_response = log_original; - } break; - case 'p': - if (h2o_memis(pt, quote_end - pt, H2O_STRLIT("local"))) { - NEW_ELEMENT(ELEMENT_TYPE_LOCAL_PORT); - } else if (h2o_memis(pt, quote_end - pt, H2O_STRLIT("remote"))) { - NEW_ELEMENT(ELEMENT_TYPE_REMOTE_PORT); - } else { - sprintf(errbuf, "failed to compile log format: unknown specifier for %%{...}p"); - goto Error; - } - break; - case 'e': - { - h2o_iovec_t name = h2o_strdup(NULL, pt, quote_end - pt); - NEW_ELEMENT(ELEMENT_TYPE_ENV_VAR); - LAST_ELEMENT()->data.name = name; - } - break; - case 't': - if (h2o_memis(pt, quote_end - pt, H2O_STRLIT("sec"))) { - NEW_ELEMENT(ELEMENT_TYPE_TIMESTAMP_SEC_SINCE_EPOCH); - } else if (h2o_memis(pt, quote_end - pt, H2O_STRLIT("msec"))) { - NEW_ELEMENT(ELEMENT_TYPE_TIMESTAMP_MSEC_SINCE_EPOCH); - } else if (h2o_memis(pt, quote_end - pt, H2O_STRLIT("usec"))) { - NEW_ELEMENT(ELEMENT_TYPE_TIMESTAMP_USEC_SINCE_EPOCH); - } else if (h2o_memis(pt, quote_end - pt, H2O_STRLIT("msec_frac"))) { - NEW_ELEMENT(ELEMENT_TYPE_TIMESTAMP_MSEC_FRAC); - } else if (h2o_memis(pt, quote_end - pt, H2O_STRLIT("usec_frac"))) { - NEW_ELEMENT(ELEMENT_TYPE_TIMESTAMP_USEC_FRAC); - } else { - h2o_iovec_t name = h2o_strdup(NULL, pt, quote_end - pt); - NEW_ELEMENT(ELEMENT_TYPE_TIMESTAMP_STRFTIME); - LAST_ELEMENT()->data.name = name; - } - break; - case 'x': -#define MAP_EXT_TO_TYPE(name, id) \ - if (h2o_lcstris(pt, quote_end - pt, H2O_STRLIT(name))) { \ - NEW_ELEMENT(id); \ - goto MAP_EXT_Found; \ - } -#define MAP_EXT_TO_PROTO(name, cb) \ - if (h2o_lcstris(pt, quote_end - pt, H2O_STRLIT(name))) { \ - h2o_conn_callbacks_t dummy_; \ - NEW_ELEMENT(ELEMENT_TYPE_PROTOCOL_SPECIFIC); \ - LAST_ELEMENT()->data.protocol_specific_callback_index = \ - &dummy_.log_.cb - dummy_.log_.callbacks; \ - goto MAP_EXT_Found; \ - } - MAP_EXT_TO_TYPE("connection-id", ELEMENT_TYPE_CONNECTION_ID); - MAP_EXT_TO_TYPE("connect-time", ELEMENT_TYPE_CONNECT_TIME); - MAP_EXT_TO_TYPE("request-total-time", ELEMENT_TYPE_REQUEST_TOTAL_TIME); - MAP_EXT_TO_TYPE("request-header-time", ELEMENT_TYPE_REQUEST_HEADER_TIME); - MAP_EXT_TO_TYPE("request-body-time", ELEMENT_TYPE_REQUEST_BODY_TIME); - MAP_EXT_TO_TYPE("process-time", ELEMENT_TYPE_PROCESS_TIME); - MAP_EXT_TO_TYPE("response-time", ELEMENT_TYPE_RESPONSE_TIME); - MAP_EXT_TO_TYPE("duration", ELEMENT_TYPE_DURATION); - MAP_EXT_TO_TYPE("error", ELEMENT_TYPE_ERROR); - MAP_EXT_TO_PROTO("http1.request-index", http1.request_index); - MAP_EXT_TO_PROTO("http2.stream-id", http2.stream_id); - MAP_EXT_TO_PROTO("http2.priority.received", http2.priority_received); - MAP_EXT_TO_PROTO("http2.priority.received.exclusive", http2.priority_received_exclusive); - MAP_EXT_TO_PROTO("http2.priority.received.parent", http2.priority_received_parent); - MAP_EXT_TO_PROTO("http2.priority.received.weight", http2.priority_received_weight); - MAP_EXT_TO_PROTO("http2.priority.actual", http2.priority_actual); - MAP_EXT_TO_PROTO("http2.priority.actual.parent", http2.priority_actual_parent); - MAP_EXT_TO_PROTO("http2.priority.actual.weight", http2.priority_actual_weight); - MAP_EXT_TO_PROTO("ssl.protocol-version", ssl.protocol_version); - MAP_EXT_TO_PROTO("ssl.session-reused", ssl.session_reused); - MAP_EXT_TO_PROTO("ssl.cipher", ssl.cipher); - MAP_EXT_TO_PROTO("ssl.cipher-bits", ssl.cipher_bits); - MAP_EXT_TO_PROTO("ssl.session-id", ssl.session_id); - { /* not found */ - h2o_iovec_t name = strdup_lowercased(pt, quote_end - pt); - NEW_ELEMENT(ELEMENT_TYPE_EXTENDED_VAR); - LAST_ELEMENT()->data.name = name; - } - MAP_EXT_Found: -#undef MAP_EXT_TO_TYPE -#undef MAP_EXT_TO_PROTO - break; - default: - sprintf(errbuf, "failed to compile log format: header name is not followed by either `i`, `o`, `x`, `e`"); - goto Error; - } - pt = quote_end + 2; - continue; - } else { - unsigned type = NUM_ELEMENT_TYPES; - switch (*pt++) { -#define TYPE_MAP(ch, ty) \ - case ch: \ - type = ty; \ - break - TYPE_MAP('A', ELEMENT_TYPE_LOCAL_ADDR); - TYPE_MAP('b', ELEMENT_TYPE_BYTES_SENT); - TYPE_MAP('H', ELEMENT_TYPE_PROTOCOL); - TYPE_MAP('h', ELEMENT_TYPE_REMOTE_ADDR); - TYPE_MAP('l', ELEMENT_TYPE_LOGNAME); - TYPE_MAP('m', ELEMENT_TYPE_METHOD); - TYPE_MAP('p', ELEMENT_TYPE_LOCAL_PORT); - TYPE_MAP('e', ELEMENT_TYPE_ENV_VAR); - TYPE_MAP('q', ELEMENT_TYPE_QUERY); - TYPE_MAP('r', ELEMENT_TYPE_REQUEST_LINE); - TYPE_MAP('s', ELEMENT_TYPE_STATUS); - TYPE_MAP('t', ELEMENT_TYPE_TIMESTAMP); - TYPE_MAP('U', ELEMENT_TYPE_URL_PATH); - TYPE_MAP('u', ELEMENT_TYPE_REMOTE_USER); - TYPE_MAP('V', ELEMENT_TYPE_AUTHORITY); - TYPE_MAP('v', ELEMENT_TYPE_HOSTCONF); -#undef TYPE_MAP - default: - sprintf(errbuf, "failed to compile log format: unknown escape sequence: %%%c", pt[-1]); - goto Error; - } - NEW_ELEMENT(type); - LAST_ELEMENT()->original_response = log_original; - continue; - } - } - /* emit current char */ - if (logconf->elements.size == 0) - NEW_ELEMENT(ELEMENT_TYPE_EMPTY); - LAST_ELEMENT()->suffix.base[LAST_ELEMENT()->suffix.len++] = *pt++; - } - - /* emit end-of-line */ - if (logconf->elements.size == 0) - NEW_ELEMENT(ELEMENT_TYPE_EMPTY); - LAST_ELEMENT()->suffix.base[LAST_ELEMENT()->suffix.len++] = '\n'; - -#undef NEW_ELEMENT -#undef LAST_ELEMENT - - if (escape == H2O_LOGCONF_ESCAPE_JSON) { - if (!determine_magicquote_nodes(logconf, errbuf)) - goto Error; - } - - return logconf; - -Error: - h2o_logconf_dispose(logconf); - return NULL; -} - -void h2o_logconf_dispose(h2o_logconf_t *logconf) -{ - size_t i; - - for (i = 0; i != logconf->elements.size; ++i) { - free(logconf->elements.entries[i].suffix.base); - switch (logconf->elements.entries[i].type) { - case ELEMENT_TYPE_EXTENDED_VAR: - case ELEMENT_TYPE_IN_HEADER_STRING: - case ELEMENT_TYPE_OUT_HEADER_STRING: - case ELEMENT_TYPE_TIMESTAMP_STRFTIME: - free(logconf->elements.entries[i].data.name.base); - break; - default: - break; - } - } - free(logconf->elements.entries); - free(logconf); -} - -static inline char *append_safe_string(char *pos, const char *src, size_t len) -{ - memcpy(pos, src, len); - return pos + len; -} - -static char *append_unsafe_string_apache(char *pos, const char *src, size_t len) -{ - const char *src_end = src + len; - - for (; src != src_end; ++src) { - if (' ' <= *src && *src < 0x7d && *src != '"') { - *pos++ = *src; - } else { - *pos++ = '\\'; - *pos++ = 'x'; - *pos++ = ("0123456789abcdef")[(*src >> 4) & 0xf]; - *pos++ = ("0123456789abcdef")[*src & 0xf]; - } - } - - return pos; -} - -static char *append_unsafe_string_json(char *pos, const char *src, size_t len) -{ - const char *src_end = src + len; - - for (; src != src_end; ++src) { - if (' ' <= *src && *src < 0x7e) { - if (*src == '"' || *src == '\\') - *pos++ = '\\'; - *pos++ = *src; - } else { - *pos++ = '\\'; - *pos++ = 'u'; - *pos++ = '0'; - *pos++ = '0'; - *pos++ = ("0123456789abcdef")[(*src >> 4) & 0xf]; - *pos++ = ("0123456789abcdef")[*src & 0xf]; - } - } - - return pos; -} - -static char *append_addr(char *pos, socklen_t (*cb)(h2o_conn_t *conn, struct sockaddr *sa), h2o_conn_t *conn, h2o_iovec_t nullexpr) -{ - struct sockaddr_storage ss; - socklen_t sslen; - - if ((sslen = cb(conn, (void *)&ss)) == 0) - goto Fail; - size_t l = h2o_socket_getnumerichost((void *)&ss, sslen, pos); - if (l == SIZE_MAX) - goto Fail; - pos += l; - return pos; - -Fail: - memcpy(pos, nullexpr.base, nullexpr.len); - pos += nullexpr.len; - return pos; -} - -static char *append_port(char *pos, socklen_t (*cb)(h2o_conn_t *conn, struct sockaddr *sa), h2o_conn_t *conn, h2o_iovec_t nullexpr) -{ - struct sockaddr_storage ss; - socklen_t sslen; - - if ((sslen = cb(conn, (void *)&ss)) == 0) - goto Fail; - int32_t port = h2o_socket_getport((void *)&ss); - if (port == -1) - goto Fail; - pos += sprintf(pos, "%" PRIu16, (uint16_t)port); - return pos; - -Fail: - memcpy(pos, nullexpr.base, nullexpr.len); - pos += nullexpr.len; - return pos; -} - -#define APPEND_DURATION(pos, name) \ - do { \ - int64_t delta_usec; \ - if (!h2o_time_compute_##name(req, &delta_usec)) \ - goto EmitNull; \ - int32_t delta_sec = (int32_t)(delta_usec / (1000 * 1000)); \ - delta_usec -= ((int64_t)delta_sec * (1000 * 1000)); \ - RESERVE(sizeof(H2O_INT32_LONGEST_STR ".999999") - 1); \ - pos += sprintf(pos, "%" PRId32, delta_sec); \ - if (delta_usec != 0) { \ - int i; \ - *pos++ = '.'; \ - for (i = 5; i >= 0; --i) { \ - pos[i] = '0' + delta_usec % 10; \ - delta_usec /= 10; \ - } \ - pos += 6; \ - } \ - } while (0); - -static char *expand_line_buf(char *line, size_t *cur_size, size_t required, int should_realloc) -{ - size_t new_size = *cur_size; - - /* determine the new size */ - do { - new_size *= 2; - } while (new_size < required); - - /* reallocate */ - if (!should_realloc) { - char *newpt = h2o_mem_alloc(new_size); - memcpy(newpt, line, *cur_size); - line = newpt; - } else { - line = h2o_mem_realloc(line, new_size); - } - *cur_size = new_size; - - return line; -} - -char *h2o_log_request(h2o_logconf_t *logconf, h2o_req_t *req, size_t *len, char *buf) -{ - char *line = buf, *pos = line, *line_end = line + *len; - h2o_iovec_t nullexpr; - char *(*append_unsafe_string)(char *pos, const char *src, size_t len); - size_t element_index, unsafe_factor; - struct tm localt = {0}; - int should_realloc_on_expand = 0; - - switch (logconf->escape) { - case H2O_LOGCONF_ESCAPE_APACHE: - nullexpr = h2o_iovec_init(H2O_STRLIT("-")); - append_unsafe_string = append_unsafe_string_apache; - unsafe_factor = 4; - break; - case H2O_LOGCONF_ESCAPE_JSON: - nullexpr = h2o_iovec_init(H2O_STRLIT("null")); - append_unsafe_string = append_unsafe_string_json; - unsafe_factor = 6; - break; - default: - h2o_fatal("unexpected escape mode"); - break; - } - - for (element_index = 0; element_index != logconf->elements.size; ++element_index) { - struct log_element_t *element = logconf->elements.entries + element_index; - -/* reserve capacity + suffix.len */ -#define RESERVE(capacity) \ - do { \ - if ((capacity) + element->suffix.len > line_end - pos) { \ - size_t off = pos - line; \ - size_t size = line_end - line; \ - line = expand_line_buf(line, &size, off + (capacity) + element->suffix.len, should_realloc_on_expand); \ - pos = line + off; \ - line_end = line + size; \ - should_realloc_on_expand = 1; \ - } \ - } while (0) - - switch (element->type) { - case ELEMENT_TYPE_EMPTY: - RESERVE(0); - break; - case ELEMENT_TYPE_LOCAL_ADDR: /* %A */ - RESERVE(NI_MAXHOST); - pos = append_addr(pos, req->conn->callbacks->get_sockname, req->conn, nullexpr); - break; - case ELEMENT_TYPE_BYTES_SENT: /* %b */ - RESERVE(sizeof(H2O_UINT64_LONGEST_STR) - 1); - pos += sprintf(pos, "%" PRIu64, (uint64_t)req->bytes_sent); - break; - case ELEMENT_TYPE_PROTOCOL: /* %H */ - RESERVE(sizeof("HTTP/1.1")); - pos += h2o_stringify_protocol_version(pos, req->version); - break; - case ELEMENT_TYPE_REMOTE_ADDR: /* %h */ - RESERVE(NI_MAXHOST); - pos = append_addr(pos, req->conn->callbacks->get_peername, req->conn, nullexpr); - break; - case ELEMENT_TYPE_METHOD: /* %m */ - RESERVE(req->input.method.len * unsafe_factor); - pos = append_unsafe_string(pos, req->input.method.base, req->input.method.len); - break; - case ELEMENT_TYPE_LOCAL_PORT: /* %p */ - RESERVE(sizeof(H2O_UINT16_LONGEST_STR) - 1); - pos = append_port(pos, req->conn->callbacks->get_sockname, req->conn, nullexpr); - break; - case ELEMENT_TYPE_REMOTE_PORT: /* %{remote}p */ - RESERVE(sizeof(H2O_UINT16_LONGEST_STR) - 1); - pos = append_port(pos, req->conn->callbacks->get_peername, req->conn, nullexpr); - break; - case ELEMENT_TYPE_ENV_VAR: /* %{..}e */ { - h2o_iovec_t *env_var = h2o_req_getenv(req, element->data.name.base, element->data.name.len, 0); - if (env_var == NULL) - goto EmitNull; - RESERVE(env_var->len * unsafe_factor); - pos = append_safe_string(pos, env_var->base, env_var->len); - } break; - case ELEMENT_TYPE_QUERY: /* %q */ - if (req->input.query_at != SIZE_MAX) { - size_t len = req->input.path.len - req->input.query_at; - RESERVE(len * unsafe_factor); - pos = append_unsafe_string(pos, req->input.path.base + req->input.query_at, len); - } - break; - case ELEMENT_TYPE_REQUEST_LINE: /* %r */ - RESERVE((req->input.method.len + req->input.path.len) * unsafe_factor + sizeof(" HTTP/1.1")); - pos = append_unsafe_string(pos, req->input.method.base, req->input.method.len); - *pos++ = ' '; - pos = append_unsafe_string(pos, req->input.path.base, req->input.path.len); - *pos++ = ' '; - pos += h2o_stringify_protocol_version(pos, req->version); - break; - case ELEMENT_TYPE_STATUS: /* %s */ - RESERVE(sizeof(H2O_INT32_LONGEST_STR) - 1); - pos += sprintf(pos, "%" PRId32, (int32_t)(element->original_response ? req->res.original.status : req->res.status)); - break; - case ELEMENT_TYPE_TIMESTAMP: /* %t */ - if (h2o_timeval_is_null(&req->processed_at.at)) - goto EmitNull; - RESERVE(H2O_TIMESTR_LOG_LEN + 2); - *pos++ = '['; - pos = append_safe_string(pos, req->processed_at.str->log, H2O_TIMESTR_LOG_LEN); - *pos++ = ']'; - break; - case ELEMENT_TYPE_TIMESTAMP_STRFTIME: /* %{...}t */ - if (h2o_timeval_is_null(&req->processed_at.at)) - goto EmitNull; - { - size_t bufsz, len; - if (localt.tm_year == 0) - localtime_r(&req->processed_at.at.tv_sec, &localt); - for (bufsz = 128;; bufsz *= 2) { - RESERVE(bufsz); - if ((len = strftime(pos, bufsz, element->data.name.base, &localt)) != 0) - break; - } - pos += len; - } - break; - case ELEMENT_TYPE_TIMESTAMP_SEC_SINCE_EPOCH: /* %{sec}t */ - if (h2o_timeval_is_null(&req->processed_at.at)) - goto EmitNull; - RESERVE(sizeof(H2O_UINT32_LONGEST_STR) - 1); - pos += sprintf(pos, "%" PRIu32, (uint32_t)req->processed_at.at.tv_sec); - break; - case ELEMENT_TYPE_TIMESTAMP_MSEC_SINCE_EPOCH: /* %{msec}t */ - if (h2o_timeval_is_null(&req->processed_at.at)) - goto EmitNull; - RESERVE(sizeof(H2O_UINT64_LONGEST_STR) - 1); - pos += sprintf(pos, "%" PRIu64, - (uint64_t)req->processed_at.at.tv_sec * 1000 + (uint64_t)req->processed_at.at.tv_usec / 1000); - break; - case ELEMENT_TYPE_TIMESTAMP_USEC_SINCE_EPOCH: /* %{usec}t */ - if (h2o_timeval_is_null(&req->processed_at.at)) - goto EmitNull; - RESERVE(sizeof(H2O_UINT64_LONGEST_STR) - 1); - pos += - sprintf(pos, "%" PRIu64, (uint64_t)req->processed_at.at.tv_sec * 1000000 + (uint64_t)req->processed_at.at.tv_usec); - break; - case ELEMENT_TYPE_TIMESTAMP_MSEC_FRAC: /* %{msec_frac}t */ - if (h2o_timeval_is_null(&req->processed_at.at)) - goto EmitNull; - RESERVE(3); - pos += sprintf(pos, "%03u", (unsigned)(req->processed_at.at.tv_usec / 1000)); - break; - case ELEMENT_TYPE_TIMESTAMP_USEC_FRAC: /* %{usec_frac}t */ - if (h2o_timeval_is_null(&req->processed_at.at)) - goto EmitNull; - RESERVE(6); - pos += sprintf(pos, "%06u", (unsigned)req->processed_at.at.tv_usec); - break; - case ELEMENT_TYPE_URL_PATH: /* %U */ { - size_t path_len = req->input.query_at == SIZE_MAX ? req->input.path.len : req->input.query_at; - RESERVE(path_len * unsafe_factor); - pos = append_unsafe_string(pos, req->input.path.base, path_len); - } break; - case ELEMENT_TYPE_REMOTE_USER: /* %u */ { - h2o_iovec_t *remote_user = h2o_req_getenv(req, H2O_STRLIT("REMOTE_USER"), 0); - if (remote_user == NULL) - goto EmitNull; - RESERVE(remote_user->len * unsafe_factor); - pos = append_unsafe_string(pos, remote_user->base, remote_user->len); - } break; - case ELEMENT_TYPE_AUTHORITY: /* %V */ - RESERVE(req->input.authority.len * unsafe_factor); - pos = append_unsafe_string(pos, req->input.authority.base, req->input.authority.len); - break; - case ELEMENT_TYPE_HOSTCONF: /* %v */ - RESERVE(req->hostconf->authority.hostport.len * unsafe_factor); - pos = append_unsafe_string(pos, req->hostconf->authority.hostport.base, req->hostconf->authority.hostport.len); - break; - -#define EMIT_HEADER(__headers, concat, findfunc, ...) \ - do { \ - h2o_headers_t *headers = (__headers); \ - ssize_t index = -1; \ - int found = 0; \ - while ((index = (findfunc)(headers, __VA_ARGS__, index)) != -1) { \ - if (found) { \ - RESERVE(2); \ - *pos++ = ','; \ - *pos++ = ' '; \ - } else { \ - found = 1; \ - } \ - const h2o_header_t *header = headers->entries + index; \ - RESERVE(header->value.len *unsafe_factor); \ - pos = append_unsafe_string(pos, header->value.base, header->value.len); \ - if (!concat) \ - break; \ - } \ - if (!found) \ - goto EmitNull; \ - } while (0) - - case ELEMENT_TYPE_IN_HEADER_TOKEN: - EMIT_HEADER(&req->headers, 0, h2o_find_header, element->data.header_token); - break; - case ELEMENT_TYPE_IN_HEADER_STRING: - EMIT_HEADER(&req->headers, 0, h2o_find_header_by_str, element->data.name.base, element->data.name.len); - break; - case ELEMENT_TYPE_OUT_HEADER_TOKEN: - EMIT_HEADER(element->original_response ? &req->res.original.headers : &req->res.headers, 0, h2o_find_header, - element->data.header_token); - break; - case ELEMENT_TYPE_OUT_HEADER_STRING: - EMIT_HEADER(element->original_response ? &req->res.original.headers : &req->res.headers, 0, h2o_find_header_by_str, - element->data.name.base, element->data.name.len); - break; - case ELEMENT_TYPE_OUT_HEADER_TOKEN_CONCATENATED: - EMIT_HEADER(element->original_response ? &req->res.original.headers : &req->res.headers, 1, h2o_find_header, - element->data.header_token); - break; - -#undef EMIT_HEADER - - case ELEMENT_TYPE_CONNECTION_ID: - RESERVE(sizeof(H2O_UINT64_LONGEST_STR) - 1); - pos += sprintf(pos, "%" PRIu64, req->conn->id); - break; - - case ELEMENT_TYPE_CONNECT_TIME: - APPEND_DURATION(pos, connect_time); - break; - - case ELEMENT_TYPE_REQUEST_HEADER_TIME: - APPEND_DURATION(pos, header_time); - break; - - case ELEMENT_TYPE_REQUEST_BODY_TIME: - APPEND_DURATION(pos, body_time); - break; - - case ELEMENT_TYPE_REQUEST_TOTAL_TIME: - APPEND_DURATION(pos, request_total_time); - break; - - case ELEMENT_TYPE_PROCESS_TIME: - APPEND_DURATION(pos, process_time); - break; - - case ELEMENT_TYPE_RESPONSE_TIME: - APPEND_DURATION(pos, response_time); - break; - - case ELEMENT_TYPE_DURATION: - APPEND_DURATION(pos, duration); - break; - - case ELEMENT_TYPE_ERROR: { - size_t i; - for (i = 0; i != req->error_logs.size; ++i) { - h2o_req_error_log_t *log = req->error_logs.entries + i; - size_t module_len = strlen(log->module); - RESERVE(sizeof("[] ") - 1 + module_len + log->msg.len * unsafe_factor); - *pos++ = '['; - pos = append_safe_string(pos, log->module, module_len); - *pos++ = ']'; - *pos++ = ' '; - pos = append_unsafe_string(pos, log->msg.base, log->msg.len); - } - } break; - - case ELEMENT_TYPE_PROTOCOL_SPECIFIC: { - h2o_iovec_t (*cb)(h2o_req_t *) = req->conn->callbacks->log_.callbacks[element->data.protocol_specific_callback_index]; - if (cb != NULL) { - h2o_iovec_t s = cb(req); - if (s.base == NULL) - goto EmitNull; - RESERVE(s.len); - pos = append_safe_string(pos, s.base, s.len); - } else { - goto EmitNull; - } - } break; - - case ELEMENT_TYPE_LOGNAME: /* %l */ - case ELEMENT_TYPE_EXTENDED_VAR: /* %{...}x */ - EmitNull: - RESERVE(nullexpr.len); - /* special case that trims surrounding quotes */ - if (element->magically_quoted_json) { - --pos; - pos = append_safe_string(pos, nullexpr.base, nullexpr.len); - pos = append_safe_string(pos, element->suffix.base + 1, element->suffix.len - 1); - continue; - } - pos = append_safe_string(pos, nullexpr.base, nullexpr.len); - break; - - default: - assert(!"unknown type"); - break; - } - -#undef RESERVE - - pos = append_safe_string(pos, element->suffix.base, element->suffix.len); - } - - *len = pos - line; - return line; -} diff --git a/web/server/h2o/libh2o/lib/core/proxy.c b/web/server/h2o/libh2o/lib/core/proxy.c deleted file mode 100644 index edb4baf9d..000000000 --- a/web/server/h2o/libh2o/lib/core/proxy.c +++ /dev/null @@ -1,610 +0,0 @@ -/* - * Copyright (c) 2014,2015 DeNA Co., Ltd., Kazuho Oku, Masahiro Nagano - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#include <netdb.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/socket.h> -#include "picohttpparser.h" -#include "h2o.h" -#include "h2o/http1.h" -#include "h2o/http1client.h" -#include "h2o/tunnel.h" - -struct rp_generator_t { - h2o_generator_t super; - h2o_req_t *src_req; - h2o_http1client_t *client; - struct { - h2o_iovec_t bufs[2]; /* first buf is the request line and headers, the second is the POST content */ - int is_head; - } up_req; - h2o_buffer_t *last_content_before_send; - h2o_doublebuffer_t sending; - int is_websocket_handshake; - int had_body_error; /* set if an error happened while fetching the body so that we can propagate the error */ -}; - -struct rp_ws_upgrade_info_t { - h2o_context_t *ctx; - h2o_timeout_t *timeout; - h2o_socket_t *upstream_sock; -}; - -static h2o_http1client_ctx_t *get_client_ctx(h2o_req_t *req) -{ - h2o_req_overrides_t *overrides = req->overrides; - if (overrides != NULL && overrides->client_ctx != NULL) - return overrides->client_ctx; - return &req->conn->ctx->proxy.client_ctx; -} - -static h2o_iovec_t rewrite_location(h2o_mem_pool_t *pool, const char *location, size_t location_len, h2o_url_t *match, - const h2o_url_scheme_t *req_scheme, h2o_iovec_t req_authority, h2o_iovec_t req_basepath) -{ - h2o_url_t loc_parsed; - - if (h2o_url_parse(location, location_len, &loc_parsed) != 0) - goto NoRewrite; - if (loc_parsed.scheme != &H2O_URL_SCHEME_HTTP) - goto NoRewrite; - if (!h2o_url_hosts_are_equal(&loc_parsed, match)) - goto NoRewrite; - if (h2o_url_get_port(&loc_parsed) != h2o_url_get_port(match)) - goto NoRewrite; - if (loc_parsed.path.len < match->path.len) - goto NoRewrite; - if (memcmp(loc_parsed.path.base, match->path.base, match->path.len) != 0) - goto NoRewrite; - - return h2o_concat(pool, req_scheme->name, h2o_iovec_init(H2O_STRLIT("://")), req_authority, req_basepath, - h2o_iovec_init(loc_parsed.path.base + match->path.len, loc_parsed.path.len - match->path.len)); - -NoRewrite: - return (h2o_iovec_t){NULL}; -} - -static h2o_iovec_t build_request_merge_headers(h2o_mem_pool_t *pool, h2o_iovec_t merged, h2o_iovec_t added, int seperator) -{ - if (added.len == 0) - return merged; - if (merged.len == 0) - return added; - - size_t newlen = merged.len + 2 + added.len; - char *buf = h2o_mem_alloc_pool(pool, newlen); - memcpy(buf, merged.base, merged.len); - buf[merged.len] = seperator; - buf[merged.len + 1] = ' '; - memcpy(buf + merged.len + 2, added.base, added.len); - merged.base = buf; - merged.len = newlen; - return merged; -} - -/* - * A request without neither Content-Length or Transfer-Encoding header implies a zero-length request body (see 6th rule of RFC 7230 - * 3.3.3). - * OTOH, section 3.3.3 states: - * - * A user agent SHOULD send a Content-Length in a request message when - * no Transfer-Encoding is sent and the request method defines a meaning - * for an enclosed payload body. For example, a Content-Length header - * field is normally sent in a POST request even when the value is 0 - * (indicating an empty payload body). A user agent SHOULD NOT send a - * Content-Length header field when the request message does not contain - * a payload body and the method semantics do not anticipate such a - * body. - * - * PUT and POST define a meaning for the payload body, let's emit a - * Content-Length header if it doesn't exist already, since the server - * might send a '411 Length Required' response. - * - * see also: ML thread starting at https://lists.w3.org/Archives/Public/ietf-http-wg/2016JulSep/0580.html - */ -static int req_requires_content_length(h2o_req_t *req) -{ - int is_put_or_post = - (req->method.len >= 1 && req->method.base[0] == 'P' && (h2o_memis(req->method.base, req->method.len, H2O_STRLIT("POST")) || - h2o_memis(req->method.base, req->method.len, H2O_STRLIT("PUT")))); - - return is_put_or_post && h2o_find_header(&req->res.headers, H2O_TOKEN_TRANSFER_ENCODING, -1) == -1; -} - -static h2o_iovec_t build_request(h2o_req_t *req, int keepalive, int is_websocket_handshake, int use_proxy_protocol) -{ - h2o_iovec_t buf; - size_t offset = 0, remote_addr_len = SIZE_MAX; - char remote_addr[NI_MAXHOST]; - struct sockaddr_storage ss; - socklen_t sslen; - h2o_iovec_t cookie_buf = {NULL}, xff_buf = {NULL}, via_buf = {NULL}; - int preserve_x_forwarded_proto = req->conn->ctx->globalconf->proxy.preserve_x_forwarded_proto; - int emit_x_forwarded_headers = req->conn->ctx->globalconf->proxy.emit_x_forwarded_headers; - int emit_via_header = req->conn->ctx->globalconf->proxy.emit_via_header; - - /* for x-f-f */ - if ((sslen = req->conn->callbacks->get_peername(req->conn, (void *)&ss)) != 0) - remote_addr_len = h2o_socket_getnumerichost((void *)&ss, sslen, remote_addr); - - /* build response */ - buf.len = req->method.len + req->path.len + req->authority.len + 512; - if (use_proxy_protocol) - buf.len += H2O_PROXY_HEADER_MAX_LENGTH; - buf.base = h2o_mem_alloc_pool(&req->pool, buf.len); - -#define RESERVE(sz) \ - do { \ - size_t required = offset + sz + 4 /* for "\r\n\r\n" */; \ - if (required > buf.len) { \ - do { \ - buf.len *= 2; \ - } while (required > buf.len); \ - char *newp = h2o_mem_alloc_pool(&req->pool, buf.len); \ - memcpy(newp, buf.base, offset); \ - buf.base = newp; \ - } \ - } while (0) -#define APPEND(s, l) \ - do { \ - memcpy(buf.base + offset, (s), (l)); \ - offset += (l); \ - } while (0) -#define APPEND_STRLIT(lit) APPEND((lit), sizeof(lit) - 1) -#define FLATTEN_PREFIXED_VALUE(prefix, value, add_size) \ - do { \ - RESERVE(sizeof(prefix) - 1 + value.len + 2 + add_size); \ - APPEND_STRLIT(prefix); \ - if (value.len != 0) { \ - APPEND(value.base, value.len); \ - if (add_size != 0) { \ - buf.base[offset++] = ','; \ - buf.base[offset++] = ' '; \ - } \ - } \ - } while (0) - - if (use_proxy_protocol) - offset += h2o_stringify_proxy_header(req->conn, buf.base + offset); - - APPEND(req->method.base, req->method.len); - buf.base[offset++] = ' '; - APPEND(req->path.base, req->path.len); - APPEND_STRLIT(" HTTP/1.1\r\nconnection: "); - if (is_websocket_handshake) { - APPEND_STRLIT("upgrade\r\nupgrade: websocket\r\nhost: "); - } else if (keepalive) { - APPEND_STRLIT("keep-alive\r\nhost: "); - } else { - APPEND_STRLIT("close\r\nhost: "); - } - APPEND(req->authority.base, req->authority.len); - buf.base[offset++] = '\r'; - buf.base[offset++] = '\n'; - assert(offset <= buf.len); - if (req->entity.base != NULL || req_requires_content_length(req)) { - RESERVE(sizeof("content-length: " H2O_UINT64_LONGEST_STR) - 1); - offset += sprintf(buf.base + offset, "content-length: %zu\r\n", req->entity.len); - } - - /* rewrite headers if necessary */ - h2o_headers_t req_headers = req->headers; - if (req->overrides != NULL && req->overrides->headers_cmds != NULL) { - req_headers.entries = NULL; - req_headers.size = 0; - req_headers.capacity = 0; - h2o_headers_command_t *cmd; - h2o_vector_reserve(&req->pool, &req_headers, req->headers.capacity); - memcpy(req_headers.entries, req->headers.entries, sizeof(req->headers.entries[0]) * req->headers.size); - req_headers.size = req->headers.size; - for (cmd = req->overrides->headers_cmds; cmd->cmd != H2O_HEADERS_CMD_NULL; ++cmd) - h2o_rewrite_headers(&req->pool, &req_headers, cmd); - } - - { - const h2o_header_t *h, *h_end; - for (h = req_headers.entries, h_end = h + req_headers.size; h != h_end; ++h) { - if (h2o_iovec_is_token(h->name)) { - const h2o_token_t *token = (void *)h->name; - if (token->proxy_should_drop_for_req) { - continue; - } else if (token == H2O_TOKEN_COOKIE) { - /* merge the cookie headers; see HTTP/2 8.1.2.5 and HTTP/1 (RFC6265 5.4) */ - /* FIXME current algorithm is O(n^2) against the number of cookie headers */ - cookie_buf = build_request_merge_headers(&req->pool, cookie_buf, h->value, ';'); - continue; - } else if (token == H2O_TOKEN_VIA) { - if (!emit_via_header) { - goto AddHeader; - } - via_buf = build_request_merge_headers(&req->pool, via_buf, h->value, ','); - continue; - } else if (token == H2O_TOKEN_X_FORWARDED_FOR) { - if (!emit_x_forwarded_headers) { - goto AddHeader; - } - xff_buf = build_request_merge_headers(&req->pool, xff_buf, h->value, ','); - continue; - } - } - if (!preserve_x_forwarded_proto && h2o_lcstris(h->name->base, h->name->len, H2O_STRLIT("x-forwarded-proto"))) - continue; - AddHeader: - RESERVE(h->name->len + h->value.len + 2); - APPEND(h->orig_name ? h->orig_name : h->name->base, h->name->len); - buf.base[offset++] = ':'; - buf.base[offset++] = ' '; - APPEND(h->value.base, h->value.len); - buf.base[offset++] = '\r'; - buf.base[offset++] = '\n'; - } - } - if (cookie_buf.len != 0) { - FLATTEN_PREFIXED_VALUE("cookie: ", cookie_buf, 0); - buf.base[offset++] = '\r'; - buf.base[offset++] = '\n'; - } - if (emit_x_forwarded_headers) { - if (!preserve_x_forwarded_proto) { - FLATTEN_PREFIXED_VALUE("x-forwarded-proto: ", req->input.scheme->name, 0); - buf.base[offset++] = '\r'; - buf.base[offset++] = '\n'; - } - if (remote_addr_len != SIZE_MAX) { - FLATTEN_PREFIXED_VALUE("x-forwarded-for: ", xff_buf, remote_addr_len); - APPEND(remote_addr, remote_addr_len); - } else { - FLATTEN_PREFIXED_VALUE("x-forwarded-for: ", xff_buf, 0); - } - buf.base[offset++] = '\r'; - buf.base[offset++] = '\n'; - } - if (emit_via_header) { - FLATTEN_PREFIXED_VALUE("via: ", via_buf, sizeof("1.1 ") - 1 + req->input.authority.len); - if (req->version < 0x200) { - buf.base[offset++] = '1'; - buf.base[offset++] = '.'; - buf.base[offset++] = '0' + (0x100 <= req->version && req->version <= 0x109 ? req->version - 0x100 : 0); - } else { - buf.base[offset++] = '2'; - } - buf.base[offset++] = ' '; - APPEND(req->input.authority.base, req->input.authority.len); - buf.base[offset++] = '\r'; - buf.base[offset++] = '\n'; - } - APPEND_STRLIT("\r\n"); - -#undef RESERVE -#undef APPEND -#undef APPEND_STRLIT -#undef FLATTEN_PREFIXED_VALUE - - /* set the length */ - assert(offset <= buf.len); - buf.len = offset; - - return buf; -} - -static void do_close(h2o_generator_t *generator, h2o_req_t *req) -{ - struct rp_generator_t *self = (void *)generator; - - if (self->client != NULL) { - h2o_http1client_cancel(self->client); - self->client = NULL; - } -} - -static void do_send(struct rp_generator_t *self) -{ - h2o_iovec_t vecs[1]; - size_t veccnt; - h2o_send_state_t ststate; - - assert(self->sending.bytes_inflight == 0); - - vecs[0] = h2o_doublebuffer_prepare(&self->sending, - self->client != NULL ? &self->client->sock->input : &self->last_content_before_send, - self->src_req->preferred_chunk_size); - - if (self->client == NULL && vecs[0].len == self->sending.buf->size && self->last_content_before_send->size == 0) { - veccnt = vecs[0].len != 0 ? 1 : 0; - ststate = H2O_SEND_STATE_FINAL; - } else { - if (vecs[0].len == 0) - return; - veccnt = 1; - ststate = H2O_SEND_STATE_IN_PROGRESS; - } - - if (self->had_body_error) - ststate = H2O_SEND_STATE_ERROR; - - h2o_send(self->src_req, vecs, veccnt, ststate); -} - -static void do_proceed(h2o_generator_t *generator, h2o_req_t *req) -{ - struct rp_generator_t *self = (void *)generator; - - h2o_doublebuffer_consume(&self->sending); - do_send(self); -} - -static void on_websocket_upgrade_complete(void *_info, h2o_socket_t *sock, size_t reqsize) -{ - struct rp_ws_upgrade_info_t *info = _info; - - if (sock != NULL) { - h2o_buffer_consume(&sock->input, reqsize);//It is detached from conn. Let's trash unused data. - h2o_tunnel_establish(info->ctx, sock, info->upstream_sock, info->timeout); - } else { - h2o_socket_close(info->upstream_sock); - } - free(info); -} - -static inline void on_websocket_upgrade(struct rp_generator_t *self, h2o_timeout_t *timeout, int rlen) -{ - h2o_req_t *req = self->src_req; - h2o_socket_t *sock = h2o_http1client_steal_socket(self->client); - h2o_buffer_consume(&sock->input, rlen);//trash data after stealing sock. - struct rp_ws_upgrade_info_t *info = h2o_mem_alloc(sizeof(*info)); - info->upstream_sock = sock; - info->timeout = timeout; - info->ctx = req->conn->ctx; - h2o_http1_upgrade(req, NULL, 0, on_websocket_upgrade_complete, info); -} - -static int on_body(h2o_http1client_t *client, const char *errstr) -{ - struct rp_generator_t *self = client->data; - - if (errstr != NULL) { - /* detach the content */ - self->last_content_before_send = self->client->sock->input; - h2o_buffer_init(&self->client->sock->input, &h2o_socket_buffer_prototype); - self->client = NULL; - if (errstr != h2o_http1client_error_is_eos) { - h2o_req_log_error(self->src_req, "lib/core/proxy.c", "%s", errstr); - self->had_body_error = 1; - } - } - if (self->sending.bytes_inflight == 0) - do_send(self); - - return 0; -} - -static char compress_hint_to_enum(const char *val, size_t len) -{ - if (h2o_lcstris(val, len, H2O_STRLIT("on"))) { - return H2O_COMPRESS_HINT_ENABLE; - } - if (h2o_lcstris(val, len, H2O_STRLIT("off"))) { - return H2O_COMPRESS_HINT_DISABLE; - } - return H2O_COMPRESS_HINT_AUTO; -} - -static h2o_http1client_body_cb on_head(h2o_http1client_t *client, const char *errstr, int minor_version, int status, - h2o_iovec_t msg, h2o_header_t *headers, size_t num_headers, int rlen) -{ - struct rp_generator_t *self = client->data; - h2o_req_t *req = self->src_req; - size_t i; - - if (errstr != NULL && errstr != h2o_http1client_error_is_eos) { - self->client = NULL; - h2o_req_log_error(req, "lib/core/proxy.c", "%s", errstr); - h2o_send_error_502(req, "Gateway Error", errstr, 0); - return NULL; - } - - /* copy the response (note: all the headers must be copied; http1client discards the input once we return from this callback) */ - req->res.status = status; - req->res.reason = h2o_strdup(&req->pool, msg.base, msg.len).base; - for (i = 0; i != num_headers; ++i) { - if (h2o_iovec_is_token(headers[i].name)) { - const h2o_token_t *token = H2O_STRUCT_FROM_MEMBER(h2o_token_t, buf, headers[i].name); - h2o_iovec_t value; - if (token->proxy_should_drop_for_res) { - goto Skip; - } - if (token == H2O_TOKEN_CONTENT_LENGTH) { - if (req->res.content_length != SIZE_MAX || - (req->res.content_length = h2o_strtosize(headers[i].value.base, headers[i].value.len)) == SIZE_MAX) { - self->client = NULL; - h2o_req_log_error(req, "lib/core/proxy.c", "%s", "invalid response from upstream (malformed content-length)"); - h2o_send_error_502(req, "Gateway Error", "invalid response from upstream", 0); - return NULL; - } - goto Skip; - } else if (token == H2O_TOKEN_LOCATION) { - if (req->res_is_delegated && (300 <= status && status <= 399) && status != 304) { - self->client = NULL; - h2o_iovec_t method = h2o_get_redirect_method(req->method, status); - h2o_send_redirect_internal(req, method, headers[i].value.base, headers[i].value.len, 1); - return NULL; - } - if (req->overrides != NULL && req->overrides->location_rewrite.match != NULL) { - value = rewrite_location(&req->pool, headers[i].value.base, headers[i].value.len, - req->overrides->location_rewrite.match, req->input.scheme, req->input.authority, - req->overrides->location_rewrite.path_prefix); - if (value.base != NULL) - goto AddHeader; - } - goto AddHeaderDuped; - } else if (token == H2O_TOKEN_LINK) { - h2o_iovec_t new_value; - new_value = h2o_push_path_in_link_header(req, headers[i].value.base, headers[i].value.len); - if (!new_value.len) - goto Skip; - headers[i].value.base = new_value.base; - headers[i].value.len = new_value.len; - } else if (token == H2O_TOKEN_SERVER) { - if (!req->conn->ctx->globalconf->proxy.preserve_server_header) - goto Skip; - } else if (token == H2O_TOKEN_X_COMPRESS_HINT) { - req->compress_hint = compress_hint_to_enum(headers[i].value.base, headers[i].value.len); - goto Skip; - } - /* default behaviour, transfer the header downstream */ - AddHeaderDuped: - value = h2o_strdup(&req->pool, headers[i].value.base, headers[i].value.len); - AddHeader: - h2o_add_header(&req->pool, &req->res.headers, token, headers[i].orig_name, value.base, value.len); - Skip:; - } else { - h2o_iovec_t name = h2o_strdup(&req->pool, headers[i].name->base, headers[i].name->len); - h2o_iovec_t value = h2o_strdup(&req->pool, headers[i].value.base, headers[i].value.len); - h2o_add_header_by_str(&req->pool, &req->res.headers, name.base, name.len, 0, headers[i].orig_name, value.base, - value.len); - } - } - - if (self->is_websocket_handshake && req->res.status == 101) { - h2o_http1client_ctx_t *client_ctx = get_client_ctx(req); - assert(client_ctx->websocket_timeout != NULL); - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_UPGRADE, NULL, H2O_STRLIT("websocket")); - on_websocket_upgrade(self, client_ctx->websocket_timeout, rlen); - self->client = NULL; - return NULL; - } - /* declare the start of the response */ - h2o_start_response(req, &self->super); - - if (errstr == h2o_http1client_error_is_eos) { - self->client = NULL; - h2o_send(req, NULL, 0, H2O_SEND_STATE_FINAL); - return NULL; - } - - return on_body; -} - -static int on_1xx(h2o_http1client_t *client, int minor_version, int status, h2o_iovec_t msg, h2o_header_t *headers, - size_t num_headers) -{ - struct rp_generator_t *self = client->data; - size_t i; - - for (i = 0; i != num_headers; ++i) { - if (headers[i].name == &H2O_TOKEN_LINK->buf) - h2o_push_path_in_link_header(self->src_req, headers[i].value.base, headers[i].value.len); - } - - return 0; -} - -static h2o_http1client_head_cb on_connect(h2o_http1client_t *client, const char *errstr, h2o_iovec_t **reqbufs, size_t *reqbufcnt, - int *method_is_head) -{ - struct rp_generator_t *self = client->data; - - if (errstr != NULL) { - self->client = NULL; - h2o_req_log_error(self->src_req, "lib/core/proxy.c", "%s", errstr); - h2o_send_error_502(self->src_req, "Gateway Error", errstr, 0); - return NULL; - } - - *reqbufs = self->up_req.bufs; - *reqbufcnt = self->up_req.bufs[1].base != NULL ? 2 : 1; - *method_is_head = self->up_req.is_head; - self->client->informational_cb = on_1xx; - return on_head; -} - -static void on_generator_dispose(void *_self) -{ - struct rp_generator_t *self = _self; - - if (self->client != NULL) { - h2o_http1client_cancel(self->client); - self->client = NULL; - } - h2o_buffer_dispose(&self->last_content_before_send); - h2o_doublebuffer_dispose(&self->sending); -} - -static struct rp_generator_t *proxy_send_prepare(h2o_req_t *req, int keepalive, int use_proxy_protocol) -{ - struct rp_generator_t *self = h2o_mem_alloc_shared(&req->pool, sizeof(*self), on_generator_dispose); - h2o_http1client_ctx_t *client_ctx = get_client_ctx(req); - - self->super.proceed = do_proceed; - self->super.stop = do_close; - self->src_req = req; - if (client_ctx->websocket_timeout != NULL && h2o_lcstris(req->upgrade.base, req->upgrade.len, H2O_STRLIT("websocket"))) { - self->is_websocket_handshake = 1; - } else { - self->is_websocket_handshake = 0; - } - self->had_body_error = 0; - self->up_req.bufs[0] = build_request(req, keepalive, self->is_websocket_handshake, use_proxy_protocol); - self->up_req.bufs[1] = req->entity; - self->up_req.is_head = h2o_memis(req->method.base, req->method.len, H2O_STRLIT("HEAD")); - h2o_buffer_init(&self->last_content_before_send, &h2o_socket_buffer_prototype); - h2o_doublebuffer_init(&self->sending, &h2o_socket_buffer_prototype); - - return self; -} - -void h2o__proxy_process_request(h2o_req_t *req) -{ - h2o_req_overrides_t *overrides = req->overrides; - h2o_http1client_ctx_t *client_ctx = get_client_ctx(req); - struct rp_generator_t *self; - - if (overrides != NULL) { - if (overrides->socketpool != NULL) { - if (overrides->use_proxy_protocol) - assert(!"proxy protocol cannot be used for a persistent upstream connection"); - self = proxy_send_prepare(req, 1, 0); - h2o_http1client_connect_with_pool(&self->client, self, client_ctx, overrides->socketpool, on_connect); - return; - } else if (overrides->hostport.host.base != NULL) { - self = proxy_send_prepare(req, 0, overrides->use_proxy_protocol); - h2o_http1client_connect(&self->client, self, client_ctx, req->overrides->hostport.host, req->overrides->hostport.port, - 0, on_connect); - return; - } - } - { /* default logic */ - h2o_iovec_t host; - uint16_t port; - if (h2o_url_parse_hostport(req->authority.base, req->authority.len, &host, &port) == NULL) { - h2o_req_log_error(req, "lib/core/proxy.c", "invalid URL supplied for internal redirection:%s://%.*s%.*s", - req->scheme->name.base, (int)req->authority.len, req->authority.base, (int)req->path.len, - req->path.base); - h2o_send_error_502(req, "Gateway Error", "internal error", 0); - return; - } - if (port == 65535) - port = req->scheme->default_port; - self = proxy_send_prepare(req, 0, overrides != NULL && overrides->use_proxy_protocol); - h2o_http1client_connect(&self->client, self, client_ctx, host, port, req->scheme == &H2O_URL_SCHEME_HTTPS, on_connect); - return; - } -} diff --git a/web/server/h2o/libh2o/lib/core/request.c b/web/server/h2o/libh2o/lib/core/request.c deleted file mode 100644 index 96aabb22d..000000000 --- a/web/server/h2o/libh2o/lib/core/request.c +++ /dev/null @@ -1,696 +0,0 @@ -/* - * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/uio.h> -#include "h2o.h" - -#ifndef IOV_MAX -#define IOV_MAX UIO_MAXIOV -#endif - -#define INITIAL_INBUFSZ 8192 - -struct st_deferred_request_action_t { - h2o_timeout_entry_t timeout; - h2o_req_t *req; -}; - -struct st_delegate_request_deferred_t { - struct st_deferred_request_action_t super; - h2o_handler_t *current_handler; -}; - -struct st_reprocess_request_deferred_t { - struct st_deferred_request_action_t super; - h2o_iovec_t method; - const h2o_url_scheme_t *scheme; - h2o_iovec_t authority; - h2o_iovec_t path; - h2o_req_overrides_t *overrides; - int is_delegated; -}; - -struct st_send_error_deferred_t { - h2o_req_t *req; - int status; - const char *reason; - const char *body; - int flags; - h2o_timeout_entry_t _timeout; -}; - -static void on_deferred_action_dispose(void *_action) -{ - struct st_deferred_request_action_t *action = _action; - if (h2o_timeout_is_linked(&action->timeout)) - h2o_timeout_unlink(&action->timeout); -} - -static struct st_deferred_request_action_t *create_deferred_action(h2o_req_t *req, size_t sz, h2o_timeout_cb cb) -{ - struct st_deferred_request_action_t *action = h2o_mem_alloc_shared(&req->pool, sz, on_deferred_action_dispose); - *action = (struct st_deferred_request_action_t){{0, cb}, req}; - h2o_timeout_link(req->conn->ctx->loop, &req->conn->ctx->zero_timeout, &action->timeout); - return action; -} - -static h2o_hostconf_t *find_hostconf(h2o_hostconf_t **hostconfs, h2o_iovec_t authority, uint16_t default_port) -{ - h2o_iovec_t hostname; - uint16_t port; - char *hostname_lc; - - /* safe-guard for alloca */ - if (authority.len >= 65536) - return NULL; - - /* extract the specified hostname and port */ - if (h2o_url_parse_hostport(authority.base, authority.len, &hostname, &port) == NULL) - return NULL; - if (port == 65535) - port = default_port; - - /* convert supplied hostname to lower-case */ - hostname_lc = alloca(hostname.len); - memcpy(hostname_lc, hostname.base, hostname.len); - h2o_strtolower(hostname_lc, hostname.len); - - do { - h2o_hostconf_t *hostconf = *hostconfs; - if (hostconf->authority.port == port || (hostconf->authority.port == 65535 && port == default_port)) { - if (hostconf->authority.host.base[0] == '*') { - /* matching against "*.foo.bar" */ - size_t cmplen = hostconf->authority.host.len - 1; - if (cmplen < hostname.len && - memcmp(hostconf->authority.host.base + 1, hostname_lc + hostname.len - cmplen, cmplen) == 0) - return hostconf; - } else { - /* exact match */ - if (h2o_memis(hostconf->authority.host.base, hostconf->authority.host.len, hostname_lc, hostname.len)) - return hostconf; - } - } - } while (*++hostconfs != NULL); - - return NULL; -} - -static h2o_hostconf_t *setup_before_processing(h2o_req_t *req) -{ - h2o_context_t *ctx = req->conn->ctx; - h2o_hostconf_t *hostconf; - - h2o_get_timestamp(ctx, &req->pool, &req->processed_at); - - /* find the host context */ - if (req->input.authority.base != NULL) { - if (req->conn->hosts[1] == NULL || - (hostconf = find_hostconf(req->conn->hosts, req->input.authority, req->input.scheme->default_port)) == NULL) - hostconf = *req->conn->hosts; - } else { - /* set the authority name to the default one */ - hostconf = *req->conn->hosts; - req->input.authority = hostconf->authority.hostport; - } - - req->scheme = req->input.scheme; - req->method = req->input.method; - req->authority = req->input.authority; - req->path = req->input.path; - req->path_normalized = - h2o_url_normalize_path(&req->pool, req->input.path.base, req->input.path.len, &req->query_at, &req->norm_indexes); - req->input.query_at = req->query_at; /* we can do this since input.path == path */ - - return hostconf; -} - -static void call_handlers(h2o_req_t *req, h2o_handler_t **handler) -{ - h2o_handler_t **end = req->pathconf->handlers.entries + req->pathconf->handlers.size; - - for (; handler != end; ++handler) - if ((*handler)->on_req(*handler, req) == 0) - return; - - h2o_send_error_404(req, "File Not Found", "not found", 0); -} - -static void process_hosted_request(h2o_req_t *req, h2o_hostconf_t *hostconf) -{ - h2o_pathconf_t *selected_pathconf = &hostconf->fallback_path; - size_t i; - - /* setup pathconf, or redirect to "path/" */ - for (i = 0; i != hostconf->paths.size; ++i) { - h2o_pathconf_t *candidate = hostconf->paths.entries + i; - if (req->path_normalized.len >= candidate->path.len && - memcmp(req->path_normalized.base, candidate->path.base, candidate->path.len) == 0 && - (candidate->path.base[candidate->path.len - 1] == '/' || req->path_normalized.len == candidate->path.len || - req->path_normalized.base[candidate->path.len] == '/')) { - selected_pathconf = candidate; - break; - } - } - h2o_req_bind_conf(req, hostconf, selected_pathconf); - - call_handlers(req, req->pathconf->handlers.entries); -} - -static void deferred_proceed_cb(h2o_timeout_entry_t *entry) -{ - h2o_req_t *req = H2O_STRUCT_FROM_MEMBER(h2o_req_t, _timeout_entry, entry); - h2o_proceed_response(req); -} - -static void close_generator_and_filters(h2o_req_t *req) -{ - /* close the generator if it is still open */ - if (req->_generator != NULL) { - /* close generator */ - if (req->_generator->stop != NULL) - req->_generator->stop(req->_generator, req); - req->_generator = NULL; - } - /* close the ostreams still open */ - while (req->_ostr_top->next != NULL) { - if (req->_ostr_top->stop != NULL) - req->_ostr_top->stop(req->_ostr_top, req); - req->_ostr_top = req->_ostr_top->next; - } -} - -static void reset_response(h2o_req_t *req) -{ - req->res = (h2o_res_t){0, NULL, SIZE_MAX}; - req->res.reason = "OK"; - req->_next_filter_index = 0; - req->bytes_sent = 0; -} - -static void retain_original_response(h2o_req_t *req) -{ - if (req->res.original.status != 0) - return; - - req->res.original.status = req->res.status; - h2o_vector_reserve(&req->pool, &req->res.original.headers, req->res.headers.size); - h2o_memcpy(req->res.original.headers.entries, req->res.headers.entries, - sizeof(req->res.headers.entries[0]) * req->res.headers.size); - req->res.original.headers.size = req->res.headers.size; -} - -void h2o_init_request(h2o_req_t *req, h2o_conn_t *conn, h2o_req_t *src) -{ - /* clear all memory (expect memory pool, since it is large) */ - memset(req, 0, offsetof(h2o_req_t, pool)); - - /* init memory pool (before others, since it may be used) */ - h2o_mem_init_pool(&req->pool); - - /* init properties that should be initialized to non-zero */ - req->conn = conn; - req->_timeout_entry.cb = deferred_proceed_cb; - req->res.reason = "OK"; /* default to "OK" regardless of the status value, it's not important after all (never sent in HTTP2) */ - req->res.content_length = SIZE_MAX; - req->preferred_chunk_size = SIZE_MAX; - - if (src != NULL) { - size_t i; -#define COPY(buf) \ - do { \ - req->buf.base = h2o_mem_alloc_pool(&req->pool, src->buf.len); \ - memcpy(req->buf.base, src->buf.base, src->buf.len); \ - req->buf.len = src->buf.len; \ - } while (0) - COPY(input.authority); - COPY(input.method); - COPY(input.path); - req->input.scheme = src->input.scheme; - req->version = src->version; - req->entity = src->entity; - req->http1_is_persistent = src->http1_is_persistent; - req->timestamps = src->timestamps; - if (src->upgrade.base != NULL) { - COPY(upgrade); - } else { - req->upgrade.base = NULL; - req->upgrade.len = 0; - } -#undef COPY - h2o_vector_reserve(&req->pool, &req->headers, src->headers.size); - req->headers.size = src->headers.size; - for (i = 0; i != src->headers.size; ++i) { - h2o_header_t *dst_header = req->headers.entries + i, *src_header = src->headers.entries + i; - if (h2o_iovec_is_token(src_header->name)) { - dst_header->name = src_header->name; - } else { - dst_header->name = h2o_mem_alloc_pool(&req->pool, sizeof(*dst_header->name)); - *dst_header->name = h2o_strdup(&req->pool, src_header->name->base, src_header->name->len); - } - dst_header->value = h2o_strdup(&req->pool, src_header->value.base, src_header->value.len); - if (!src_header->orig_name) - dst_header->orig_name = NULL; - else - dst_header->orig_name = h2o_strdup(&req->pool, src_header->orig_name, src_header->name->len).base; - } - if (src->env.size != 0) { - h2o_vector_reserve(&req->pool, &req->env, src->env.size); - req->env.size = src->env.size; - for (i = 0; i != req->env.size; ++i) - req->env.entries[i] = h2o_strdup(&req->pool, src->env.entries[i].base, src->env.entries[i].len); - } - } -} - -void h2o_dispose_request(h2o_req_t *req) -{ - close_generator_and_filters(req); - - h2o_timeout_unlink(&req->_timeout_entry); - - if (req->version != 0 && req->pathconf != NULL) { - h2o_logger_t **logger = req->pathconf->loggers.entries, **end = logger + req->pathconf->loggers.size; - for (; logger != end; ++logger) { - (*logger)->log_access((*logger), req); - } - } - - h2o_mem_clear_pool(&req->pool); -} - -void h2o_process_request(h2o_req_t *req) -{ - h2o_hostconf_t *hostconf = setup_before_processing(req); - process_hosted_request(req, hostconf); -} - -void h2o_delegate_request(h2o_req_t *req, h2o_handler_t *current_handler) -{ - h2o_handler_t **handler = req->pathconf->handlers.entries, **end = handler + req->pathconf->handlers.size; - - for (; handler != end; ++handler) { - if (*handler == current_handler) { - ++handler; - break; - } - } - call_handlers(req, handler); -} - -static void on_delegate_request_cb(h2o_timeout_entry_t *entry) -{ - struct st_delegate_request_deferred_t *args = - H2O_STRUCT_FROM_MEMBER(struct st_delegate_request_deferred_t, super.timeout, entry); - h2o_delegate_request(args->super.req, args->current_handler); -} - -void h2o_delegate_request_deferred(h2o_req_t *req, h2o_handler_t *current_handler) -{ - struct st_delegate_request_deferred_t *args = - (struct st_delegate_request_deferred_t *)create_deferred_action(req, sizeof(*args), on_delegate_request_cb); - args->current_handler = current_handler; -} - -void h2o_reprocess_request(h2o_req_t *req, h2o_iovec_t method, const h2o_url_scheme_t *scheme, h2o_iovec_t authority, - h2o_iovec_t path, h2o_req_overrides_t *overrides, int is_delegated) -{ - h2o_hostconf_t *hostconf; - - retain_original_response(req); - - /* close generators and filters that are already running */ - close_generator_and_filters(req); - - /* setup the request/response parameters */ - req->method = method; - req->scheme = scheme; - req->authority = authority; - req->path = path; - req->path_normalized = h2o_url_normalize_path(&req->pool, req->path.base, req->path.len, &req->query_at, &req->norm_indexes); - req->overrides = overrides; - req->res_is_delegated |= is_delegated; - reset_response(req); - - /* check the delegation (or reprocess) counter */ - if (req->res_is_delegated) { - if (req->num_delegated == req->conn->ctx->globalconf->max_delegations) { - /* TODO log */ - h2o_send_error_502(req, "Gateway Error", "too many internal delegations", 0); - return; - } - ++req->num_delegated; - } else { - if (req->num_reprocessed >= 5) { - /* TODO log */ - h2o_send_error_502(req, "Gateway Error", "too many internal reprocesses", 0); - return; - } - ++req->num_reprocessed; - } - - /* handle the response using the handlers, if hostconf exists */ - h2o_hostconf_t **hosts = is_delegated ? req->conn->ctx->globalconf->hosts : req->conn->hosts; - if (req->overrides == NULL && (hostconf = find_hostconf(hosts, req->authority, req->scheme->default_port)) != NULL) { - req->pathconf = NULL; - process_hosted_request(req, hostconf); - return; - } - - /* uses the current pathconf, in other words, proxy uses the previous pathconf for building filters */ - h2o__proxy_process_request(req); -} - -static void on_reprocess_request_cb(h2o_timeout_entry_t *entry) -{ - struct st_reprocess_request_deferred_t *args = - H2O_STRUCT_FROM_MEMBER(struct st_reprocess_request_deferred_t, super.timeout, entry); - h2o_reprocess_request(args->super.req, args->method, args->scheme, args->authority, args->path, args->overrides, - args->is_delegated); -} - -void h2o_reprocess_request_deferred(h2o_req_t *req, h2o_iovec_t method, const h2o_url_scheme_t *scheme, h2o_iovec_t authority, - h2o_iovec_t path, h2o_req_overrides_t *overrides, int is_delegated) -{ - struct st_reprocess_request_deferred_t *args = - (struct st_reprocess_request_deferred_t *)create_deferred_action(req, sizeof(*args), on_reprocess_request_cb); - args->method = method; - args->scheme = scheme; - args->authority = authority; - args->path = path; - args->overrides = overrides; - args->is_delegated = is_delegated; -} - -void h2o_start_response(h2o_req_t *req, h2o_generator_t *generator) -{ - retain_original_response(req); - - /* set generator */ - assert(req->_generator == NULL); - req->_generator = generator; - - /* setup response filters */ - if (req->prefilters != NULL) { - req->prefilters->on_setup_ostream(req->prefilters, req, &req->_ostr_top); - } else { - h2o_setup_next_ostream(req, &req->_ostr_top); - } -} - -void h2o_send(h2o_req_t *req, h2o_iovec_t *bufs, size_t bufcnt, h2o_send_state_t state) -{ - assert(req->_generator != NULL); - - if (!h2o_send_state_is_in_progress(state)) - req->_generator = NULL; - - req->_ostr_top->do_send(req->_ostr_top, req, bufs, bufcnt, state); -} - -h2o_req_prefilter_t *h2o_add_prefilter(h2o_req_t *req, size_t sz) -{ - h2o_req_prefilter_t *prefilter = h2o_mem_alloc_pool(&req->pool, sz); - prefilter->next = req->prefilters; - req->prefilters = prefilter; - return prefilter; -} - -h2o_ostream_t *h2o_add_ostream(h2o_req_t *req, size_t sz, h2o_ostream_t **slot) -{ - h2o_ostream_t *ostr = h2o_mem_alloc_pool(&req->pool, sz); - ostr->next = *slot; - ostr->do_send = NULL; - ostr->stop = NULL; - ostr->start_pull = NULL; - - *slot = ostr; - - return ostr; -} - -static void apply_env(h2o_req_t *req, h2o_envconf_t *env) -{ - size_t i; - - if (env->parent != NULL) - apply_env(req, env->parent); - for (i = 0; i != env->unsets.size; ++i) - h2o_req_unsetenv(req, env->unsets.entries[i].base, env->unsets.entries[i].len); - for (i = 0; i != env->sets.size; i += 2) - *h2o_req_getenv(req, env->sets.entries[i].base, env->sets.entries[i].len, 1) = env->sets.entries[i + 1]; -} - -void h2o_req_bind_conf(h2o_req_t *req, h2o_hostconf_t *hostconf, h2o_pathconf_t *pathconf) -{ - req->hostconf = hostconf; - req->pathconf = pathconf; - if (pathconf->env != NULL) - apply_env(req, pathconf->env); -} - -void h2o_ostream_send_next(h2o_ostream_t *ostream, h2o_req_t *req, h2o_iovec_t *bufs, size_t bufcnt, h2o_send_state_t state) -{ - if (!h2o_send_state_is_in_progress(state)) { - assert(req->_ostr_top == ostream); - req->_ostr_top = ostream->next; - } else if (bufcnt == 0) { - h2o_timeout_link(req->conn->ctx->loop, &req->conn->ctx->zero_timeout, &req->_timeout_entry); - return; - } - ostream->next->do_send(ostream->next, req, bufs, bufcnt, state); -} - -void h2o_req_fill_mime_attributes(h2o_req_t *req) -{ - ssize_t content_type_index; - h2o_mimemap_type_t *mime; - - if (req->res.mime_attr != NULL) - return; - - if ((content_type_index = h2o_find_header(&req->res.headers, H2O_TOKEN_CONTENT_TYPE, -1)) != -1 && - (mime = h2o_mimemap_get_type_by_mimetype(req->pathconf->mimemap, req->res.headers.entries[content_type_index].value, 0)) != - NULL) - req->res.mime_attr = &mime->data.attr; - else - req->res.mime_attr = &h2o_mime_attributes_as_is; -} - -void h2o_send_inline(h2o_req_t *req, const char *body, size_t len) -{ - static h2o_generator_t generator = {NULL, NULL}; - - h2o_iovec_t buf = h2o_strdup(&req->pool, body, len); - /* the function intentionally does not set the content length, since it may be used for generating 304 response, etc. */ - /* req->res.content_length = buf.len; */ - - h2o_start_response(req, &generator); - - if (h2o_memis(req->input.method.base, req->input.method.len, H2O_STRLIT("HEAD"))) - h2o_send(req, NULL, 0, H2O_SEND_STATE_FINAL); - else - h2o_send(req, &buf, 1, H2O_SEND_STATE_FINAL); -} - -void h2o_send_error_generic(h2o_req_t *req, int status, const char *reason, const char *body, int flags) -{ - if (req->pathconf == NULL) { - h2o_hostconf_t *hostconf = setup_before_processing(req); - h2o_req_bind_conf(req, hostconf, &hostconf->fallback_path); - } - - if ((flags & H2O_SEND_ERROR_HTTP1_CLOSE_CONNECTION) != 0) - req->http1_is_persistent = 0; - - req->res.status = status; - req->res.reason = reason; - req->res.content_length = strlen(body); - - if ((flags & H2O_SEND_ERROR_KEEP_HEADERS) == 0) - memset(&req->res.headers, 0, sizeof(req->res.headers)); - - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, NULL, H2O_STRLIT("text/plain; charset=utf-8")); - - h2o_send_inline(req, body, SIZE_MAX); -} - -#define DECL_SEND_ERROR_DEFERRED(status_) \ - static void send_error_deferred_cb_##status_(h2o_timeout_entry_t *entry) \ - { \ - struct st_send_error_deferred_t *args = H2O_STRUCT_FROM_MEMBER(struct st_send_error_deferred_t, _timeout, entry); \ - reset_response(args->req); \ - args->req->conn->ctx->emitted_error_status[H2O_STATUS_ERROR_##status_]++; \ - h2o_send_error_generic(args->req, args->status, args->reason, args->body, args->flags); \ - } \ - \ - static void h2o_send_error_deferred_##status_(h2o_req_t *req, const char *reason, const char *body, int flags) \ - { \ - struct st_send_error_deferred_t *args = h2o_mem_alloc_pool(&req->pool, sizeof(*args)); \ - *args = (struct st_send_error_deferred_t){req, status_, reason, body, flags}; \ - args->_timeout.cb = send_error_deferred_cb_##status_; \ - h2o_timeout_link(req->conn->ctx->loop, &req->conn->ctx->zero_timeout, &args->_timeout); \ - } - -DECL_SEND_ERROR_DEFERRED(502) - -#undef DECL_SEND_ERROR_DEFERRED - -void h2o_req_log_error(h2o_req_t *req, const char *module, const char *fmt, ...) -{ -#define INITIAL_BUF_SIZE 256 - - char *errbuf = h2o_mem_alloc_pool(&req->pool, INITIAL_BUF_SIZE); - int errlen; - va_list args; - - va_start(args, fmt); - errlen = vsnprintf(errbuf, INITIAL_BUF_SIZE, fmt, args); - va_end(args); - - if (errlen >= INITIAL_BUF_SIZE) { - errbuf = h2o_mem_alloc_pool(&req->pool, errlen + 1); - va_start(args, fmt); - errlen = vsnprintf(errbuf, errlen + 1, fmt, args); - va_end(args); - } - -#undef INITIAL_BUF_SIZE - - /* save the log */ - h2o_vector_reserve(&req->pool, &req->error_logs, req->error_logs.size + 1); - req->error_logs.entries[req->error_logs.size++] = (h2o_req_error_log_t){module, h2o_iovec_init(errbuf, errlen)}; - - if (req->pathconf->error_log.emit_request_errors) { - /* build prefix */ - char *prefix = alloca(sizeof("[] in request::") + 32 + strlen(module)), *p = prefix; - p += sprintf(p, "[%s] in request:", module); - if (req->path.len < 32) { - memcpy(p, req->path.base, req->path.len); - p += req->path.len; - } else { - memcpy(p, req->path.base, 29); - p += 29; - memcpy(p, "...", 3); - p += 3; - } - *p++ = ':'; - /* use writev(2) to emit error atomically */ - struct iovec vecs[] = {{prefix, p - prefix}, {errbuf, errlen}, {"\n", 1}}; - H2O_BUILD_ASSERT(sizeof(vecs) / sizeof(vecs[0]) < IOV_MAX); - writev(2, vecs, sizeof(vecs) / sizeof(vecs[0])); - } -} - -void h2o_send_redirect(h2o_req_t *req, int status, const char *reason, const char *url, size_t url_len) -{ - if (req->res_is_delegated) { - h2o_iovec_t method = h2o_get_redirect_method(req->method, status); - h2o_send_redirect_internal(req, method, url, url_len, 0); - return; - } - - static h2o_generator_t generator = {NULL, NULL}; - static const h2o_iovec_t body_prefix = {H2O_STRLIT("<!DOCTYPE html><TITLE>Moved</TITLE><P>The document has moved <A HREF=\"")}; - static const h2o_iovec_t body_suffix = {H2O_STRLIT("\">here</A>")}; - - /* build and send response */ - h2o_iovec_t bufs[3]; - size_t bufcnt; - if (h2o_memis(req->input.method.base, req->input.method.len, H2O_STRLIT("HEAD"))) { - req->res.content_length = SIZE_MAX; - bufcnt = 0; - } else { - bufs[0] = body_prefix; - bufs[1] = h2o_htmlescape(&req->pool, url, url_len); - bufs[2] = body_suffix; - bufcnt = 3; - req->res.content_length = body_prefix.len + bufs[1].len + body_suffix.len; - } - req->res.status = status; - req->res.reason = reason; - req->res.headers = (h2o_headers_t){NULL}; - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_LOCATION, NULL, url, url_len); - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, NULL, H2O_STRLIT("text/html; charset=utf-8")); - h2o_start_response(req, &generator); - h2o_send(req, bufs, bufcnt, H2O_SEND_STATE_FINAL); -} - -void h2o_send_redirect_internal(h2o_req_t *req, h2o_iovec_t method, const char *url_str, size_t url_len, int preserve_overrides) -{ - h2o_url_t url; - - /* parse the location URL */ - if (h2o_url_parse_relative(url_str, url_len, &url) != 0) { - /* TODO log fprintf(stderr, "[proxy] cannot handle location header: %.*s\n", (int)url_len, url); */ - h2o_send_error_deferred_502(req, "Gateway Error", "internal error", 0); - return; - } - /* convert the location to absolute (while creating copies of the values passed to the deferred call) */ - if (url.scheme == NULL) - url.scheme = req->scheme; - if (url.authority.base == NULL) { - if (req->hostconf != NULL) - url.authority = req->hostconf->authority.hostport; - else - url.authority = req->authority; - } else { - if (h2o_lcstris(url.authority.base, url.authority.len, req->authority.base, req->authority.len)) { - url.authority = req->authority; - } else { - url.authority = h2o_strdup(&req->pool, url.authority.base, url.authority.len); - preserve_overrides = 0; - } - } - h2o_iovec_t base_path = req->path; - h2o_url_resolve_path(&base_path, &url.path); - url.path = h2o_concat(&req->pool, base_path, url.path); - - h2o_reprocess_request_deferred(req, method, url.scheme, url.authority, url.path, preserve_overrides ? req->overrides : NULL, 1); -} - -h2o_iovec_t h2o_get_redirect_method(h2o_iovec_t method, int status) -{ - if (h2o_memis(method.base, method.len, H2O_STRLIT("POST")) && !(status == 307 || status == 308)) - method = h2o_iovec_init(H2O_STRLIT("GET")); - return method; -} - -h2o_iovec_t h2o_push_path_in_link_header(h2o_req_t *req, const char *value, size_t value_len) -{ - int i; - h2o_iovec_t ret = h2o_iovec_init(value, value_len); - if (req->conn->callbacks->push_path == NULL) - return ret; - - h2o_iovec_vector_t paths = h2o_extract_push_path_from_link_header( - &req->pool, value, value_len, req->path_normalized, req->input.scheme, req->input.authority, - req->res_is_delegated ? req->scheme : NULL, req->res_is_delegated ? &req->authority : NULL, &ret); - if (paths.size == 0) - return ret; - - for (i = 0; i < paths.size; i++) { - req->conn->callbacks->push_path(req, paths.entries[i].base, paths.entries[i].len); - } - return ret; -} diff --git a/web/server/h2o/libh2o/lib/core/token.c b/web/server/h2o/libh2o/lib/core/token.c deleted file mode 100644 index e21ce2383..000000000 --- a/web/server/h2o/libh2o/lib/core/token.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2014 DeNA Co., Ltd. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#include "h2o.h" -#include "token_table.h" - -int h2o_iovec_is_token(const h2o_iovec_t *buf) -{ - return &h2o__tokens[0].buf <= buf && buf <= &h2o__tokens[H2O_MAX_TOKENS - 1].buf; -} diff --git a/web/server/h2o/libh2o/lib/core/token_table.h b/web/server/h2o/libh2o/lib/core/token_table.h deleted file mode 100644 index ae26aa6c4..000000000 --- a/web/server/h2o/libh2o/lib/core/token_table.h +++ /dev/null @@ -1,408 +0,0 @@ -/* - * Copyright (c) 2014 DeNA Co., Ltd. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -/* DO NOT EDIT! generated by tokens.pl */ -h2o_token_t h2o__tokens[] = {{{H2O_STRLIT(":authority")}, 1, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT(":method")}, 2, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT(":path")}, 4, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT(":scheme")}, 6, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT(":status")}, 8, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("accept")}, 19, 0, 0, 0, 0, 1, 0}, - {{H2O_STRLIT("accept-charset")}, 15, 0, 0, 0, 0, 1, 0}, - {{H2O_STRLIT("accept-encoding")}, 16, 0, 0, 0, 0, 1, 0}, - {{H2O_STRLIT("accept-language")}, 17, 0, 0, 0, 0, 1, 0}, - {{H2O_STRLIT("accept-ranges")}, 18, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("access-control-allow-origin")}, 20, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("age")}, 21, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("allow")}, 22, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("authorization")}, 23, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("cache-control")}, 24, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("cache-digest")}, 0, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("connection")}, 0, 1, 1, 0, 1, 0, 0}, - {{H2O_STRLIT("content-disposition")}, 25, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("content-encoding")}, 26, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("content-language")}, 27, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("content-length")}, 28, 0, 0, 1, 0, 0, 0}, - {{H2O_STRLIT("content-location")}, 29, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("content-range")}, 30, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("content-type")}, 31, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("cookie")}, 32, 0, 0, 0, 0, 0, 1}, - {{H2O_STRLIT("date")}, 33, 0, 1, 0, 0, 0, 0}, - {{H2O_STRLIT("etag")}, 34, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("expect")}, 35, 0, 0, 1, 0, 0, 0}, - {{H2O_STRLIT("expires")}, 36, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("from")}, 37, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("host")}, 38, 0, 0, 1, 1, 0, 0}, - {{H2O_STRLIT("http2-settings")}, 0, 1, 0, 0, 1, 0, 0}, - {{H2O_STRLIT("if-match")}, 39, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("if-modified-since")}, 40, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("if-none-match")}, 41, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("if-range")}, 42, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("if-unmodified-since")}, 43, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("keep-alive")}, 0, 1, 1, 0, 0, 0, 0}, - {{H2O_STRLIT("last-modified")}, 44, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("link")}, 45, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("location")}, 46, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("max-forwards")}, 47, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("proxy-authenticate")}, 48, 1, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("proxy-authorization")}, 49, 1, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("range")}, 50, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("referer")}, 51, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("refresh")}, 52, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("retry-after")}, 53, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("server")}, 54, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("set-cookie")}, 55, 0, 0, 0, 0, 0, 1}, - {{H2O_STRLIT("strict-transport-security")}, 56, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("te")}, 0, 1, 0, 0, 1, 0, 0}, - {{H2O_STRLIT("transfer-encoding")}, 57, 1, 1, 1, 1, 0, 0}, - {{H2O_STRLIT("upgrade")}, 0, 1, 1, 1, 1, 0, 0}, - {{H2O_STRLIT("user-agent")}, 58, 0, 0, 0, 0, 1, 0}, - {{H2O_STRLIT("vary")}, 59, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("via")}, 60, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("www-authenticate")}, 61, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("x-compress-hint")}, 0, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("x-forwarded-for")}, 0, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("x-reproxy-url")}, 0, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("x-traffic")}, 0, 0, 0, 0, 0, 0, 0}}; -size_t h2o__num_tokens = 62; - -const h2o_token_t *h2o_lookup_token(const char *name, size_t len) -{ - switch (len) { - case 2: - switch (name[1]) { - case 'e': - if (memcmp(name, "t", 1) == 0) - return H2O_TOKEN_TE; - break; - } - break; - case 3: - switch (name[2]) { - case 'a': - if (memcmp(name, "vi", 2) == 0) - return H2O_TOKEN_VIA; - break; - case 'e': - if (memcmp(name, "ag", 2) == 0) - return H2O_TOKEN_AGE; - break; - } - break; - case 4: - switch (name[3]) { - case 'e': - if (memcmp(name, "dat", 3) == 0) - return H2O_TOKEN_DATE; - break; - case 'g': - if (memcmp(name, "eta", 3) == 0) - return H2O_TOKEN_ETAG; - break; - case 'k': - if (memcmp(name, "lin", 3) == 0) - return H2O_TOKEN_LINK; - break; - case 'm': - if (memcmp(name, "fro", 3) == 0) - return H2O_TOKEN_FROM; - break; - case 't': - if (memcmp(name, "hos", 3) == 0) - return H2O_TOKEN_HOST; - break; - case 'y': - if (memcmp(name, "var", 3) == 0) - return H2O_TOKEN_VARY; - break; - } - break; - case 5: - switch (name[4]) { - case 'e': - if (memcmp(name, "rang", 4) == 0) - return H2O_TOKEN_RANGE; - break; - case 'h': - if (memcmp(name, ":pat", 4) == 0) - return H2O_TOKEN_PATH; - break; - case 'w': - if (memcmp(name, "allo", 4) == 0) - return H2O_TOKEN_ALLOW; - break; - } - break; - case 6: - switch (name[5]) { - case 'e': - if (memcmp(name, "cooki", 5) == 0) - return H2O_TOKEN_COOKIE; - break; - case 'r': - if (memcmp(name, "serve", 5) == 0) - return H2O_TOKEN_SERVER; - break; - case 't': - if (memcmp(name, "accep", 5) == 0) - return H2O_TOKEN_ACCEPT; - if (memcmp(name, "expec", 5) == 0) - return H2O_TOKEN_EXPECT; - break; - } - break; - case 7: - switch (name[6]) { - case 'd': - if (memcmp(name, ":metho", 6) == 0) - return H2O_TOKEN_METHOD; - break; - case 'e': - if (memcmp(name, ":schem", 6) == 0) - return H2O_TOKEN_SCHEME; - if (memcmp(name, "upgrad", 6) == 0) - return H2O_TOKEN_UPGRADE; - break; - case 'h': - if (memcmp(name, "refres", 6) == 0) - return H2O_TOKEN_REFRESH; - break; - case 'r': - if (memcmp(name, "refere", 6) == 0) - return H2O_TOKEN_REFERER; - break; - case 's': - if (memcmp(name, ":statu", 6) == 0) - return H2O_TOKEN_STATUS; - if (memcmp(name, "expire", 6) == 0) - return H2O_TOKEN_EXPIRES; - break; - } - break; - case 8: - switch (name[7]) { - case 'e': - if (memcmp(name, "if-rang", 7) == 0) - return H2O_TOKEN_IF_RANGE; - break; - case 'h': - if (memcmp(name, "if-matc", 7) == 0) - return H2O_TOKEN_IF_MATCH; - break; - case 'n': - if (memcmp(name, "locatio", 7) == 0) - return H2O_TOKEN_LOCATION; - break; - } - break; - case 9: - switch (name[8]) { - case 'c': - if (memcmp(name, "x-traffi", 8) == 0) - return H2O_TOKEN_X_TRAFFIC; - break; - } - break; - case 10: - switch (name[9]) { - case 'e': - if (memcmp(name, "keep-aliv", 9) == 0) - return H2O_TOKEN_KEEP_ALIVE; - if (memcmp(name, "set-cooki", 9) == 0) - return H2O_TOKEN_SET_COOKIE; - break; - case 'n': - if (memcmp(name, "connectio", 9) == 0) - return H2O_TOKEN_CONNECTION; - break; - case 't': - if (memcmp(name, "user-agen", 9) == 0) - return H2O_TOKEN_USER_AGENT; - break; - case 'y': - if (memcmp(name, ":authorit", 9) == 0) - return H2O_TOKEN_AUTHORITY; - break; - } - break; - case 11: - switch (name[10]) { - case 'r': - if (memcmp(name, "retry-afte", 10) == 0) - return H2O_TOKEN_RETRY_AFTER; - break; - } - break; - case 12: - switch (name[11]) { - case 'e': - if (memcmp(name, "content-typ", 11) == 0) - return H2O_TOKEN_CONTENT_TYPE; - break; - case 's': - if (memcmp(name, "max-forward", 11) == 0) - return H2O_TOKEN_MAX_FORWARDS; - break; - case 't': - if (memcmp(name, "cache-diges", 11) == 0) - return H2O_TOKEN_CACHE_DIGEST; - break; - } - break; - case 13: - switch (name[12]) { - case 'd': - if (memcmp(name, "last-modifie", 12) == 0) - return H2O_TOKEN_LAST_MODIFIED; - break; - case 'e': - if (memcmp(name, "content-rang", 12) == 0) - return H2O_TOKEN_CONTENT_RANGE; - break; - case 'h': - if (memcmp(name, "if-none-matc", 12) == 0) - return H2O_TOKEN_IF_NONE_MATCH; - break; - case 'l': - if (memcmp(name, "cache-contro", 12) == 0) - return H2O_TOKEN_CACHE_CONTROL; - if (memcmp(name, "x-reproxy-ur", 12) == 0) - return H2O_TOKEN_X_REPROXY_URL; - break; - case 'n': - if (memcmp(name, "authorizatio", 12) == 0) - return H2O_TOKEN_AUTHORIZATION; - break; - case 's': - if (memcmp(name, "accept-range", 12) == 0) - return H2O_TOKEN_ACCEPT_RANGES; - break; - } - break; - case 14: - switch (name[13]) { - case 'h': - if (memcmp(name, "content-lengt", 13) == 0) - return H2O_TOKEN_CONTENT_LENGTH; - break; - case 's': - if (memcmp(name, "http2-setting", 13) == 0) - return H2O_TOKEN_HTTP2_SETTINGS; - break; - case 't': - if (memcmp(name, "accept-charse", 13) == 0) - return H2O_TOKEN_ACCEPT_CHARSET; - break; - } - break; - case 15: - switch (name[14]) { - case 'e': - if (memcmp(name, "accept-languag", 14) == 0) - return H2O_TOKEN_ACCEPT_LANGUAGE; - break; - case 'g': - if (memcmp(name, "accept-encodin", 14) == 0) - return H2O_TOKEN_ACCEPT_ENCODING; - break; - case 'r': - if (memcmp(name, "x-forwarded-fo", 14) == 0) - return H2O_TOKEN_X_FORWARDED_FOR; - break; - case 't': - if (memcmp(name, "x-compress-hin", 14) == 0) - return H2O_TOKEN_X_COMPRESS_HINT; - break; - } - break; - case 16: - switch (name[15]) { - case 'e': - if (memcmp(name, "content-languag", 15) == 0) - return H2O_TOKEN_CONTENT_LANGUAGE; - if (memcmp(name, "www-authenticat", 15) == 0) - return H2O_TOKEN_WWW_AUTHENTICATE; - break; - case 'g': - if (memcmp(name, "content-encodin", 15) == 0) - return H2O_TOKEN_CONTENT_ENCODING; - break; - case 'n': - if (memcmp(name, "content-locatio", 15) == 0) - return H2O_TOKEN_CONTENT_LOCATION; - break; - } - break; - case 17: - switch (name[16]) { - case 'e': - if (memcmp(name, "if-modified-sinc", 16) == 0) - return H2O_TOKEN_IF_MODIFIED_SINCE; - break; - case 'g': - if (memcmp(name, "transfer-encodin", 16) == 0) - return H2O_TOKEN_TRANSFER_ENCODING; - break; - } - break; - case 18: - switch (name[17]) { - case 'e': - if (memcmp(name, "proxy-authenticat", 17) == 0) - return H2O_TOKEN_PROXY_AUTHENTICATE; - break; - } - break; - case 19: - switch (name[18]) { - case 'e': - if (memcmp(name, "if-unmodified-sinc", 18) == 0) - return H2O_TOKEN_IF_UNMODIFIED_SINCE; - break; - case 'n': - if (memcmp(name, "content-dispositio", 18) == 0) - return H2O_TOKEN_CONTENT_DISPOSITION; - if (memcmp(name, "proxy-authorizatio", 18) == 0) - return H2O_TOKEN_PROXY_AUTHORIZATION; - break; - } - break; - case 25: - switch (name[24]) { - case 'y': - if (memcmp(name, "strict-transport-securit", 24) == 0) - return H2O_TOKEN_STRICT_TRANSPORT_SECURITY; - break; - } - break; - case 27: - switch (name[26]) { - case 'n': - if (memcmp(name, "access-control-allow-origi", 26) == 0) - return H2O_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN; - break; - } - break; - } - - return NULL; -} diff --git a/web/server/h2o/libh2o/lib/core/util.c b/web/server/h2o/libh2o/lib/core/util.c deleted file mode 100644 index 50d2b2493..000000000 --- a/web/server/h2o/libh2o/lib/core/util.c +++ /dev/null @@ -1,562 +0,0 @@ -/* - * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Satoh Hiroh - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#include <assert.h> -#include <inttypes.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include "h2o.h" -#include "h2o/http1.h" -#include "h2o/http2.h" - -struct st_h2o_accept_data_t { - h2o_accept_ctx_t *ctx; - h2o_socket_t *sock; - h2o_timeout_entry_t timeout; - h2o_memcached_req_t *async_resumption_get_req; - struct timeval connected_at; -}; - -static void on_accept_timeout(h2o_timeout_entry_t *entry); - -static struct st_h2o_accept_data_t *create_accept_data(h2o_accept_ctx_t *ctx, h2o_socket_t *sock, struct timeval connected_at) -{ - struct st_h2o_accept_data_t *data = h2o_mem_alloc(sizeof(*data)); - - data->ctx = ctx; - data->sock = sock; - data->timeout = (h2o_timeout_entry_t){0}; - data->timeout.cb = on_accept_timeout; - h2o_timeout_link(ctx->ctx->loop, &ctx->ctx->handshake_timeout, &data->timeout); - data->async_resumption_get_req = NULL; - data->connected_at = connected_at; - - sock->data = data; - return data; -} - -static void free_accept_data(struct st_h2o_accept_data_t *data) -{ - assert(data->async_resumption_get_req == NULL); - h2o_timeout_unlink(&data->timeout); - free(data); -} - -static struct { - h2o_memcached_context_t *memc; - unsigned expiration; -} async_resumption_context; - -static void async_resumption_on_get(h2o_iovec_t session_data, void *_accept_data) -{ - struct st_h2o_accept_data_t *accept_data = _accept_data; - accept_data->async_resumption_get_req = NULL; - h2o_socket_ssl_resume_server_handshake(accept_data->sock, session_data); -} - -static void async_resumption_get(h2o_socket_t *sock, h2o_iovec_t session_id) -{ - struct st_h2o_accept_data_t *data = sock->data; - - data->async_resumption_get_req = - h2o_memcached_get(async_resumption_context.memc, data->ctx->libmemcached_receiver, session_id, async_resumption_on_get, - data, H2O_MEMCACHED_ENCODE_KEY | H2O_MEMCACHED_ENCODE_VALUE); -} - -static void async_resumption_new(h2o_iovec_t session_id, h2o_iovec_t session_data) -{ - h2o_memcached_set(async_resumption_context.memc, session_id, session_data, - (uint32_t)time(NULL) + async_resumption_context.expiration, - H2O_MEMCACHED_ENCODE_KEY | H2O_MEMCACHED_ENCODE_VALUE); -} - -void h2o_accept_setup_async_ssl_resumption(h2o_memcached_context_t *memc, unsigned expiration) -{ - async_resumption_context.memc = memc; - async_resumption_context.expiration = expiration; - h2o_socket_ssl_async_resumption_init(async_resumption_get, async_resumption_new); -} - -void on_accept_timeout(h2o_timeout_entry_t *entry) -{ - /* TODO log */ - struct st_h2o_accept_data_t *data = H2O_STRUCT_FROM_MEMBER(struct st_h2o_accept_data_t, timeout, entry); - if (data->async_resumption_get_req != NULL) { - h2o_memcached_cancel_get(async_resumption_context.memc, data->async_resumption_get_req); - data->async_resumption_get_req = NULL; - } - h2o_socket_t *sock = data->sock; - free_accept_data(data); - h2o_socket_close(sock); -} - -static void on_ssl_handshake_complete(h2o_socket_t *sock, const char *err) -{ - struct st_h2o_accept_data_t *data = sock->data; - sock->data = NULL; - - if (err != NULL) { - h2o_socket_close(sock); - goto Exit; - } - - h2o_iovec_t proto = h2o_socket_ssl_get_selected_protocol(sock); - const h2o_iovec_t *ident; - for (ident = h2o_http2_alpn_protocols; ident->len != 0; ++ident) { - if (proto.len == ident->len && memcmp(proto.base, ident->base, proto.len) == 0) { - /* connect as http2 */ - h2o_http2_accept(data->ctx, sock, data->connected_at); - goto Exit; - } - } - /* connect as http1 */ - h2o_http1_accept(data->ctx, sock, data->connected_at); - -Exit: - free_accept_data(data); -} - -static ssize_t parse_proxy_line(char *src, size_t len, struct sockaddr *sa, socklen_t *salen) -{ -#define CHECK_EOF() \ - if (p == end) \ - return -2 -#define EXPECT_CHAR(ch) \ - do { \ - CHECK_EOF(); \ - if (*p++ != ch) \ - return -1; \ - } while (0) -#define SKIP_TO_WS() \ - do { \ - do { \ - CHECK_EOF(); \ - } while (*p++ != ' '); \ - --p; \ - } while (0) - - char *p = src, *end = p + len; - void *addr; - in_port_t *port; - - /* "PROXY "*/ - EXPECT_CHAR('P'); - EXPECT_CHAR('R'); - EXPECT_CHAR('O'); - EXPECT_CHAR('X'); - EXPECT_CHAR('Y'); - EXPECT_CHAR(' '); - - /* "TCP[46] " */ - CHECK_EOF(); - if (*p++ != 'T') { - *salen = 0; /* indicate that no data has been obtained */ - goto SkipToEOL; - } - EXPECT_CHAR('C'); - EXPECT_CHAR('P'); - CHECK_EOF(); - switch (*p++) { - case '4': - *salen = sizeof(struct sockaddr_in); - memset(sa, 0, sizeof(struct sockaddr_in)); - sa->sa_family = AF_INET; - addr = &((struct sockaddr_in *)sa)->sin_addr; - port = &((struct sockaddr_in *)sa)->sin_port; - break; - case '6': - *salen = sizeof(struct sockaddr_in6); - memset(sa, 0, sizeof(struct sockaddr_in6)); - sa->sa_family = AF_INET6; - addr = &((struct sockaddr_in6 *)sa)->sin6_addr; - port = &((struct sockaddr_in6 *)sa)->sin6_port; - break; - default: - return -1; - } - EXPECT_CHAR(' '); - - /* parse peer address */ - char *addr_start = p; - SKIP_TO_WS(); - *p = '\0'; - if (inet_pton(sa->sa_family, addr_start, addr) != 1) - return -1; - *p++ = ' '; - - /* skip local address */ - SKIP_TO_WS(); - ++p; - - /* parse peer port */ - char *port_start = p; - SKIP_TO_WS(); - *p = '\0'; - unsigned short usval; - if (sscanf(port_start, "%hu", &usval) != 1) - return -1; - *port = htons(usval); - *p++ = ' '; - -SkipToEOL: - do { - CHECK_EOF(); - } while (*p++ != '\r'); - CHECK_EOF(); - if (*p++ != '\n') - return -2; - return p - src; - -#undef CHECK_EOF -#undef EXPECT_CHAR -#undef SKIP_TO_WS -} - -static void on_read_proxy_line(h2o_socket_t *sock, const char *err) -{ - struct st_h2o_accept_data_t *data = sock->data; - - if (err != NULL) { - free_accept_data(data); - h2o_socket_close(sock); - return; - } - - struct sockaddr_storage addr; - socklen_t addrlen; - ssize_t r = parse_proxy_line(sock->input->bytes, sock->input->size, (void *)&addr, &addrlen); - switch (r) { - case -1: /* error, just pass the input to the next handler */ - break; - case -2: /* incomplete */ - return; - default: - h2o_buffer_consume(&sock->input, r); - if (addrlen != 0) - h2o_socket_setpeername(sock, (void *)&addr, addrlen); - break; - } - - if (data->ctx->ssl_ctx != NULL) { - h2o_socket_ssl_handshake(sock, data->ctx->ssl_ctx, NULL, on_ssl_handshake_complete); - } else { - struct st_h2o_accept_data_t *data = sock->data; - sock->data = NULL; - h2o_http1_accept(data->ctx, sock, data->connected_at); - free_accept_data(data); - } -} - -void h2o_accept(h2o_accept_ctx_t *ctx, h2o_socket_t *sock) -{ - struct timeval connected_at = *h2o_get_timestamp(ctx->ctx, NULL, NULL); - - if (ctx->expect_proxy_line || ctx->ssl_ctx != NULL) { - create_accept_data(ctx, sock, connected_at); - if (ctx->expect_proxy_line) { - h2o_socket_read_start(sock, on_read_proxy_line); - } else { - h2o_socket_ssl_handshake(sock, ctx->ssl_ctx, NULL, on_ssl_handshake_complete); - } - } else { - h2o_http1_accept(ctx, sock, connected_at); - } -} - -size_t h2o_stringify_protocol_version(char *dst, int version) -{ - char *p = dst; - - if (version < 0x200) { - assert(version <= 0x109); -#define PREFIX "HTTP/1." - memcpy(p, PREFIX, sizeof(PREFIX) - 1); - p += sizeof(PREFIX) - 1; -#undef PREFIX - *p++ = '0' + (version & 0xff); - } else { -#define PROTO "HTTP/2" - memcpy(p, PROTO, sizeof(PROTO) - 1); - p += sizeof(PROTO) - 1; -#undef PROTO - } - - *p = '\0'; - return p - dst; -} - -size_t h2o_stringify_proxy_header(h2o_conn_t *conn, char *buf) -{ - struct sockaddr_storage ss; - socklen_t sslen; - size_t strlen; - uint16_t peerport; - char *dst = buf; - - if ((sslen = conn->callbacks->get_peername(conn, (void *)&ss)) == 0) - goto Unknown; - switch (ss.ss_family) { - case AF_INET: - memcpy(dst, "PROXY TCP4 ", 11); - dst += 11; - break; - case AF_INET6: - memcpy(dst, "PROXY TCP6 ", 11); - dst += 11; - break; - default: - goto Unknown; - } - if ((strlen = h2o_socket_getnumerichost((void *)&ss, sslen, dst)) == SIZE_MAX) - goto Unknown; - dst += strlen; - *dst++ = ' '; - - peerport = h2o_socket_getport((void *)&ss); - - if ((sslen = conn->callbacks->get_sockname(conn, (void *)&ss)) == 0) - goto Unknown; - if ((strlen = h2o_socket_getnumerichost((void *)&ss, sslen, dst)) == SIZE_MAX) - goto Unknown; - dst += strlen; - *dst++ = ' '; - - dst += sprintf(dst, "%" PRIu16 " %" PRIu16 "\r\n", peerport, (uint16_t)h2o_socket_getport((void *)&ss)); - - return dst - buf; - -Unknown: - memcpy(buf, "PROXY UNKNOWN\r\n", 15); - return 15; -} - -static void push_one_path(h2o_mem_pool_t *pool, h2o_iovec_vector_t *paths_to_push, h2o_iovec_t url, h2o_iovec_t base_path, - const h2o_url_scheme_t *input_scheme, h2o_iovec_t input_authority, const h2o_url_scheme_t *base_scheme, - h2o_iovec_t *base_authority) -{ - h2o_url_t parsed, resolved; - - /* check the authority, and extract absolute path */ - if (h2o_url_parse_relative(url.base, url.len, &parsed) != 0) - return; - - /* fast-path for abspath form */ - if (base_scheme == NULL && parsed.scheme == NULL && parsed.authority.base == NULL && url.len != 0 && url.base[0] == '/') { - h2o_vector_reserve(pool, paths_to_push, paths_to_push->size + 1); - paths_to_push->entries[paths_to_push->size++] = h2o_strdup(pool, url.base, url.len); - return; - } - - /* check scheme and authority if given URL contains either of the two, or if base is specified */ - h2o_url_t base = {input_scheme, input_authority, {NULL}, base_path, 65535}; - if (base_scheme != NULL) { - base.scheme = base_scheme; - base.authority = *base_authority; - } - h2o_url_resolve(pool, &base, &parsed, &resolved); - if (input_scheme != resolved.scheme) - return; - if (!h2o_lcstris(input_authority.base, input_authority.len, resolved.authority.base, resolved.authority.len)) - return; - - h2o_vector_reserve(pool, paths_to_push, paths_to_push->size + 1); - paths_to_push->entries[paths_to_push->size++] = resolved.path; -} - -h2o_iovec_vector_t h2o_extract_push_path_from_link_header(h2o_mem_pool_t *pool, const char *value, size_t value_len, - h2o_iovec_t base_path, const h2o_url_scheme_t *input_scheme, - h2o_iovec_t input_authority, const h2o_url_scheme_t *base_scheme, - h2o_iovec_t *base_authority, h2o_iovec_t *filtered_value) -{ - h2o_iovec_vector_t paths_to_push = {NULL}; - h2o_iovec_t iter = h2o_iovec_init(value, value_len), token_value; - const char *token; - size_t token_len; - *filtered_value = h2o_iovec_init(NULL, 0); - -#define PUSH_FILTERED_VALUE(s, e) \ - do { \ - if (filtered_value->len != 0) { \ - memcpy(filtered_value->base + filtered_value->len, ", ", 2); \ - filtered_value->len += 2; \ - } \ - memcpy(filtered_value->base + filtered_value->len, (s), (e) - (s)); \ - filtered_value->len += (e) - (s); \ - } while (0) - - /* extract URL values from Link: </pushed.css>; rel=preload */ - do { - if ((token = h2o_next_token(&iter, ';', &token_len, NULL)) == NULL) - break; - /* first element should be <URL> */ - if (!(token_len >= 2 && token[0] == '<' && token[token_len - 1] == '>')) - break; - h2o_iovec_t url_with_brackets = h2o_iovec_init(token, token_len); - /* find rel=preload */ - int preload = 0, nopush = 0, push_only = 0; - while ((token = h2o_next_token(&iter, ';', &token_len, &token_value)) != NULL && - !h2o_memis(token, token_len, H2O_STRLIT(","))) { - if (h2o_lcstris(token, token_len, H2O_STRLIT("rel")) && - h2o_lcstris(token_value.base, token_value.len, H2O_STRLIT("preload"))) { - preload++; - } else if (h2o_lcstris(token, token_len, H2O_STRLIT("nopush"))) { - nopush++; - } else if (h2o_lcstris(token, token_len, H2O_STRLIT("x-http2-push-only"))) { - push_only++; - } - } - /* push the path */ - if (!nopush && preload) - push_one_path(pool, &paths_to_push, h2o_iovec_init(url_with_brackets.base + 1, url_with_brackets.len - 2), base_path, - input_scheme, input_authority, base_scheme, base_authority); - /* store the elements that needs to be preserved to filtered_value */ - if (push_only) { - if (filtered_value->base == NULL) { - /* the max. size of filtered_value would be x2 in the worst case, when "," is converted to ", " */ - filtered_value->base = h2o_mem_alloc_pool(pool, value_len * 2); - const char *prev_comma = h2o_memrchr(value, ',', url_with_brackets.base - value); - if (prev_comma != NULL) - PUSH_FILTERED_VALUE(value, prev_comma); - } - } else if (filtered_value->base != NULL) { - PUSH_FILTERED_VALUE(url_with_brackets.base, token != NULL ? token : value + value_len); - } - } while (token != NULL); - - if (filtered_value->base != NULL) { - if (token != NULL) - PUSH_FILTERED_VALUE(token, value + value_len); - } else { - *filtered_value = h2o_iovec_init(value, value_len); - } - - return paths_to_push; - -#undef PUSH_FILTERED_VALUE -} - -int h2o_get_compressible_types(const h2o_headers_t *headers) -{ - size_t header_index; - int compressible_types = 0; - - for (header_index = 0; header_index != headers->size; ++header_index) { - const h2o_header_t *header = headers->entries + header_index; - if (H2O_UNLIKELY(header->name == &H2O_TOKEN_ACCEPT_ENCODING->buf)) { - h2o_iovec_t iter = h2o_iovec_init(header->value.base, header->value.len); - const char *token = NULL; - size_t token_len = 0; - while ((token = h2o_next_token(&iter, ',', &token_len, NULL)) != NULL) { - if (h2o_lcstris(token, token_len, H2O_STRLIT("gzip"))) - compressible_types |= H2O_COMPRESSIBLE_GZIP; - else if (h2o_lcstris(token, token_len, H2O_STRLIT("br"))) - compressible_types |= H2O_COMPRESSIBLE_BROTLI; - } - } - } - - return compressible_types; -} - -h2o_iovec_t h2o_build_destination(h2o_req_t *req, const char *prefix, size_t prefix_len, int use_path_normalized) -{ - h2o_iovec_t parts[4]; - size_t num_parts = 0; - int conf_ends_with_slash = req->pathconf->path.base[req->pathconf->path.len - 1] == '/'; - int prefix_ends_with_slash = prefix[prefix_len - 1] == '/'; - - /* destination starts with given prefix */ - parts[num_parts++] = h2o_iovec_init(prefix, prefix_len); - - /* make adjustments depending on the trailing slashes */ - if (conf_ends_with_slash != prefix_ends_with_slash) { - if (conf_ends_with_slash) { - parts[num_parts++] = h2o_iovec_init(H2O_STRLIT("/")); - } else { - if (req->path_normalized.len != req->pathconf->path.len) - parts[num_parts - 1].len -= 1; - } - } - - /* append suffix path and query */ - - if (use_path_normalized) { - parts[num_parts++] = h2o_uri_escape(&req->pool, req->path_normalized.base + req->pathconf->path.len, - req->path_normalized.len - req->pathconf->path.len, "/@:"); - if (req->query_at != SIZE_MAX) { - parts[num_parts++] = h2o_iovec_init(req->path.base + req->query_at, req->path.len - req->query_at); - } - } else { - if (req->path.len > 1) { - /* - * When proxying, we want to modify the input URL as little - * as possible. We use norm_indexes to find the start of - * the path we want to forward. - */ - size_t next_unnormalized; - if (req->norm_indexes && req->pathconf->path.len > 1) { - next_unnormalized = req->norm_indexes[req->pathconf->path.len - 1]; - } else { - next_unnormalized = req->pathconf->path.len; - } - - /* - * Special case: the input path didn't have any '/' including the first, - * so the first character is actually found at '0' - */ - if (req->path.base[0] != '/' && next_unnormalized == 1) { - next_unnormalized = 0; - } - parts[num_parts++] = (h2o_iovec_t){req->path.base + next_unnormalized, req->path.len - next_unnormalized}; - } - } - - return h2o_concat_list(&req->pool, parts, num_parts); -} - -/* h2-14 and h2-16 are kept for backwards compatibility, as they are often used */ -#define ALPN_ENTRY(s) \ - { \ - H2O_STRLIT(s) \ - } -#define ALPN_PROTOCOLS_CORE ALPN_ENTRY("h2"), ALPN_ENTRY("h2-16"), ALPN_ENTRY("h2-14") -#define NPN_PROTOCOLS_CORE \ - "\x02" \ - "h2" \ - "\x05" \ - "h2-16" \ - "\x05" \ - "h2-14" - -static const h2o_iovec_t http2_alpn_protocols[] = {ALPN_PROTOCOLS_CORE, {NULL}}; -const h2o_iovec_t *h2o_http2_alpn_protocols = http2_alpn_protocols; - -static const h2o_iovec_t alpn_protocols[] = {ALPN_PROTOCOLS_CORE, {H2O_STRLIT("http/1.1")}, {NULL}}; -const h2o_iovec_t *h2o_alpn_protocols = alpn_protocols; - -const char *h2o_http2_npn_protocols = NPN_PROTOCOLS_CORE; -const char *h2o_npn_protocols = NPN_PROTOCOLS_CORE "\x08" - "http/1.1"; - -uint64_t h2o_connection_id = 0; |