Ejemplo n.º 1
0
void
http_cfg_free(struct http_cfg *cfg) {
    http_free(cfg->content_decoders);
    http_headers_delete(cfg->default_headers);

    memset(cfg, 0, sizeof(struct http_cfg));
}
Ejemplo n.º 2
0
void
http_response_delete(struct http_response *response) {
    if (!response)
        return;

    c_free(response->reason);

    http_headers_delete(response->headers);

    c_free(response->body);

    c_vector_delete(response->content_codings);

    http_url_delete(response->redirection_location);

    c_free0(response, sizeof(struct http_response));
}
Ejemplo n.º 3
0
int
http_response_parse(const char *data, size_t sz, uint32_t flags,
                    struct http_response **presponse, size_t *psz) {
    struct http_response *response;
    const char *ptr;
    size_t len, toklen;
    char status_string[4];
    size_t status_sz;
    int32_t status_value;
    int ret;

    ptr = data;
    len = sz;

#define HTTP_FAIL(fmt_, ...)                  \
    do {                                      \
        if (fmt_)                             \
            c_set_error(fmt_, ##__VA_ARGS__); \
        http_response_delete(response);       \
        return -1;                            \
    } while (0)

#define HTTP_TRUNCATED()                      \
    do {                                      \
        http_response_delete(response);       \
        return 0;                             \
    } while (0)

    response = http_response_new();

    /* Version */
    toklen = c_memcspn(ptr, len, " ");
    if (toklen == len) {
        if (len > HTTP_VERSION_MAX_LENGTH)
            HTTP_FAIL("invalid version");
        HTTP_TRUNCATED();
    }

    if (http_version_parse(ptr, toklen, &response->version) == -1)
        HTTP_FAIL(NULL);

    ptr += toklen + 1;
    len -= toklen + 1;

    /* Status */
    toklen = c_memcspn(ptr, len, " ");
    if (toklen == len) {
        if (len > 3)
            HTTP_FAIL("invalid status code");
        HTTP_TRUNCATED();
    }

    if (toklen > 3)
        HTTP_FAIL("invalid status code");

    memcpy(status_string, ptr, toklen);
    status_string[toklen] = '\0';

    if (c_parse_i32(status_string, &status_value, &status_sz) == -1)
        HTTP_FAIL("invalid status code");
    if (status_sz != toklen)
        HTTP_FAIL("invalid trailing data after status code");
    response->status = (enum http_status)status_value;

    ptr += toklen + 1;
    len -= toklen + 1;

    /* Reason */
    toklen = c_memcspn(ptr, len, "\r");
    if (toklen == len) {
        if (len > HTTP_REASON_MAX_LENGTH)
            HTTP_FAIL("reason string too long");
        HTTP_TRUNCATED();
    }

    response->reason = c_strndup(ptr, toklen);

    ptr += toklen;
    len -= toklen;

    /* End of status line */
    if (len < 2)
        HTTP_TRUNCATED();
    if (ptr[0] != '\r' || ptr[1] != '\n')
        HTTP_FAIL("malformed status line");

    ptr += 2;
    len -= 2;

    /* Headers */
    http_headers_delete(response->headers);
    response->headers = NULL;

    ret = http_headers_parse(ptr, len, &response->headers, NULL, &toklen);
    if (ret == -1)
        HTTP_FAIL(NULL);
    if (ret == 0)
        HTTP_TRUNCATED();

    ptr += toklen;
    len -= toklen;

    if (http_response_preprocess_headers(response) == -1) {
        http_response_delete(response);
        return -1;
    }

    /* Body */
    if (!http_response_can_have_body(response))
        goto end;

    if (response->has_content_length) {
        if (response->content_length > HTTP_RESPONSE_MAX_CONTENT_LENGTH)
            HTTP_FAIL("payload too large");

        if (len < response->content_length)
            HTTP_TRUNCATED();

        response->body_sz = response->content_length;
        response->body = c_strndup(ptr, response->content_length);

        ptr += response->body_sz;
        len -= response->body_sz;
    } else if (response->is_body_chunked) {
        struct http_headers *trailer;
        size_t chunked_data_sz;

        ret = http_chunked_data_parse(ptr, len,
                                      &response->body, &response->body_sz,
                                      &chunked_data_sz);
        if (ret == -1)
            HTTP_FAIL("invalid chunked body: %s", c_get_error());
        if (ret == 0)
            HTTP_TRUNCATED();

        ptr += chunked_data_sz;
        len -= chunked_data_sz;

        /* Trailer */
        ret = http_headers_parse(ptr, len, &trailer, NULL, &toklen);
        if (ret == -1)
            HTTP_FAIL(NULL);
        if (ret == 0)
            HTTP_TRUNCATED();

        http_headers_merge_nocopy(response->headers, trailer);
        http_headers_delete(trailer);

        ptr += toklen;
        len -= toklen;
    } else if (response->has_connection_close) {
        size_t content_length;

        if (flags & HTTP_RESPONSE_PARSE_EOF) {
            content_length = len;

            if (content_length > HTTP_RESPONSE_MAX_CONTENT_LENGTH)
                HTTP_FAIL("payload too large");

            response->body_sz = content_length;
            response->body = c_strndup(ptr, content_length);

            ptr += response->body_sz;
            len -= response->body_sz;
        } else {
            HTTP_TRUNCATED();
        }
    } else {
        HTTP_FAIL("missing content length");
    }

#undef HTTP_FAIL
#undef HTTP_TRUNCATED

end:
    *presponse = response;
    *psz = sz - len;
    return 1;
}