Esempio n. 1
0
File: headers.c Progetto: herumi/h2o
void h2o_set_header_by_str(h2o_mempool_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_buf_t *slot = &headers->entries[cursor].value;
            slot->base = (char*)value;
            slot->len = value_len;
        }
    } else {
        h2o_buf_t *name_buf = h2o_mempool_alloc(pool, sizeof(h2o_buf_t));
        name_buf->base = (char*)name;
        name_buf->len = name_len;
        add_header(pool, headers, name_buf, value, value_len);
    }
}
Esempio n. 2
0
int h2o_is_websocket_handshake(h2o_req_t *req, const char **ws_client_key)
{
    ssize_t key_header_index;

    *ws_client_key = NULL;

    /* method */
    if (h2o_memis(req->input.method.base, req->input.method.len, H2O_STRLIT("GET"))) {
        /* ok */
    } else {
        return 0;
    }

    /* upgrade header */
    if (req->upgrade.base != NULL && h2o_lcstris(req->upgrade.base, req->upgrade.len, H2O_STRLIT("websocket"))) {
        /* ok */
    } else {
        return 0;
    }
    /* sec-websocket-key header */
    if ((key_header_index = h2o_find_header_by_str(&req->headers, H2O_STRLIT("sec-websocket-key"), -1)) != -1) {
        if (req->headers.entries[key_header_index].value.len != 24) {
            return -1;
        }
    } else {
        return 0;
    }

    *ws_client_key = req->headers.entries[key_header_index].value.base;
    return 0;
}
Esempio n. 3
0
ssize_t 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) {
            return h2o_set_header(pool, headers, token, value, value_len, overwrite_if_exists);
        }
    }

    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;
        }
        return cursor;
    } else {
        h2o_iovec_t *name_buf = h2o_mem_alloc_pool(pool, *name_buf, 1);
        name_buf->base = (char *)name;
        name_buf->len = name_len;
        return add_header(pool, headers, name_buf, NULL, value, value_len, (h2o_header_flags_t){0});
    }
}
Esempio n. 4
0
static h2o_iovec_t __get_if_match_header_value(const h2o_req_t* req,
                                               const kstr_t* key)
{
    ssize_t header =
        h2o_find_header(&req->headers, H2O_TOKEN_IF_MATCH, SIZE_MAX);

    if (-1 == header)
        return (h2o_iovec_t){.base = NULL, .len = 0 };

    return req->headers.entries[header].value;
}

/**
 * @return 1 if the client wants an ETag; otherwise 0
 */
static int __prefers_etag(const h2o_req_t* req)
{
    ssize_t header = h2o_find_header_by_str(
        &req->headers, "prefers", strlen("prefers"), SIZE_MAX);

    if (-1 == header)
        return 0;

    if (!strncmp(req->headers.entries[header].value.base, "ETag",
                 min(strlen("ETag"), req->headers.entries[header].value.len)))
        return 1;

    return 0;
}
Esempio n. 5
0
static h2o_header_t *find_header(h2o_headers_t *headers, h2o_headers_command_t *cmd)
{
    size_t index;

    if (h2o_iovec_is_token(cmd->name)) {
        index = h2o_find_header(headers, (void *)cmd->name, SIZE_MAX);
    } else {
        index = h2o_find_header_by_str(headers, cmd->name->base, cmd->name->len, SIZE_MAX);
    }
    if (index == SIZE_MAX)
        return NULL;
    return headers->entries + index;
}
Esempio n. 6
0
static mrb_value h2o_mrb_get_request_headers_out(mrb_state *mrb, mrb_value self)
{
    h2o_mruby_internal_context_t *mruby_ctx = (h2o_mruby_internal_context_t *)mrb->ud;
    mrb_value key;
    ssize_t index;
    h2o_header_t *h;

    mrb_get_args(mrb, "o", &key);
    key = mrb_funcall(mrb, key, "downcase", 0);

    index = h2o_find_header_by_str(&mruby_ctx->req->res.headers, RSTRING_PTR(key), RSTRING_LEN(key), -1);
    if (index == -1)
        return mrb_nil_value();

    h = mruby_ctx->req->res.headers.entries + index;

    return mrb_str_new(mrb, h->value.base, h->value.len);
}
Esempio n. 7
0
static void check(const h2o_url_scheme_t *scheme, const char *host, const char *expected)
{
    h2o_loopback_conn_t *conn = h2o_loopback_create(&ctx, ctx.globalconf->hosts);

    conn->req.input.method = h2o_iovec_init(H2O_STRLIT("GET"));
    conn->req.input.scheme = scheme;
    conn->req.input.authority = h2o_iovec_init(host, strlen(host));
    conn->req.input.path = h2o_iovec_init(H2O_STRLIT("/"));
    h2o_loopback_run_loop(conn);
    ok(conn->req.res.status == 200);

    size_t index = h2o_find_header_by_str(&conn->req.res.headers, H2O_STRLIT("x-authority"), SIZE_MAX);
    ok(index != SIZE_MAX);

    if (index != SIZE_MAX) {
        ok(h2o_memis(conn->req.res.headers.entries[index].value.base, conn->req.res.headers.entries[index].value.len, expected, strlen(expected)));
    }

    h2o_loopback_destroy(conn);
}
Esempio n. 8
0
static void log_access(h2o_logger_t *_self, h2o_req_t *req)
{
    struct st_h2o_access_logger_t *self = (struct st_h2o_access_logger_t *)_self;
    h2o_access_log_filehandle_t *fh = self->fh;
    char *line, *pos, *line_end;
    size_t element_index;

    /* note: LOG_ALLOCA_SIZE should be much greater than NI_MAXHOST to avoid unnecessary reallocations */
    line = alloca(LOG_ALLOCA_SIZE);
    pos = line;
    line_end = line + LOG_ALLOCA_SIZE;

    for (element_index = 0; element_index != fh->num_elements; ++element_index) {
        struct log_element_t *element = fh->elements + element_index;

/* reserve capacity + suffix.len */
#define RESERVE(capacity)                                                                                                          \
    do {                                                                                                                           \
        if ((capacity) + element->suffix.len > line_end - pos) {                                                                   \
            size_t off = pos - line;                                                                                               \
            line = expand_line_buf(line, line_end - line, off + (capacity) + element->suffix.len);                                 \
            pos = line + off;                                                                                                      \
        }                                                                                                                          \
    } while (0)

        switch (element->type) {
        case ELEMENT_TYPE_EMPTY:
            RESERVE(0);
            break;
        case ELEMENT_TYPE_BYTES_SENT: /* %b */
            RESERVE(sizeof("18446744073709551615") - 1);
            pos += sprintf(pos, "%llu", (unsigned long long)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 */ {
            struct sockaddr_storage ss;
            socklen_t sslen;
            if ((sslen = req->conn->get_peername(req->conn, (void *)&ss)) != 0) {
                RESERVE(NI_MAXHOST);
                size_t l = h2o_socket_getnumerichost((void *)&ss, sslen, pos);
                if (l != SIZE_MAX)
                    pos += l;
                else
                    *pos++ = '-';
            } else {
                RESERVE(1);
                *pos++ = '-';
            }
        } break;
        case ELEMENT_TYPE_METHOD: /* %m */
            RESERVE(req->input.method.len * 4);
            pos = append_unsafe_string(pos, req->input.method.base, req->input.method.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 * 4);
                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) * 4 + 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("2147483647") - 1);
            pos += sprintf(pos, "%d", req->res.status);
            break;
        case ELEMENT_TYPE_TIMESTAMP: /* %t */
            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_URL_PATH: /* %U */
        {
            size_t path_len = req->input.query_at == SIZE_MAX ? req->input.path.len : req->input.query_at;
            RESERVE(req->input.scheme->name.len + (sizeof("://") - 1) + (req->input.authority.len + path_len) * 4);
            pos = append_safe_string(pos, req->input.scheme->name.base, req->input.scheme->name.len);
            pos = append_safe_string(pos, H2O_STRLIT("://"));
            pos = append_unsafe_string(pos, req->input.authority.base, req->input.authority.len);
            pos = append_unsafe_string(pos, req->input.path.base, path_len);
        } break;
        case ELEMENT_TYPE_AUTHORITY: /* %V */
            RESERVE(req->input.authority.len * 4);
            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 * 4);
            pos = append_unsafe_string(pos, req->hostconf->authority.hostport.base, req->hostconf->authority.hostport.len);
            break;

        case ELEMENT_TYPE_LOGNAME:     /* %l */
        case ELEMENT_TYPE_REMOTE_USER: /* %u */
            RESERVE(1);
            *pos++ = '-';
            break;

#define EMIT_HEADER(headers, _index)                                                                                               \
    do {                                                                                                                           \
        ssize_t index = (_index);                                                                                                  \
        if (index != -1) {                                                                                                         \
            const h2o_header_t *header = (headers)->entries + index;                                                               \
            RESERVE(header->value.len * 4);                                                                                        \
            pos = append_unsafe_string(pos, header->value.base, header->value.len);                                                \
        } else {                                                                                                                   \
            RESERVE(1);                                                                                                            \
            *pos++ = '-';                                                                                                          \
        }                                                                                                                          \
    } while (0)
        case ELEMENT_TYPE_IN_HEADER_TOKEN:
            EMIT_HEADER(&req->headers, h2o_find_header(&req->headers, element->data.header_token, SIZE_MAX));
            break;
        case ELEMENT_TYPE_IN_HEADER_STRING:
            EMIT_HEADER(&req->headers, h2o_find_header_by_str(&req->headers, element->data.header_string.base,
                                                              element->data.header_string.len, SIZE_MAX));
            break;
        case ELEMENT_TYPE_OUT_HEADER_TOKEN:
            EMIT_HEADER(&req->res.headers, h2o_find_header(&req->res.headers, element->data.header_token, SIZE_MAX));
            break;
        case ELEMENT_TYPE_OUT_HEADER_STRING:
            EMIT_HEADER(&req->res.headers, h2o_find_header_by_str(&req->res.headers, element->data.header_string.base,
                                                                  element->data.header_string.len, SIZE_MAX));
            break;
#undef EMIT_HEADER

        default:
            assert(!"unknown type");
            break;
        }

#undef RESERVE

        pos = append_safe_string(pos, element->suffix.base, element->suffix.len);
    }

    write(fh->fd, line, pos - line);

    if (line_end - line != LOG_ALLOCA_SIZE)
        free(line);
}