Example #1
0
File: file.c Project: Akilklk/vlc
int vlc_http_file_seek(struct vlc_http_file *file, uintmax_t offset)
{
    struct vlc_http_msg *resp = vlc_http_file_open(file, offset);
    if (resp == NULL)
        return -1;

    int status = vlc_http_msg_get_status(resp);
    if (file->resp != NULL)
    {   /* Accept the new and ditch the old one if:
         * - requested succeeded and range was accepted (206),
         * - requested failed due to out-of-range (416),
         * - request succeeded and seek offset is zero (2xx).
         */
        if (status != 206 && status != 416 && (offset != 0 || status >= 300))
        {
            vlc_http_msg_destroy(resp);
            return -1;
        }
        vlc_http_msg_destroy(file->resp);
    }

    file->resp = resp;
    file->offset = offset;
    return 0;
}
Example #2
0
File: file.c Project: Akilklk/vlc
void vlc_http_file_destroy(struct vlc_http_file *file)
{
    if (file->resp != NULL)
        vlc_http_msg_destroy(file->resp);
    vlc_http_res_deinit(&file->resource);
    free(file);
}
Example #3
0
struct vlc_http_msg *
vlc_http_req_create(const char *method, const char *scheme,
                    const char *authority, const char *path)
{
    struct vlc_http_msg *m = malloc(sizeof (*m));
    if (unlikely(m == NULL))
        return NULL;

    assert(method != NULL);
    m->status = -1;
    m->method = strdup(method);
    m->scheme = (scheme != NULL) ? strdup(scheme) : NULL;
    m->authority = (authority != NULL) ? strdup(authority) : NULL;
    m->path = (path != NULL) ? strdup(path) : NULL;
    m->count = 0;
    m->headers = NULL;
    m->payload = NULL;

    if (unlikely(m->method == NULL
              || (scheme != NULL && m->scheme == NULL)
              || (authority != NULL && m->authority == NULL)
              || (path != NULL && m->path == NULL)))
    {
        /* LVP added */
        //fprintf(stderr, "LVP msg_destroy because problem while creating the request\n");

        vlc_http_msg_destroy(m);
        m = NULL;
    }
    return m;
}
Example #4
0
struct vlc_http_msg *
vlc_http_req_create(const char *method, const char *scheme,
                    const char *authority, const char *path)
{
    struct vlc_http_msg *m = malloc(sizeof (*m));
    if (unlikely(m == NULL))
        return NULL;

    assert(method != NULL);
    m->status = -1;
    m->method = strdup(method);
    m->scheme = (scheme != NULL) ? strdup(scheme) : NULL;
    m->authority = (authority != NULL) ? strdup(authority) : NULL;
    m->path = (path != NULL) ? strdup(path) : NULL;
    m->count = 0;
    m->headers = NULL;
    m->payload = NULL;

    if (unlikely(m->method == NULL
              || (scheme != NULL && m->scheme == NULL)
              || (authority != NULL && m->authority == NULL)
              || (path != NULL && m->path == NULL)))
    {
        vlc_http_msg_destroy(m);
        m = NULL;
    }
    return m;
}
Example #5
0
File: file.c Project: Akilklk/vlc
static struct vlc_http_msg *vlc_http_file_open(struct vlc_http_file *file,
                                               uintmax_t offset)
{
    struct vlc_http_msg *resp;

    resp = vlc_http_res_open(&file->resource, vlc_http_file_req, &offset);
    if (resp == NULL)
        return NULL;

    int status = vlc_http_msg_get_status(resp);
    if (status == 206)
    {
        const char *str = vlc_http_msg_get_header(resp, "Content-Range");
        if (str == NULL)
            /* A multipart/byteranges response. This is not what we asked for
             * and we do not support it. */
            goto fail;

        uintmax_t start, end;
        if (sscanf(str, "bytes %ju-%ju", &start, &end) != 2
         || start != offset || start > end)
            /* A single range response is what we asked for, but not at that
             * start offset. */
            goto fail;
    }

    return resp;
fail:
    vlc_http_msg_destroy(resp);
    errno = EIO;
    return NULL;
}
Example #6
0
struct vlc_http_msg *vlc_http_msg_iterate(struct vlc_http_msg *m)
{
    struct vlc_http_msg *next = vlc_http_stream_read_headers(m->payload);

    m->payload = NULL;
    vlc_http_msg_destroy(m);
    return next;
}
Example #7
0
struct vlc_http_msg *vlc_http_res_open(struct vlc_http_resource *res,
                                       void *opaque)
{
    struct vlc_http_msg *req;
retry:
    req = vlc_http_res_req(res, opaque);
    if (unlikely(req == NULL))
        return NULL;

    struct vlc_http_msg *resp = vlc_http_mgr_request(res->manager, res->secure,
                                res->host, res->port, req);
    vlc_http_msg_destroy(req);

    resp = vlc_http_msg_get_final(resp);
    if (resp == NULL)
        return NULL;

    vlc_http_msg_get_cookies(resp, vlc_http_mgr_get_jar(res->manager),
                             res->secure, res->host, res->path);

    int status = vlc_http_msg_get_status(resp);
    if (status < 200 || status >= 599)
        goto fail;

    if (status == 406 && res->negotiate)
    {   /* Not Acceptable: Content negotiation failed. Normally it means
         * one (or more) Accept or Accept-* header line does not match any
         * representation of the entity. So we set a flag to remove those
         * header lines (unless they accept everything), and retry.
         * In principles, it could be any header line, and the server can
         * pass Vary to clarify. It cannot be caused by If-*, Range, TE or the
         * other transfer- rather than representation-affecting header lines.
         */
        vlc_http_msg_destroy(resp);
        res->negotiate = false;
        goto retry;
    }

    if (res->cbs->response_validate(res, resp, opaque))
        goto fail;

    return resp;
fail:
    vlc_http_msg_destroy(resp);
    return NULL;
}
Example #8
0
static void stream_reply(uint_fast32_t id, bool nodata)
{
    struct vlc_http_msg *m = vlc_http_resp_create(200);
    assert(m != NULL);
    vlc_http_msg_add_agent(m, "VLC-h2-tester");

    conn_send(vlc_http_msg_h2_frame(m, id, nodata));
    vlc_http_msg_destroy(m);
}
Example #9
0
static struct vlc_http_stream *stream_open(void)
{
    struct vlc_http_msg *m = vlc_http_req_create("GET", "https",
                                                 "www.example.com", "/");
    assert(m != NULL);

    struct vlc_http_stream *s = vlc_http_stream_open(conn, m);
    vlc_http_msg_destroy(m);
    return s;
}
Example #10
0
static void vlc_http_res_deinit(struct vlc_http_resource *res)
{
    free(res->referrer);
    free(res->agent);
    free(res->path);
    free(res->authority);
    free(res->host);

    if (res->response != NULL)
        vlc_http_msg_destroy(res->response);
}
Example #11
0
struct vlc_http_msg *vlc_http_msg_iterate(struct vlc_http_msg *m)
{
    struct vlc_http_msg *next = vlc_http_stream_read_headers(m->payload);

    m->payload = NULL;
    vlc_http_msg_destroy(m);

    /* LVP added */
    //fprintf(stderr, "LVP msg_destroy inside of msg_iterate\n");

    return next;
}
Example #12
0
static struct vlc_http_msg *vlc_http_tunnel_open(struct vlc_http_conn *conn,
                                                 const char *hostname,
                                                 unsigned port)
{
    char *authority = vlc_http_authority(hostname, port);
    if (authority == NULL)
        return NULL;

    struct vlc_http_msg *req = vlc_http_req_create("CONNECT", NULL, authority,
                                                   NULL);
    free(authority);
    if (unlikely(req == NULL))
        return NULL;

    vlc_http_msg_add_header(req, "ALPN", "h2, http%%2F1.1");
    vlc_http_msg_add_agent(req, PACKAGE_NAME "/" PACKAGE_VERSION);

    struct vlc_http_stream *stream = vlc_http_stream_open(conn, req);

    vlc_http_msg_destroy(req);
    if (stream == NULL)
        return NULL;

    struct vlc_http_msg *resp = vlc_http_msg_get_initial(stream);
    resp = vlc_http_msg_get_final(resp);
    if (resp == NULL)
        return NULL;

    int status = vlc_http_msg_get_status(resp);
    if ((status / 100) != 2)
    {
        vlc_http_msg_destroy(resp);
        resp = NULL;
    }
    return resp;
}
Example #13
0
static struct vlc_http_msg *
vlc_http_res_req(const struct vlc_http_resource *res, void *opaque)
{
    struct vlc_http_msg *req;

    req = vlc_http_req_create("GET", res->secure ? "https" : "http",
                              res->authority, res->path);
    if (unlikely(req == NULL))
        return NULL;

    /* Content negotiation */
    vlc_http_msg_add_header(req, "Accept", "*/*");

    if (res->negotiate)
    {
        const char *lang = vlc_gettext("C");
        if (!strcmp(lang, "C"))
            lang = "en_US";
        vlc_http_msg_add_header(req, "Accept-Language", "%s", lang);
    }

    /* Authentication */
    if (res->username != NULL)
        vlc_http_msg_add_creds_basic(req, false, res->username, res->password);

    /* Request context */
    if (res->agent != NULL)
        vlc_http_msg_add_agent(req, res->agent);

    if (res->referrer != NULL) /* TODO: validate URL */
        vlc_http_msg_add_header(req, "Referer", "%s", res->referrer);

    vlc_http_msg_add_cookies(req, vlc_http_mgr_get_jar(res->manager));

    /* TODO: vlc_http_msg_add_header(req, "TE", "gzip, deflate"); */

    if (res->cbs->request_format(res, req, opaque))
    {
        vlc_http_msg_destroy(req);
        return NULL;
    }

    return req;
}
Example #14
0
/** Reports received stream headers */
static void vlc_h2_stream_headers(void *ctx, unsigned count, char *hdrs[][2])
{
    struct vlc_h2_stream *s = ctx;

    /* NOTE: HTTP message trailers are not supported so far. Follow-up headers
     * can therefore only be a final response after a 1xx continue response.
     * Then it is safe to discard the existing header. */
    if (s->recv_hdr != NULL)
    {
        msg_Dbg(SO(s), "stream %"PRIu32" discarding old headers", s->id);
        vlc_http_msg_destroy(s->recv_hdr);
        s->recv_hdr = NULL;
    }

    msg_Dbg(SO(s), "stream %"PRIu32" %u headers:", s->id, count);

    for (unsigned i = 0; i < count; i++)
        msg_Dbg(SO(s), " %s: \"%s\"", hdrs[i][0], hdrs[i][1]);

    s->recv_hdr = vlc_http_msg_h2_headers(count, hdrs);
    if (unlikely(s->recv_hdr == NULL))
        vlc_h2_stream_fatal(s, VLC_H2_PROTOCOL_ERROR);
    vlc_cond_signal(&s->recv_wait);
}
Example #15
0
/**
 * Terminates a stream.
 *
 * Sends an HTTP/2 stream reset, removes the stream from the HTTP/2 connection
 * and deletes any stream resource.
 */
static void vlc_h2_stream_close(struct vlc_http_stream *stream)
{
    struct vlc_h2_stream *s = (struct vlc_h2_stream *)stream;
    struct vlc_h2_conn *conn = s->conn;
    bool destroy = false;

    vlc_mutex_lock(&conn->lock);
    if (s->older != NULL)
        s->older->newer = s->newer;
    if (s->newer != NULL)
        s->newer->older = s->older;
    else
    {
        assert(conn->streams == s);
        conn->streams = s->older;
        destroy = (conn->streams == NULL) && conn->released;
    }
    vlc_mutex_unlock(&conn->lock);

    vlc_h2_stream_error(conn, s->id, VLC_H2_NO_ERROR);

    if (s->recv_hdr != NULL)
        vlc_http_msg_destroy(s->recv_hdr);

    for (struct vlc_h2_frame *f = s->recv_head, *next; f != NULL; f = next)
    {
        next = f->next;
        free(f);
    }

    vlc_cond_destroy(&s->recv_wait);
    free(s);

    if (destroy)
        vlc_h2_conn_destroy(conn);
}
Example #16
0
int main(void)
{
    struct vlc_http_stream *s;
    struct vlc_http_msg *m;
    struct block_t *b;

    /* Dummy */
    conn_create();
    conn_destroy();

    /* Test rejected connection */
    conn_create();
    conn_shutdown(SHUT_RD);
    s = stream_open();
    assert(s == NULL);
    conn_destroy();

    /* Test rejected stream */
    conn_create();
    s = stream_open();
    assert(s != NULL);
    conn_shutdown(SHUT_WR);

    m = vlc_http_stream_read_headers(s);
    assert(m == NULL);
    b = vlc_http_stream_read(s);
    assert(b == NULL);
    m = vlc_http_stream_read_headers(s);
    assert(m == NULL);
    b = vlc_http_stream_read(s);
    assert(b == NULL);
    m = vlc_http_msg_get_initial(s);
    assert(m == NULL);

    s = stream_open();
    assert(s == NULL);
    conn_destroy();

    /* Test garbage */
    conn_create();
    s = stream_open();
    assert(s != NULL);
    conn_send("Go away!\r\n\r\n");
    conn_shutdown(SHUT_WR);

    m = vlc_http_stream_read_headers(s);
    assert(m == NULL);
    b = vlc_http_stream_read(s);
    assert(b == NULL);
    conn_destroy();
    vlc_http_stream_close(s, false);

    /* Test HTTP/1.0 stream */
    conn_create();
    s = stream_open();
    assert(s != NULL);
    conn_send("HTTP/1.0 200 OK\r\n\r\n");
    m = vlc_http_msg_get_initial(s);
    assert(m != NULL);

    conn_send("Hello world!");
    conn_shutdown(SHUT_WR);
    b = vlc_http_msg_read(m);
    assert(b != NULL);
    assert(b->i_buffer == 12);
    assert(!memcmp(b->p_buffer, "Hello world!", 12));
    block_Release(b);
    b = vlc_http_msg_read(m);
    assert(b == NULL);
    vlc_http_msg_destroy(m);
    conn_destroy();

    /* Test HTTP/1.1 with closed connection */
    conn_create();
    s = stream_open();
    assert(s != NULL);
    conn_send("HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n");
    m = vlc_http_msg_get_initial(s);
    assert(m != NULL);

    conn_send("Hello again!");
    conn_shutdown(SHUT_WR);
    b = vlc_http_msg_read(m);
    assert(b != NULL);
    assert(b->i_buffer == 12);
    assert(!memcmp(b->p_buffer, "Hello again!", 12));
    block_Release(b);
    b = vlc_http_msg_read(m);
    assert(b == NULL);
    vlc_http_msg_destroy(m);
    conn_destroy();

    /* Test HTTP/1.1 with chunked transfer encoding */
    conn_create();
    s = stream_open();
    assert(s != NULL);
    conn_send("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n"
              "Content-Length: 1000000\r\n\r\n"); /* length must be ignored */
    m = vlc_http_msg_get_initial(s);
    assert(m != NULL);

    conn_send("C\r\nHello there!\r\n0\r\n\r\n");
    b = vlc_http_msg_read(m);
    assert(b != NULL);
    assert(b->i_buffer == 12);
    assert(!memcmp(b->p_buffer, "Hello there!", 12));
    block_Release(b);
    conn_destroy(); /* test connection release before closing stream */
    b = vlc_http_msg_read(m);
    assert(b == NULL);
    vlc_http_msg_destroy(m);

    /* Test HTTP/1.1 with content length */
    conn_create();
    s = stream_open();
    assert(s != NULL);
    conn_send("HTTP/1.1 200 OK\r\nContent-Length: 8\r\n\r\n");
    m = vlc_http_msg_get_initial(s);
    assert(m != NULL);

    conn_send("Bye bye!");
    b = vlc_http_msg_read(m);
    assert(b != NULL);
    assert(b->i_buffer == 8);
    assert(!memcmp(b->p_buffer, "Bye bye!", 8));
    block_Release(b);
    b = vlc_http_msg_read(m);
    assert(b == NULL);
    vlc_http_msg_destroy(m);
    conn_destroy();

    return 0;
}
Example #17
0
int main(void)
{
    struct vlc_http_stream *s, *s2;
    struct vlc_http_msg *m;
    struct block_t *b;
    uint_fast32_t sid = -1; /* Second guessed stream IDs :-/ */

    conn_create();
    conn_destroy();

    conn_create();
    conn_send(vlc_h2_frame_ping(42));
    conn_expect(PING);

    /* Test rejected stream */
    sid += 2;
    s = stream_open();
    assert(s != NULL);
    conn_expect(HEADERS);
    conn_send(vlc_h2_frame_rst_stream(sid, VLC_H2_REFUSED_STREAM));
    m = vlc_http_stream_read_headers(s);
    assert(m == NULL);
    b = vlc_http_stream_read(s);
    assert(b == NULL);
    vlc_http_stream_close(s, false);
    conn_expect(RST_STREAM);

    /* Test accepted stream */
    sid += 2;
    s = stream_open();
    assert(s != NULL);
    stream_reply(sid, false);
    m = vlc_http_msg_get_initial(s);
    assert(m != NULL);
    vlc_http_msg_destroy(m);

    stream_data(3, "Hello ", false); /* late data */
    stream_data(3, "world!", true);

    conn_expect(HEADERS);
    conn_expect(RST_STREAM);
    conn_expect(RST_STREAM);
    conn_expect(RST_STREAM);

    /* Test continuation then accepted stream */
    sid += 2;
    s = stream_open();
    assert(s != NULL);
    stream_continuation(sid);
    m = vlc_http_msg_get_initial(s);
    assert(m != NULL);
    assert(vlc_http_msg_get_status(m) == 100);
    stream_reply(sid, false);
    m = vlc_http_msg_iterate(m);
    assert(m != NULL);
    stream_data(sid, "Hello ", false);
    stream_data(sid, "world!", true);
    stream_data(sid, "Stray message", false); /* data after EOS */
    b = vlc_http_msg_read(m);
    assert(b != NULL);
    block_Release(b);
    b = vlc_http_msg_read(m);
    assert(b != NULL);
    block_Release(b);
    b = vlc_http_msg_read(m);
    assert(b == NULL);
    vlc_http_msg_destroy(m);

    conn_expect(HEADERS);
    conn_expect(RST_STREAM);
    conn_expect(RST_STREAM);

    /* Test accepted stream after continuation */
    sid += 2;
    s = stream_open();
    assert(s != NULL);
    stream_continuation(sid);
    stream_reply(sid, true);
    sid += 2;
    s2 = stream_open(); /* second stream to enforce test timing/ordering */
    assert(s2 != NULL);
    stream_reply(sid, true);
    m = vlc_http_msg_get_initial(s2);
    assert(m != NULL);
    vlc_http_msg_destroy(m);
    m = vlc_http_msg_get_initial(s);
    assert(m != NULL);
    assert(vlc_http_msg_get_status(m) == 200);
    b = vlc_http_msg_read(m);
    assert(b == NULL);
    vlc_http_msg_destroy(m);

    conn_expect(HEADERS);
    conn_expect(HEADERS);
    conn_expect(RST_STREAM);
    conn_expect(RST_STREAM);

    /* Test nonexistent stream reset */
    conn_send(vlc_h2_frame_rst_stream(sid + 100, VLC_H2_REFUSED_STREAM));

    /* Test multiple streams in non-LIFO order */
    sid += 2;
    s = stream_open();
    assert(s != NULL);
    sid += 2;
    s2 = stream_open();
    assert(s2 != NULL);
    stream_reply(sid, false);
    stream_reply(sid - 2, true);
    stream_data(sid, "Discarded", false); /* not read data */
    m = vlc_http_msg_get_initial(s);
    assert(m != NULL);
    vlc_http_msg_destroy(m);
    m = vlc_http_msg_get_initial(s2);
    assert(m != NULL);
    vlc_http_msg_destroy(m);

    conn_expect(HEADERS);
    conn_expect(HEADERS);
    conn_expect(RST_STREAM);
    conn_expect(RST_STREAM);
    /* might or might not seen one or two extra RST_STREAM now */

    /* Test graceful connection termination */
    sid += 2;
    s = stream_open();
    assert(s != NULL);
    conn_send(vlc_h2_frame_goaway(sid - 2, VLC_H2_NO_ERROR));
    m = vlc_http_stream_read_headers(s);
    assert(m == NULL);

    /* Test stream after connection shut down */
    assert(stream_open() == NULL);

    /* Test releasing connection before stream */
    conn_destroy();
    vlc_http_stream_close(s, false);

    return 0;
}