コード例 #1
0
ファイル: file.c プロジェクト: Akilklk/vlc
bool vlc_http_file_can_seek(struct vlc_http_file *file)
{   /* See IETF RFC7233 */
    int status = vlc_http_file_get_status(file);
    if (status < 0)
        return false;
    if (status == 206 || status == 416)
        return true; /* Partial Content */

    return vlc_http_msg_get_token(file->resp, "Accept-Ranges",
                                  "bytes") != NULL;
}
コード例 #2
0
ファイル: file.c プロジェクト: Akilklk/vlc
uintmax_t vlc_http_file_get_size(struct vlc_http_file *file)
{
    int status = vlc_http_file_get_status(file);
    if (status < 0)
        return -1;

    const char *range = vlc_http_msg_get_header(file->resp, "Content-Range");

    if (status == 206 /* Partial Content */)
    {   /* IETF RFC7233 §4.1 */
        assert(range != NULL); /* checked by vlc_http_file_open() */

        uintmax_t end, total;

        switch (sscanf(range, "bytes %*u-%ju/%ju", &end, &total))
        {
            case 1:
                if (unlikely(end == UINTMAX_MAX))
                    return -1; /* avoid wrapping to zero */
                return end + 1;
            case 2:
                return total;
        }
        vlc_assert_unreachable(); /* checked by vlc_http_file_open() */
    }

    if (status == 416 /* Range Not Satisfiable */)
    {   /* IETF RFC7233 §4.4 */
        uintmax_t total;

        if (range == NULL)
            return -1; /* valid but helpless response */

        if (sscanf(range, "bytes */%ju", &total) == 1)
            return total; /* this occurs when seeking beyond EOF */
    }

    if (status >= 300 || status == 201)
        return -1; /* Error or redirection, size is unknown/irrelevant. */

    /* Content-Range is meaningless here (see RFC7233 B), so check if the size
     * of the response entity body is known. */
    return vlc_http_msg_get_size(file->resp);
}
コード例 #3
0
ファイル: file.c プロジェクト: Akilklk/vlc
block_t *vlc_http_file_read(struct vlc_http_file *file)
{
    if (vlc_http_file_get_status(file) < 0)
        return NULL;

    block_t *block = vlc_http_res_read(file->resp);

    if (block == NULL)
    {   /* Automatically reconnect if server supports seek */
        if (vlc_http_file_can_seek(file)
         && vlc_http_file_seek(file, file->offset) == 0)
            block = vlc_http_res_read(file->resp);

        if (block == NULL)
            return NULL;
    }

    file->offset += block->i_buffer;
    return block;
}
コード例 #4
0
ファイル: file.c プロジェクト: Akilklk/vlc
char *vlc_http_file_get_type(struct vlc_http_file *file)
{
    if (vlc_http_file_get_status(file) < 0)
        return NULL;
    return vlc_http_res_get_type(file->resp);
}
コード例 #5
0
ファイル: file.c プロジェクト: Akilklk/vlc
char *vlc_http_file_get_redirect(struct vlc_http_file *file)
{
    if (vlc_http_file_get_status(file) < 0)
        return NULL;
    return vlc_http_res_get_redirect(&file->resource, file->resp);
}
コード例 #6
0
ファイル: access.c プロジェクト: jtrent238/vlc
static int Open(vlc_object_t *obj)
{
    access_t *access = (access_t *)obj;
    access_sys_t *sys = malloc(sizeof (*sys));
    int ret = VLC_ENOMEM;

    if (unlikely(sys == NULL))
        return VLC_ENOMEM;

    sys->manager = NULL;
    sys->file = NULL;

    sys->manager = vlc_http_mgr_create(obj);
    if (sys->manager == NULL)
        goto error;

    char *ua = var_InheritString(obj, "http-user-agent");
    char *ref = var_InheritString(obj, "http-referrer");

    sys->file = vlc_http_file_create(sys->manager, access->psz_url, ua, ref);
    free(ref);
    free(ua);
    if (sys->file == NULL)
        goto error;

    char *redir = vlc_http_file_get_redirect(sys->file);
    if (redir != NULL)
    {
        access->psz_url = redir;
        ret = VLC_ACCESS_REDIRECT;
        goto error;
    }

    ret = VLC_EGENERIC;

    int status = vlc_http_file_get_status(sys->file);
    if (status < 0)
    {
        msg_Err(access, "HTTP connection failure");
        goto error;
    }
    if (status >= 300)
    {
        msg_Err(access, "HTTP %d error", status);
        goto error;
    }

    access->info.b_eof = false;
    access->pf_read = NULL;
    access->pf_block = Read;
    access->pf_seek = Seek;
    access->pf_control = Control;
    access->p_sys = sys;
    return VLC_SUCCESS;

error:
    if (sys->file != NULL)
        vlc_http_file_destroy(sys->file);
    if (sys->manager != NULL)
        vlc_http_mgr_destroy(sys->manager);
    free(sys);
    return ret;
}
コード例 #7
0
int main(void)
{
    struct vlc_http_file *f;
    char *str;

    /* Request failure test */
    f = vlc_http_file_create(NULL, url, ua, NULL);
    assert(f != NULL);
    vlc_http_file_seek(f, 0);
    assert(vlc_http_file_get_status(f) < 0);
    assert(vlc_http_file_get_redirect(f) == NULL);
    assert(vlc_http_file_get_size(f) == (uintmax_t)-1);
    assert(!vlc_http_file_can_seek(f));
    assert(vlc_http_file_get_type(f) == NULL);
    assert(vlc_http_file_read(f) == NULL);
    vlc_http_file_destroy(f);

    /* Non-seekable stream test */
    replies[0] = "HTTP/1.1 200 OK\r\n"
                 "ETag: \"foobar42\"\r\n"
                 "Content-Type: video/mpeg\r\n"
                 "\r\n";

    offset = 0;
    f = vlc_http_file_create(NULL, url, ua, NULL);
    assert(f != NULL);
    assert(vlc_http_file_get_status(f) == 200);
    assert(!vlc_http_file_can_seek(f));
    assert(vlc_http_file_get_size(f) == (uintmax_t)-1);
    str = vlc_http_file_get_type(f);
    assert(str != NULL && !strcmp(str, "video/mpeg"));
    free(str);

    /* Seek failure */
    replies[0] = "HTTP/1.1 200 OK\r\nETag: \"foobar42\"\r\n\r\n";

    assert(vlc_http_file_seek(f, offset = 1234) < 0);
    vlc_http_file_destroy(f);

    /* Seekable file test */
    replies[0] = "HTTP/1.1 206 Partial Content\r\n"
                 "Content-Range: bytes 0-2344/2345\r\n"
                 "ETag: W/\"foobar42\"\r\n"
                 "\r\n";

    offset = 0;
    f = vlc_http_file_create(NULL, url, ua, NULL);
    assert(f != NULL);
    assert(vlc_http_file_can_seek(f));
    assert(vlc_http_file_get_size(f) == 2345);

    /* Seek success */
    replies[0] = "HTTP/1.1 206 Partial Content\r\n"
                 "Content-Range: bytes 1234-3455/3456\r\n"
                 "ETag: W/\"foobar42\"\r\n"
                 "\r\n";
    assert(vlc_http_file_seek(f, offset = 1234) == 0);
    assert(vlc_http_file_can_seek(f));
    assert(vlc_http_file_get_size(f) == 3456);

    /* Seek too far */
    replies[0] = "HTTP/1.1 416 Range Not Satisfiable\r\n"
                 "Content-Range: bytes */4567\r\n"
                 "ETag: W/\"foobar42\"\r\n"
                 "\r\n";
    vlc_http_file_seek(f, offset = 5678);
    assert(vlc_http_file_can_seek(f));
    assert(vlc_http_file_get_size(f) == 4567);
    assert(vlc_http_file_read(f) == NULL);
    vlc_http_file_destroy(f);

    /* Redirect */
    replies[0] = "HTTP/1.1 301 Permanent Redirect\r\n"
                 "Location: /somewhere/else/#here\r\n"
                 "\r\n";

    offset = 0;
    f = vlc_http_file_create(NULL, url, ua, NULL);
    assert(f != NULL);
    assert(!vlc_http_file_can_seek(f));
    assert(vlc_http_file_get_size(f) == (uintmax_t)-1);
    str = vlc_http_file_get_redirect(f);
    assert(str != NULL
        && !strcmp(str, "https://www.example.com:8443/somewhere/else/"));
    free(str);
    vlc_http_file_destroy(f);

    /* Continuation */
    replies[0] = "HTTP/1.1 100 Standby\r\n"
                 "\r\n";
    replies[1] = "HTTP/1.1 200 OK\r\n"
                 "Content-Length: 9999\r\n"
                 "\r\n";
    offset = 0;
    f = vlc_http_file_create(NULL, url, ua, NULL);
    assert(f != NULL);
    assert(vlc_http_file_get_size(f) == 9999);
    assert(vlc_http_file_get_redirect(f) == NULL);
    vlc_http_file_destroy(f);


    /* Dummy API calls */
    f = vlc_http_file_create(NULL, "ftp://localhost/foo", NULL, NULL);
    assert(f == NULL);

    return 0;
}