static int on_config_virtual_host(h2o_configurator_t *configurator, void *_config, const char *file, yoml_t *node) { h2o_global_configuration_t *config = _config; size_t i; if (node->type != YOML_TYPE_MAPPING) { h2o_config_print_error(configurator, file, node, "argument must be a mapping"); 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_host_configuration_t *host_config; if (key->type != YOML_TYPE_SCALAR) { h2o_config_print_error(configurator, file, key, "key (representing the hostname) must be a string"); return -1; } host_config = h2o_config_register_virtual_host(config, key->data.scalar); if (apply_commands(host_config, file, value, config) != 0) return -1; } return 0; }
static int on_config_mime_types(h2o_configurator_t *configurator, void *_config, const char *file, yoml_t *node) { h2o_host_configuration_t *host_config = _config; size_t i; if (node->type != YOML_TYPE_MAPPING) { h2o_config_print_error(configurator, file, node, "argument must be a mapping"); 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; if (key->type != YOML_TYPE_SCALAR) { h2o_config_print_error(configurator, file, key, "key (representing the extension) must be a string"); return -1; } if (value->type != YOML_TYPE_SCALAR) { h2o_config_print_error(configurator, file, node, "value (representing the mime-type) must be a string"); return -1; } h2o_define_mimetype(&host_config->mimemap, key->data.scalar, value->data.scalar); } return 0; }
static int on_config_files(h2o_configurator_t *configurator, void *_config, const char *file, yoml_t *node) { h2o_host_configuration_t *host_config = _config; size_t i; if (node->type != YOML_TYPE_MAPPING) { h2o_config_print_error(configurator, file, node, "argument must be a mapping"); 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; if (key->type != YOML_TYPE_SCALAR) { h2o_config_print_error(configurator, file, key, "key (representing the virtual path) must be a string"); return -1; } if (value->type != YOML_TYPE_SCALAR) { h2o_config_print_error(configurator, file, key, "value (representing the local path) must be a string"); return -1; } h2o_register_file_handler(host_config, key->data.scalar, value->data.scalar, "index.html" /* FIXME */); } return 0; }
static int assert_is_extension(h2o_configurator_command_t *cmd, const char *file, yoml_t *node) { if (node->type != YOML_TYPE_SCALAR) { h2o_config_print_error(cmd, file, node, "expected a scalar (extension)"); return -1; } if (node->data.scalar[0] != '.') { h2o_config_print_error(cmd, file, node, "given extension \"%s\" does not start with a \".\"", node->data.scalar); return -1; } return 0; }
static int assert_is_mimetype(h2o_configurator_command_t *cmd, const char *file, yoml_t *node) { if (node->type != YOML_TYPE_SCALAR) { h2o_config_print_error(cmd, file, node, "expected a scalar (mime-type)"); return -1; } if (strchr(node->data.scalar, '/') == NULL) { h2o_config_print_error(cmd, file, node, "the string \"%s\" does not look like a mime-type", node->data.scalar); return -1; } return 0; }
static int set_mimetypes(h2o_configurator_command_t *cmd, h2o_mimemap_t *mimemap, const char *file, 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, file, key) != 0) return -1; switch (value->type) { case YOML_TYPE_SCALAR: if (assert_is_extension(cmd, file, value) != 0) return -1; h2o_mimemap_set_type(mimemap, value->data.scalar + 1, key->data.scalar); 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, file, ext_node) != 0) return -1; h2o_mimemap_set_type(mimemap, ext_node->data.scalar + 1, key->data.scalar); } break; default: h2o_config_print_error(cmd, file, value, "only scalar or sequence of scalar is permitted at the value part of the argument"); return -1; } } return 0; }
ssize_t h2o_config_get_one_of(h2o_configurator_t *configurator, const char *file, 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_config_print_error(configurator, file, node, "argument must be one of: %s", candidates); return -1; }
static SSL_CTX *on_config_listen_setup_ssl(h2o_configurator_command_t *cmd, const char *config_file, yoml_t *config_node) { SSL_CTX *ssl_ctx = NULL; const char *cert_file = NULL, *key_file = NULL; yoml_t *t; /* parse */ if (config_node->type != YOML_TYPE_MAPPING) { h2o_config_print_error(cmd, config_file, config_node, "`ssl` is not a mapping"); goto Error; } if ((t = yoml_get(config_node, "certificate-file")) == NULL) { h2o_config_print_error(cmd, config_file, config_node, "could not find mandatory property `certificate-file`"); goto Error; } else if (t->type != YOML_TYPE_SCALAR) { h2o_config_print_error(cmd, config_file, t, "the property must be a string"); goto Error; } cert_file = t->data.scalar; if ((t = yoml_get(config_node, "key-file")) == NULL) { h2o_config_print_error(cmd, config_file, config_node, "could not find mandatory property `key-file`"); goto Error; } else if (t->type != YOML_TYPE_SCALAR) { h2o_config_print_error(cmd, config_file, t, "the property must be a string"); goto Error; } key_file = t->data.scalar; /* setup */ init_openssl(); ssl_ctx = SSL_CTX_new(SSLv23_server_method()); SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2); setup_ecc_key(ssl_ctx); if (SSL_CTX_use_certificate_file(ssl_ctx, cert_file, SSL_FILETYPE_PEM) != 1) { h2o_config_print_error(cmd, config_file, config_node, "failed to load certificate file:%s\n", cert_file); ERR_print_errors_fp(stderr); goto Error; } if (SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) { h2o_config_print_error(cmd, config_file, config_node, "failed to load private key file:%s\n", key_file); ERR_print_errors_fp(stderr); goto Error; } /* setup protocol negotiation methods */ #if H2O_USE_NPN h2o_ssl_register_npn_protocols(ssl_ctx, h2o_http2_npn_protocols); #endif #if H2O_USE_ALPN h2o_ssl_register_alpn_protocols(ssl_ctx, h2o_http2_alpn_protocols); #endif return ssl_ctx; Error: if (ssl_ctx != NULL) SSL_CTX_free(ssl_ctx); return NULL; }
static int apply_commands(void *config, const char *file, yoml_t *node, h2o_global_configuration_t *global_config) { yoml_t *key, *value; size_t i; if (node->type != YOML_TYPE_MAPPING) { h2o_config_print_error(NULL, file, node, "node must be a MAPPING"); return -1; } for (i = 0; i != node->data.mapping.size; ++i) { h2o_configurator_t *configurator; key = node->data.mapping.elements[i].key; value = node->data.mapping.elements[i].value; if (key->type != YOML_TYPE_SCALAR) { h2o_config_print_error(NULL, file, key, "command must be a string"); return -1; } if (config == global_config) { if ((configurator = h2o_config_get_configurator(&global_config->global_configurators, key->data.scalar)) != NULL) { if (configurator->on_cmd(configurator, config, file, value) != 0) return -1; } else if ((configurator = h2o_config_get_configurator(&global_config->host_configurators, key->data.scalar)) != NULL) { if (configurator->on_cmd(configurator, &global_config->default_host, file, value) != 0) return -1; } else { goto UnknownCommand; } } else { if ((configurator = h2o_config_get_configurator(&global_config->host_configurators, key->data.scalar)) == NULL) goto UnknownCommand; if (configurator->on_cmd(configurator, config, file, value) != 0) return -1; } } return 0; UnknownCommand: h2o_config_print_error(NULL, file, key, "unknown command: %s", key->data.scalar); return -1; }
int h2o_config_scanf(h2o_configurator_t *configurator, const char *file, 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_config_print_error(configurator, file, node, "argument must match the format: %s", fmt); return -1; }
static int on_config_index(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, const char *file, yoml_t *node) { struct st_h2o_file_configurator_t *self = (void*)cmd->configurator; size_t i; free(self->vars->index_files); self->vars->index_files = h2o_malloc(sizeof(self->vars->index_files[0]) * (node->data.sequence.size + 1)); for (i = 0; i != node->data.sequence.size; ++i) { yoml_t *element = node->data.sequence.elements[i]; if (element->type != YOML_TYPE_SCALAR) { h2o_config_print_error(cmd, file, element, "argument must be a sequence of scalars"); return -1; } self->vars->index_files[i] = element->data.scalar; } self->vars->index_files[i] = NULL; return 0; }
static int on_config_listen(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, const char *config_file, yoml_t *config_node) { struct config_t *conf = H2O_STRUCT_FROM_MEMBER(struct config_t, global_config, ctx->globalconf); const char *hostname = NULL, *servname = NULL; SSL_CTX *ssl_ctx = NULL; struct addrinfo hints, *res; int error; /* fetch servname (and hostname) */ switch (config_node->type) { case YOML_TYPE_SCALAR: servname = config_node->data.scalar; break; case YOML_TYPE_MAPPING: { yoml_t *t; if ((t = yoml_get(config_node, "host")) != NULL) { if (t->type != YOML_TYPE_SCALAR) { h2o_config_print_error(cmd, config_file, t, "`host` is not a string"); return -1; } hostname = t->data.scalar; } if ((t = yoml_get(config_node, "port")) == NULL) { h2o_config_print_error(cmd, config_file, config_node, "cannot find mandatory property `port`"); return -1; } if (t->type != YOML_TYPE_SCALAR) { h2o_config_print_error(cmd, config_file, config_node, "`port` is not a string"); return -1; } servname = t->data.scalar; if ((t = yoml_get(config_node, "ssl")) != NULL) { if ((ssl_ctx = on_config_listen_setup_ssl(cmd, config_file, t)) == NULL) return -1; } } break; default: h2o_config_print_error(cmd, config_file, config_node, "value must be a string or a mapping (with keys: `port` and optionally `host`)"); return -1; } /* call getaddrinfo */ memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV | AI_PASSIVE; if ((error = getaddrinfo(hostname, servname, &hints, &res)) != 0) { h2o_config_print_error(cmd, config_file, config_node, "failed to resolve the listening address: %s", gai_strerror(error)); return -1; } else if (res == NULL) { h2o_config_print_error(cmd, config_file, config_node, "failed to resolve the listening address: getaddrinfo returned an empty list"); return -1; } { /* save the entries */ struct addrinfo *ai; for (ai = res; ai != NULL; ai = ai->ai_next) { struct listener_config_t *listener = h2o_malloc(sizeof(*listener)); listener->fd = -1; listener->family = ai->ai_family; listener->socktype = ai->ai_socktype; listener->protocol = ai->ai_protocol; memcpy(&listener->addr, ai->ai_addr, ai->ai_addrlen); listener->addrlen = ai->ai_addrlen; listener->ssl_ctx = ssl_ctx; conf->listeners = h2o_realloc(conf->listeners, sizeof(*conf->listeners) * (conf->num_listeners + 1)); conf->listeners[conf->num_listeners++] = listener; } } /* release res */ freeaddrinfo(res); return 0; }