Esempio n. 1
0
static int create_spawnproc(h2o_configurator_command_t *cmd, yoml_t *node, const char *dirname, char *const *argv,
                            struct sockaddr_un *sa)
{
    int listen_fd, pipe_fds[2] = {-1, -1};

    /* build socket path */
    sa->sun_family = AF_UNIX;
    strcpy(sa->sun_path, dirname);
    strcat(sa->sun_path, "/_");

    /* create socket */
    if ((listen_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        h2o_configurator_errprintf(cmd, node, "socket(2) failed: %s", strerror(errno));
        goto Error;
    }
    if (bind(listen_fd, (void *)sa, sizeof(*sa)) != 0) {
        h2o_configurator_errprintf(cmd, node, "bind(2) failed: %s", strerror(errno));
        goto Error;
    }
    if (listen(listen_fd, SOMAXCONN) != 0) {
        h2o_configurator_errprintf(cmd, node, "listen(2) failed: %s", strerror(errno));
        goto Error;
    }

    /* create pipe which is used to notify the termination of the server */
    if (pipe(pipe_fds) != 0) {
        h2o_configurator_errprintf(cmd, node, "pipe(2) failed: %s", strerror(errno));
        pipe_fds[0] = -1;
        pipe_fds[1] = -1;
        goto Error;
    }
    fcntl(pipe_fds[1], F_SETFD, FD_CLOEXEC);

    /* spawn */
    int mapped_fds[] = {listen_fd, 0,   /* listen_fd to 0 */
                        pipe_fds[0], 5, /* pipe_fds[0] to 5 */
                        -1};
    pid_t pid = h2o_spawnp(argv[0], argv, mapped_fds, 0);
    if (pid == -1) {
        fprintf(stderr, "[lib/handler/fastcgi.c] failed to launch helper program %s:%s\n", argv[0], strerror(errno));
        goto Error;
    }

    close(listen_fd);
    listen_fd = -1;
    close(pipe_fds[0]);
    pipe_fds[0] = -1;

    return pipe_fds[1];

Error:
    if (pipe_fds[0] != -1)
        close(pipe_fds[0]);
    if (pipe_fds[1])
        close(pipe_fds[1]);
    if (listen_fd != -1)
        close(listen_fd);
    unlink(sa->sun_path);
    return -1;
}
Esempio n. 2
0
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;
        }
        ctx->hostconf = h2o_config_register_host(ctx->globalconf, hostname, port);
        if (h2o_configurator_apply_commands(ctx, value, H2O_CONFIGURATOR_FLAG_HOST, NULL) != 0)
            return -1;
        if (yoml_get(value, "paths") == NULL) {
            h2o_configurator_errprintf(NULL, value, "mandatory configuration directive `paths` is missing");
            return -1;
        }
        ctx->hostconf = NULL;
    }

    return 0;
}
Esempio n. 3
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;
}
Esempio n. 4
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;
}
Esempio n. 5
0
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]),
          (void *)sort_from_longer_paths);

    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;
        ctx->pathconf = h2o_config_register_path(ctx->hostconf, key->data.scalar);
        if (h2o_configurator_apply_commands(ctx, value, H2O_CONFIGURATOR_FLAG_PATH, NULL) != 0)
            return -1;
        ctx->pathconf = NULL;
    }

    return 0;
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
static int on_config_spawn(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node)
{
    struct fastcgi_configurator_t *self = (void *)cmd->configurator;
    char dirname[] = "/tmp/h2o.fcgisock.XXXXXX";
    char *argv[] = {h2o_configurator_get_cmd_path("share/h2o/kill-on-close"), "--rm", dirname, "--", "/bin/sh", "-c",
                    node->data.scalar, NULL};
    int spawner_fd;
    struct sockaddr_un sun = {};
    h2o_fastcgi_config_vars_t config_vars;
    int ret = -1;

    /* create temporary directory */
    if (mkdtemp(dirname) == NULL) {
        h2o_configurator_errprintf(cmd, node, "mkdtemp(3) failed to create temporary directory:%s:%s", dirname, strerror(errno));
        dirname[0] = '\0';
        goto Exit;
    }

    /* launch spawnfcgi command */
    if ((spawner_fd = create_spawnproc(cmd, node, dirname, argv, &sun)) == -1) {
        goto Exit;
    }

    config_vars = *self->vars;
    config_vars.callbacks.dispose = spawnproc_on_dispose;
    config_vars.callbacks.data = (char *)NULL + spawner_fd;
    h2o_fastcgi_register_by_address(ctx->pathconf, (void *)&sun, sizeof(sun), &config_vars);

    ret = 0;
Exit:
    if (dirname[0] != '\0')
        unlink(dirname);
    free(argv[0]);
    return ret;
}
Esempio n. 8
0
static int on_config_mruby_handler_file(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node)
{
    struct mruby_configurator_t *self = (void *)cmd->configurator;
    FILE *fp = NULL;
    h2o_iovec_t buf = {};
    int ret = -1;

    /* open and read file */
    if ((fp = fopen(node->data.scalar, "rt")) == NULL) {
        h2o_configurator_errprintf(cmd, node, "failed to open file: %s:%s", node->data.scalar, strerror(errno));
        goto Exit;
    }
    while (!feof(fp)) {
        buf.base = h2o_mem_realloc(buf.base, buf.len + 65536);
        buf.len += fread(buf.base + buf.len, 1, 65536, fp);
        if (ferror(fp)) {
            h2o_configurator_errprintf(cmd, node, "I/O error occurred while reading file:%s:%s", node->data.scalar,
                                       strerror(errno));
            goto Exit;
        }
    }

    /* set source */
    self->vars->source = buf;
    buf.base = NULL;
    self->vars->path = node->data.scalar; /* the value is retained until the end of the configuration phase */
    self->vars->lineno = 0;

    /* check if there is any error in source */
    char errbuf[1024];
    if (!compile_test(self->vars, errbuf)) {
        h2o_configurator_errprintf(cmd, node, "failed to compile file:%s:%s", node->data.scalar, errbuf);
        goto Exit;
    }

    /* register */
    h2o_mruby_register(ctx->pathconf, self->vars);

    ret = 0;

Exit:
    if (fp != NULL)
        fclose(fp);
    if (buf.base != NULL)
        free(buf.base);
    return ret;
}
Esempio n. 9
0
static int on_config(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, const char *file, yoml_t *node)
{
    struct st_h2o_access_log_configurator_t *self = (void*)cmd->configurator;
    const char *path, *fmt = NULL;
    h2o_access_log_filehandle_t *fh;

    switch (node->type) {
    case  YOML_TYPE_SCALAR:
        path = node->data.scalar;
        break;
    case YOML_TYPE_MAPPING:
        {
            yoml_t *t;
            /* get path */
            if ((t = yoml_get(node, "path")) == NULL) {
                h2o_configurator_errprintf(cmd, file, node, "could not find mandatory key `path`");
                return -1;
            }
            if (t->type != YOML_TYPE_SCALAR) {
                h2o_configurator_errprintf(cmd, file, t, "`path` must be scalar");
                return -1;
            }
            path = t->data.scalar;
            /* get format */
            if ((t = yoml_get(node, "format")) != NULL) {
                if (t->type != YOML_TYPE_SCALAR) {
                    h2o_configurator_errprintf(cmd, file, t, "`format` must be a scalar");
                    return -1;
                }
                fmt = t->data.scalar;
            }
        }
        break;
    default:
        h2o_configurator_errprintf(cmd, file, node, "node must be a scalar or a mapping");
        return -1;
    }

    if ((fh = h2o_access_log_open_handle(path, fmt)) == NULL)
        return -1;

    h2o_vector_reserve(NULL, (h2o_vector_t*)self->handles, sizeof(self->handles->entries[0]), self->handles->size + 1);
    self->handles->entries[self->handles->size++] = fh;

    return 0;
}
Esempio n. 10
0
static int on_config_header_2arg(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, int cmd_id, yoml_t *node)
{
    h2o_iovec_t *name, value;

    if (extract_name_value(node->data.scalar, &name, &value) != 0) {
        h2o_configurator_errprintf(cmd, node, "failed to parse the value; should be in form of `name: value`");
        return -1;
    }
    if (add_cmd(cmd, node, cmd_id, name, value) != 0)
        return -1;
    return 0;
}
Esempio n. 11
0
static int on_config_header_unset(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node)
{
    h2o_iovec_t *name;

    if (extract_name(node->data.scalar, strlen(node->data.scalar), &name) != 0) {
        h2o_configurator_errprintf(cmd, node, "invalid header name");
        return -1;
    }
    if (add_cmd(cmd, node, H2O_HEADERS_CMD_UNSET, name, (h2o_iovec_t){}) != 0)
        return -1;
    return 0;
}
Esempio n. 12
0
static int on_config(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node)
{
    const char *dest;
    int status = 302; /* default is temporary redirect */
    yoml_t *t;

    switch (node->type) {
    case YOML_TYPE_SCALAR:
        dest = node->data.scalar;
        break;
    case YOML_TYPE_MAPPING:
        if ((t = yoml_get(node, "url")) == NULL) {
            h2o_configurator_errprintf(cmd, node, "mandatory property `url` is missing");
            return -1;
        }
        if (t->type != YOML_TYPE_SCALAR) {
            h2o_configurator_errprintf(cmd, t, "property `url` must be a string");
            return -1;
        }
        dest = t->data.scalar;
        if ((t = yoml_get(node, "status")) == NULL) {
            h2o_configurator_errprintf(cmd, node, "mandatory property `status` is missing");
            return -1;
        }
        if (h2o_configurator_scanf(cmd, t, "%d", &status) != 0)
            return -1;
        if (!(300 <= status && status <= 399)) {
            h2o_configurator_errprintf(cmd, t, "value of property `status` should be within 300 to 399");
            return -1;
        }
        break;
    default:
        h2o_configurator_errprintf(cmd, node, "value must be a string or a mapping");
        return -1;
    }

    h2o_redirect_register(ctx->pathconf, status, dest);

    return 0;
}
Esempio n. 13
0
int h2o_configurator_apply(h2o_globalconf_t *config, yoml_t *node)
{
    h2o_configurator_context_t ctx = {config};

    if (h2o_configurator_apply_commands(&ctx, node, H2O_CONFIGURATOR_FLAG_GLOBAL, NULL) != 0)
        return -1;
    if (config->hosts[0] == NULL) {
        h2o_configurator_errprintf(NULL, node, "mandatory configuration directive `hosts` is missing");
        return -1;
    }

    return 0;
}
Esempio n. 14
0
static int add_cmd(h2o_configurator_command_t *cmd, yoml_t *node, int cmd_id, h2o_iovec_t *name, h2o_iovec_t value)
{
    struct headers_configurator_t *self = (void *)cmd->configurator;

    if (h2o_iovec_is_token(name)) {
        const h2o_token_t *token = (void *)name;
        if (h2o_headers_is_prohibited_name(token)) {
            h2o_configurator_errprintf(cmd, node, "the named header cannot be rewritten");
            return -1;
        }
    }

    h2o_vector_reserve(NULL, (h2o_vector_t *)self->cmds, sizeof(self->cmds->entries[0]), self->cmds->size + 1);
    self->cmds->entries[self->cmds->size++] = (h2o_headers_command_t){cmd_id, name, value};
    return 0;
}
Esempio n. 15
0
static int on_config_document_root(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node)
{
    struct fastcgi_configurator_t *self = (void *)cmd->configurator;

    if (node->data.scalar[0] == '\0') {
        /* unset */
        self->vars->document_root = h2o_iovec_init(NULL, 0);
    } else if (node->data.scalar[0] == '/') {
        /* set */
        self->vars->document_root = h2o_iovec_init(node->data.scalar, strlen(node->data.scalar));
    } else {
        h2o_configurator_errprintf(cmd, node, "value does not start from `/`");
        return -1;
    }
    return 0;
}
Esempio n. 16
0
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;
}
Esempio n. 17
0
static int on_config_mruby_handler_path(h2o_configurator_command_t *cmd,
    h2o_configurator_context_t *ctx, yoml_t *node)
{
    struct mruby_configurator_t *self = (void *)cmd->configurator;

    if (node->data.scalar[0] == '\0') {
        self->vars->mruby_handler_path = h2o_iovec_init(NULL, 0);
    } else if (node->data.scalar[0] == '/') {
        self->vars->mruby_handler_path = h2o_iovec_init(node->data.scalar,
            strlen(node->data.scalar));
        h2o_mruby_register(ctx->pathconf, self->vars);
    } else {
        h2o_configurator_errprintf(cmd, node,
            "mruby_handler_path must be absoluted path");
        return -1;
    }
    return 0;
}
Esempio n. 18
0
static int set_mimetypes(h2o_configurator_command_t *cmd, h2o_mimemap_t *mimemap, yoml_t *node)
{
    size_t i, j;
    h2o_mimemap_type_t *type = NULL;

    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;
        type = h2o_mimemap_create_extension_type(key->data.scalar);
        switch (value->type) {
        case YOML_TYPE_SCALAR:
            if (assert_is_extension(cmd, value) != 0)
                goto Error;
            h2o_mimemap_set_type(mimemap, value->data.scalar + 1, type, 1);
            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)
                    goto Error;
                h2o_mimemap_set_type(mimemap, ext_node->data.scalar + 1, type, 1);
            }
            break;
        default:
            h2o_configurator_errprintf(cmd, value,
                                       "only scalar or sequence of scalar is permitted at the value part of the argument");
            goto Error;
        }
        h2o_mem_release_shared(type);
        type = NULL;
    }

    return 0;

Error:
    if (type != NULL)
        h2o_mem_release_shared(type);
    return -1;
}
Esempio n. 19
0
static int on_config_index(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, 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_mem_alloc(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_configurator_errprintf(cmd, 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;
}
Esempio n. 20
0
static int on_config_mruby_handler(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node)
{
    struct mruby_configurator_t *self = (void *)cmd->configurator;

    /* set source */
    self->vars->source = h2o_strdup(NULL, node->data.scalar, SIZE_MAX);
    self->vars->path = node->filename;
    self->vars->lineno = (int)node->line;

    /* check if there is any error in source */
    char errbuf[1024];
    if (!compile_test(self->vars, errbuf)) {
        h2o_configurator_errprintf(cmd, node, "ruby compile error:%s", errbuf);
        return -1;
    }

    /* register */
    h2o_mruby_register(ctx->pathconf, self->vars);

    return 0;
}
Esempio n. 21
0
static int on_config_connect(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node)
{
    struct fastcgi_configurator_t *self = (void *)cmd->configurator;
    const char *hostname = "127.0.0.1", *servname = NULL, *type = "tcp";

    /* fetch servname (and hostname) */
    switch (node->type) {
    case YOML_TYPE_SCALAR:
        servname = node->data.scalar;
        break;
    case YOML_TYPE_MAPPING: {
        yoml_t *t;
        if ((t = yoml_get(node, "host")) != NULL) {
            if (t->type != YOML_TYPE_SCALAR) {
                h2o_configurator_errprintf(cmd, t, "`host` is not a string");
                return -1;
            }
            hostname = t->data.scalar;
        }
        if ((t = yoml_get(node, "port")) == NULL) {
            h2o_configurator_errprintf(cmd, node, "cannot find mandatory property `port`");
            return -1;
        }
        if (t->type != YOML_TYPE_SCALAR) {
            h2o_configurator_errprintf(cmd, node, "`port` is not a string");
            return -1;
        }
        servname = t->data.scalar;
        if ((t = yoml_get(node, "type")) != NULL) {
            if (t->type != YOML_TYPE_SCALAR) {
                h2o_configurator_errprintf(cmd, t, "`type` is not a string");
                return -1;
            }
            type = t->data.scalar;
        }
    } break;
    default:
        h2o_configurator_errprintf(cmd, node,
                                   "value must be a string or a mapping (with keys: `port` and optionally `host` and `type`)");
        return -1;
    }

    if (strcmp(type, "unix") == 0) {
        /* unix socket */
        struct sockaddr_un sa = {};
        if (strlen(servname) >= sizeof(sa.sun_path)) {
            h2o_configurator_errprintf(cmd, node, "path:%s is too long as a unix socket name", servname);
            return -1;
        }
        sa.sun_family = AF_UNIX;
        strcpy(sa.sun_path, servname);
        h2o_fastcgi_register_by_address(ctx->pathconf, (void *)&sa, sizeof(sa), self->vars);
    } else if (strcmp(type, "tcp") == 0) {
        /* tcp socket */
        uint16_t port;
        if (sscanf(servname, "%" SCNu16, &port) != 1) {
            h2o_configurator_errprintf(cmd, node, "invalid port number:%s", servname);
            return -1;
        }
        h2o_fastcgi_register_by_hostport(ctx->pathconf, hostname, port, self->vars);
    } else {
        h2o_configurator_errprintf(cmd, node, "unknown listen type: %s", type);
        return -1;
    }

    return 0;
}
Esempio n. 22
0
int h2o_configurator_apply_commands(h2o_configurator_context_t *ctx, yoml_t *node, int flags_mask, const char **ignore_commands)
{
    struct {
        h2o_configurator_command_t *cmd;
        yoml_t *value;
    } *deferred;
    size_t num_deferred = 0, i;

    if (node->type != YOML_TYPE_MAPPING) {
        h2o_configurator_errprintf(NULL, node, "node must be a MAPPING");
        return -1;
    }
    deferred = alloca(sizeof(*deferred) * node->data.mapping.size);

    /* call on_enter of every configurator */
    if (setup_configurators(ctx, 1, node) != 0)
        return -1;

    /* handle the configuration commands */
    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");
            return -1;
        }
        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);
            return -1;
        }
        if ((cmd->flags & flags_mask) == 0) {
            h2o_configurator_errprintf(cmd, key, "the command cannot be used at this level");
            return -1;
        }
        /* 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");
                    return -1;
                }
                break;
            case YOML_TYPE_SEQUENCE:
                if ((cmd->flags & H2O_CONFIGURATOR_FLAG_EXPECT_SEQUENCE) == 0) {
                    h2o_configurator_errprintf(cmd, value, "argument cannot be a sequence");
                    return -1;
                }
                break;
            case YOML_TYPE_MAPPING:
                if ((cmd->flags & H2O_CONFIGURATOR_FLAG_EXPECT_MAPPING) == 0) {
                    h2o_configurator_errprintf(cmd, value, "argument cannot be a mapping");
                    return -1;
                }
                break;
            default:
                assert(!"unreachable");
                break;
            }
        }
        /* handle the command (or keep it for later execution) */
        if ((cmd->flags & H2O_CONFIGURATOR_FLAG_DEFERRED) != 0) {
            deferred[num_deferred].cmd = cmd;
            deferred[num_deferred].value = value;
            ++num_deferred;
        } else {
            if (cmd->cb(cmd, ctx, value) != 0)
                return -1;
        }
    SkipCommand:
        ;
    }
    for (i = 0; i != num_deferred; ++i) {
        if (deferred[i].cmd->cb(deferred[i].cmd, ctx, deferred[i].value) != 0)
            return -1;
    }

    /* call on_enter of every configurator */
    if (setup_configurators(ctx, 0, node) != 0)
        return -1;

    return 0;
}
Esempio n. 23
0
static int on_config_spawn(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node)
{
    struct fastcgi_configurator_t *self = (void *)cmd->configurator;
    char *spawn_user = NULL, *spawn_cmd;
    char dirname[] = "/tmp/h2o.fcgisock.XXXXXX";
    char *argv[10];
    int spawner_fd;
    struct sockaddr_un sa = {};
    h2o_fastcgi_config_vars_t config_vars;
    int ret = -1;

    switch (node->type) {
    case YOML_TYPE_SCALAR:
        spawn_user = ctx->globalconf->user;
        spawn_cmd = node->data.scalar;
        break;
    case YOML_TYPE_MAPPING: {
        yoml_t *t;
        if ((t = yoml_get(node, "command")) == NULL) {
            h2o_configurator_errprintf(cmd, node, "mandatory attribute `command` does not exist");
            return -1;
        }
        if (t->type != YOML_TYPE_SCALAR) {
            h2o_configurator_errprintf(cmd, node, "attribute `command` must be scalar");
            return -1;
        }
        spawn_cmd = t->data.scalar;
        if ((t = yoml_get(node, "user")) != NULL) {
            if (t->type != YOML_TYPE_SCALAR) {
                h2o_configurator_errprintf(cmd, node, "attribute `user` must be scalar");
                return -1;
            }
            spawn_user = t->data.scalar;
        }
    } break;
    default:
        h2o_configurator_errprintf(cmd, node, "argument must be scalar or mapping");
        return -1;
    }

    { /* build args */
        size_t i = 0;
        argv[i++] = h2o_configurator_get_cmd_path("share/h2o/kill-on-close");
        argv[i++] = "--rm";
        argv[i++] = dirname;
        argv[i++] = "--";
        if (spawn_user != NULL) {
            argv[i++] = h2o_configurator_get_cmd_path("share/h2o/setuidgid");
            argv[i++] = spawn_user;
        }
        argv[i++] = "/bin/sh";
        argv[i++] = "-c";
        argv[i++] = spawn_cmd;
        argv[i++] = NULL;
        assert(i <= sizeof(argv) / sizeof(argv[0]));
    }

    if (ctx->dry_run) {
        dirname[0] = '\0';
        spawner_fd = -1;
        sa.sun_family = AF_UNIX;
        strcpy(sa.sun_path, "/dry-run.nonexistent");
    } else {
        /* create temporary directory */
        if (mkdtemp(dirname) == NULL) {
            h2o_configurator_errprintf(cmd, node, "mkdtemp(3) failed to create temporary directory:%s:%s", dirname,
                                       strerror(errno));
            dirname[0] = '\0';
            goto Exit;
        }
        /* launch spawnfcgi command */
        if ((spawner_fd = create_spawnproc(cmd, node, dirname, argv, &sa)) == -1) {
            goto Exit;
        }
    }

    config_vars = *self->vars;
    config_vars.callbacks.dispose = spawnproc_on_dispose;
    config_vars.callbacks.data = (char *)NULL + spawner_fd;
    h2o_fastcgi_register_by_address(ctx->pathconf, (void *)&sa, sizeof(sa), &config_vars);

    ret = 0;
Exit:
    if (dirname[0] != '\0')
        unlink(dirname);
    free(argv[0]);
    return ret;
}
Esempio n. 24
0
static int on_config_spawn(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node)
{
    struct fastcgi_configurator_t *self = (void *)cmd->configurator;
    char *spawn_user = NULL, *spawn_cmd;
    char *kill_on_close_cmd_path = NULL, *setuidgid_cmd_path = NULL;
    char dirname[] = "/tmp/h2o.fcgisock.XXXXXX";
    char *argv[10];
    int spawner_fd;
    struct sockaddr_un sa;
    h2o_fastcgi_config_vars_t config_vars;
    int ret = -1;
    struct passwd h2o_user_pwbuf, *h2o_user_pw;
    char h2o_user_buf[65536];

    memset(&sa, 0, sizeof(sa));

    switch (node->type) {
    case YOML_TYPE_SCALAR:
        spawn_user = ctx->globalconf->user;
        spawn_cmd = node->data.scalar;
        break;
    case YOML_TYPE_MAPPING: {
        yoml_t *t;
        if ((t = yoml_get(node, "command")) == NULL) {
            h2o_configurator_errprintf(cmd, node, "mandatory attribute `command` does not exist");
            return -1;
        }
        if (t->type != YOML_TYPE_SCALAR) {
            h2o_configurator_errprintf(cmd, node, "attribute `command` must be scalar");
            return -1;
        }
        spawn_cmd = t->data.scalar;
        spawn_user = ctx->globalconf->user;
        if ((t = yoml_get(node, "user")) != NULL) {
            if (t->type != YOML_TYPE_SCALAR) {
                h2o_configurator_errprintf(cmd, node, "attribute `user` must be scalar");
                return -1;
            }
            spawn_user = t->data.scalar;
        }
    } break;
    default:
        h2o_configurator_errprintf(cmd, node, "argument must be scalar or mapping");
        return -1;
    }

    /* obtain uid & gid of the client that connects to the FastCGI daemon (i.e. H2O after dropping privileges) */
    if (ctx->globalconf->user != NULL) {
        /* change ownership of temporary directory */
        if (getpwnam_r(ctx->globalconf->user, &h2o_user_pwbuf, h2o_user_buf, sizeof(h2o_user_buf), &h2o_user_pw) != 0 ||
            h2o_user_pw == NULL) {
            h2o_configurator_errprintf(cmd, node, "getpwnam_r(3) failed to obtain uid of user:%s", ctx->globalconf->user);
            goto Exit;
        }
    } else {
        h2o_user_pw = NULL;
    }

    { /* build args */
        size_t i = 0;
        argv[i++] = kill_on_close_cmd_path = h2o_configurator_get_cmd_path("share/h2o/kill-on-close");
        argv[i++] = "--rm";
        argv[i++] = dirname;
        argv[i++] = "--";
        if (spawn_user != NULL) {
            argv[i++] = setuidgid_cmd_path = h2o_configurator_get_cmd_path("share/h2o/setuidgid");
            argv[i++] = spawn_user;
        }
        argv[i++] = "/bin/sh";
        argv[i++] = "-c";
        argv[i++] = spawn_cmd;
        argv[i++] = NULL;
        assert(i <= sizeof(argv) / sizeof(argv[0]));
    }

    if (ctx->dry_run) {
        dirname[0] = '\0';
        spawner_fd = -1;
        sa.sun_family = AF_UNIX;
        strcpy(sa.sun_path, "/dry-run.nonexistent");
    } else {
        /* create temporary directory */
        if (mkdtemp(dirname) == NULL) {
            h2o_configurator_errprintf(cmd, node, "mkdtemp(3) failed to create temporary directory:%s:%s", dirname,
                                       strerror(errno));
            dirname[0] = '\0';
            goto Exit;
        }
        /* change ownership of temporary directory */
        if (h2o_user_pw != NULL && chown(dirname, h2o_user_pw->pw_uid, h2o_user_pw->pw_gid) != 0) {
            h2o_configurator_errprintf(cmd, node, "chown(2) failed to change ownership of temporary directory:%s:%s", dirname,
                                       strerror(errno));
            goto Exit;
        }
        /* launch spawnfcgi command */
        if ((spawner_fd = create_spawnproc(cmd, node, dirname, argv, &sa, h2o_user_pw)) == -1) {
            goto Exit;
        }
    }

    config_vars = *self->vars;
    config_vars.callbacks.dispose = spawnproc_on_dispose;
    config_vars.callbacks.data = (char *)NULL + spawner_fd;
    h2o_fastcgi_register_by_address(ctx->pathconf, (void *)&sa, sizeof(sa), &config_vars);

    ret = 0;
Exit:
    if (dirname[0] != '\0')
        unlink(dirname);
    free(kill_on_close_cmd_path);
    free(setuidgid_cmd_path);
    return ret;
}
Esempio n. 25
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 = {}, semi_deferred = {};
    size_t i;
    int ret = -1;

    if (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 */
    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_push_back(NULL, &semi_deferred, ((struct st_cmd_value_t){cmd, value}));
        } else if ((cmd->flags & H2O_CONFIGURATOR_FLAG_DEFERRED) != 0) {
Esempio n. 26
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};
    struct st_h2o_file_configurator_t *self = (void *)cmd->configurator;
    h2o_pathconf_t *prev_pathconf = ctx->pathconf;
    yoml_t *ext_node;
    h2o_mimemap_type_t *type = NULL;
    int ret = -1;

    if (node->type != YOML_TYPE_MAPPING) {
        h2o_configurator_errprintf(cmd, node, "argument must be a MAPPING");
        goto Exit;
    }
    if ((ext_node = yoml_get(node, "extension")) == NULL) {
        h2o_configurator_errprintf(cmd, node, "mandatory key `extension` is missing");
        goto Exit;
    }

    type = h2o_mimemap_create_dynamic_type(ctx->globalconf);
    ctx->pathconf = &type->data.dynamic.pathconf;
    if (h2o_configurator_apply_commands(ctx, node, H2O_CONFIGURATOR_FLAG_EXTENSION, ignore_commands) != 0)
        goto Exit;
    switch (type->data.dynamic.pathconf.handlers.size) {
    case 1:
        break;
    case 0:
        h2o_configurator_errprintf(cmd, node, "no handler declared for given extension");
        goto Exit;
    default:
        h2o_configurator_errprintf(cmd, node, "cannot assign more than one handler for given extension");
        goto Exit;
    }

    clone_mimemap_if_clean(self);

    switch (ext_node->type) {
    case YOML_TYPE_SCALAR:
        if (assert_is_extension(cmd, ext_node) != 0)
            goto Exit;
        h2o_mimemap_set_type(self->vars->mimemap, ext_node->data.scalar + 1, type, 1);
        break;
    case YOML_TYPE_SEQUENCE: {
        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)
                goto Exit;
            h2o_mimemap_set_type(self->vars->mimemap, n->data.scalar + 1, type, 1);
        }
    } break;
    default:
        h2o_configurator_errprintf(cmd, ext_node,
                                   "only scalar or sequence of scalar is permitted at the value part of the argument");
        goto Exit;
    }

    ret = 0;
Exit:
    if (type != NULL)
        h2o_mem_release_shared(type);
    ctx->pathconf = prev_pathconf;
    return ret;
}
Esempio n. 27
0
static int on_config_mruby_handler_path(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node)
{
    h2o_configurator_errprintf(cmd, node, "the command has been removed; see https://github.com/h2o/h2o/pull/467");
    return -1;
}