http: factor more common between file and live streams
authorRémi Denis-Courmont <remi@remlab.net>
Sun, 10 Jul 2016 15:14:46 +0000 (18:14 +0300)
committerRémi Denis-Courmont <remi@remlab.net>
Sun, 10 Jul 2016 17:46:32 +0000 (20:46 +0300)
modules/access/http/access.c
modules/access/http/file.c
modules/access/http/file.h
modules/access/http/file_test.c
modules/access/http/live.c
modules/access/http/live.h
modules/access/http/resource.c
modules/access/http/resource.h

index 01405d6..a4090f0 100644 (file)
 #include <vlc_network.h> /* FIXME: only for vlc_getProxyUrl() */
 
 #include "connmgr.h"
+#include "resource.h"
 #include "file.h"
 #include "live.h"
 
 struct access_sys_t
 {
     struct vlc_http_mgr *manager;
-    union
-    {
-        struct vlc_http_file *file;
-        struct vlc_http_live *live;
-    };
+    struct vlc_http_resource *resource;
 };
 
 static block_t *FileRead(access_t *access)
 {
     access_sys_t *sys = access->p_sys;
 
-    block_t *b = vlc_http_file_read(sys->file);
+    block_t *b = vlc_http_file_read(sys->resource);
     if (b == NULL)
         access->info.b_eof = true;
     return b;
@@ -61,7 +58,7 @@ static int FileSeek(access_t *access, uint64_t pos)
     access_sys_t *sys = access->p_sys;
     access->info.b_eof = false;
 
-    if (vlc_http_file_seek(sys->file, pos))
+    if (vlc_http_file_seek(sys->resource, pos))
         return VLC_EGENERIC;
     return VLC_SUCCESS;
 }
@@ -73,7 +70,7 @@ static int FileControl(access_t *access, int query, va_list args)
     switch (query)
     {
         case ACCESS_CAN_SEEK:
-            *va_arg(args, bool *) = vlc_http_file_can_seek(sys->file);
+            *va_arg(args, bool *) = vlc_http_file_can_seek(sys->resource);
             break;
 
         case ACCESS_CAN_FASTSEEK:
@@ -87,7 +84,7 @@ static int FileControl(access_t *access, int query, va_list args)
 
         case ACCESS_GET_SIZE:
         {
-            uintmax_t val = vlc_http_file_get_size(sys->file);
+            uintmax_t val = vlc_http_file_get_size(sys->resource);
             if (val >= UINT64_MAX)
                 return VLC_EGENERIC;
 
@@ -101,7 +98,7 @@ static int FileControl(access_t *access, int query, va_list args)
             break;
 
         case ACCESS_GET_CONTENT_TYPE:
-            *va_arg(args, char **) = vlc_http_file_get_type(sys->file);
+            *va_arg(args, char **) = vlc_http_file_get_type(sys->resource);
             break;
 
         case ACCESS_SET_PAUSE_STATE:
@@ -117,7 +114,7 @@ static block_t *LiveRead(access_t *access)
 {
     access_sys_t *sys = access->p_sys;
 
-    block_t *b = vlc_http_live_read(sys->live);
+    block_t *b = vlc_http_live_read(sys->resource);
     if (b == NULL) /* TODO: loop instead of EOF, see vlc_http_live_read() */
         access->info.b_eof = true;
     return b;
@@ -149,7 +146,7 @@ static int LiveControl(access_t *access, int query, va_list args)
             break;
 
         case ACCESS_GET_CONTENT_TYPE:
-            *va_arg(args, char **) = vlc_http_live_get_type(sys->live);
+            *va_arg(args, char **) = vlc_http_live_get_type(sys->resource);
             break;
 
         default:
@@ -177,7 +174,7 @@ static int Open(vlc_object_t *obj)
         return VLC_ENOMEM;
 
     sys->manager = NULL;
-    sys->file = NULL;
+    sys->resource = NULL;
 
     void *jar = NULL;
     if (var_InheritBool(obj, "http-forward-cookies"))
@@ -194,31 +191,18 @@ static int Open(vlc_object_t *obj)
     bool live = var_InheritBool(obj, "http-continuous");
 
     if (live)
-        sys->live = vlc_http_live_create(sys->manager, access->psz_url, ua,
-                                         referer);
+        sys->resource = vlc_http_live_create(sys->manager, access->psz_url, ua,
+                                             referer);
     else
-        sys->file = vlc_http_file_create(sys->manager, access->psz_url, ua,
-                                         referer);
+        sys->resource = vlc_http_file_create(sys->manager, access->psz_url, ua,
+                                             referer);
     free(referer);
     free(ua);
 
-    char *redir;
-
-    if (live)
-    {
-        if (sys->live == NULL)
-            goto error;
-
-        redir = vlc_http_live_get_redirect(sys->live);
-    }
-    else
-    {
-        if (sys->file == NULL)
-            goto error;
-
-        redir = vlc_http_file_get_redirect(sys->file);
-    }
+    if (sys->resource == NULL)
+        goto error;
 
+    char *redir = vlc_http_res_get_redirect(sys->resource);
     if (redir != NULL)
     {
         access->psz_url = redir;
@@ -228,8 +212,7 @@ static int Open(vlc_object_t *obj)
 
     ret = VLC_EGENERIC;
 
-    int status = live ? vlc_http_live_get_status(sys->live)
-                      : vlc_http_file_get_status(sys->file);
+    int status = vlc_http_res_get_status(sys->resource);
     if (status < 0)
     {
         msg_Err(access, "HTTP connection failure");
@@ -261,8 +244,8 @@ static int Open(vlc_object_t *obj)
     return VLC_SUCCESS;
 
 error:
-    if (sys->file != NULL)
-        vlc_http_file_destroy(sys->file);
+    if (sys->resource != NULL)
+        vlc_http_res_destroy(sys->resource);
     if (sys->manager != NULL)
         vlc_http_mgr_destroy(sys->manager);
     free(sys);
@@ -274,10 +257,7 @@ static void Close(vlc_object_t *obj)
     access_t *access = (access_t *)obj;
     access_sys_t *sys = access->p_sys;
 
-    if (access->pf_block == LiveRead)
-        vlc_http_live_destroy(sys->live);
-    else
-        vlc_http_file_destroy(sys->file);
+    vlc_http_res_destroy(sys->resource);
     vlc_http_mgr_destroy(sys->manager);
     free(sys);
 }
index 542e6a3..c8c037a 100644 (file)
 struct vlc_http_file
 {
     struct vlc_http_resource resource;
-    struct vlc_http_msg *resp;
     uintmax_t offset;
-    bool failed;
 };
 
-static int vlc_http_file_req(struct vlc_http_msg *req,
-                             const struct vlc_http_resource *res, void *opaque)
+static int vlc_http_file_req(const struct vlc_http_resource *res,
+                             struct vlc_http_msg *req, void *opaque)
 {
     struct vlc_http_file *file = (struct vlc_http_file *)res;
     const uintmax_t *offset = opaque;
 
-    if (file->resp != NULL)
+    if (file->resource.response != NULL)
     {
-        const char *str = vlc_http_msg_get_header(file->resp, "ETag");
+        const char *str = vlc_http_msg_get_header(file->resource.response,
+                                                  "ETag");
         if (str != NULL)
         {
             if (!memcmp(str, "W/", 2))
@@ -64,7 +63,7 @@ static int vlc_http_file_req(struct vlc_http_msg *req,
         }
         else
         {
-            time_t mtime = vlc_http_msg_get_mtime(file->resp);
+            time_t mtime = vlc_http_msg_get_mtime(file->resource.response);
             if (mtime != -1)
                 vlc_http_msg_add_time(req, "If-Unmodified-Since", &mtime);
         }
@@ -76,17 +75,12 @@ static int vlc_http_file_req(struct vlc_http_msg *req,
     return 0;
 }
 
-static struct vlc_http_msg *vlc_http_file_open(struct vlc_http_file *file,
-                                               uintmax_t offset)
+static int vlc_http_file_resp(const struct vlc_http_resource *res,
+                              const struct vlc_http_msg *resp, void *opaque)
 {
-    struct vlc_http_msg *resp;
-
-    resp = vlc_http_res_open(&file->resource, vlc_http_file_req, &offset);
-    if (resp == NULL)
-        return NULL;
+    const uintmax_t *offset = opaque;
 
-    int status = vlc_http_msg_get_status(resp);
-    if (status == 206)
+    if (vlc_http_msg_get_status(resp) == 206)
     {
         const char *str = vlc_http_msg_get_header(resp, "Content-Range");
         if (str == NULL)
@@ -96,81 +90,57 @@ static struct vlc_http_msg *vlc_http_file_open(struct vlc_http_file *file,
 
         uintmax_t start, end;
         if (sscanf(str, "bytes %ju-%ju", &start, &end) != 2
-         || start != offset || start > end)
+         || start != *offset || start > end)
             /* A single range response is what we asked for, but not at that
              * start offset. */
             goto fail;
     }
 
-    return resp;
+    (void) res;
+    return 0;
+
 fail:
-    vlc_http_msg_destroy(resp);
     errno = EIO;
-    return NULL;
+    return -1;
 }
 
-void vlc_http_file_destroy(struct vlc_http_file *file)
+static const struct vlc_http_resource_cbs vlc_http_file_callbacks =
 {
-    if (file->resp != NULL)
-        vlc_http_msg_destroy(file->resp);
-    vlc_http_res_deinit(&file->resource);
-    free(file);
-}
+    vlc_http_file_req,
+    vlc_http_file_resp,
+};
 
-struct vlc_http_file *vlc_http_file_create(struct vlc_http_mgr *mgr,
-                                           const char *uri, const char *ua,
-                                           const char *ref)
+struct vlc_http_resource *vlc_http_file_create(struct vlc_http_mgr *mgr,
+                                               const char *uri, const char *ua,
+                                               const char *ref)
 {
     struct vlc_http_file *file = malloc(sizeof (*file));
     if (unlikely(file == NULL))
         return NULL;
 
-    if (vlc_http_res_init(&file->resource, mgr, uri, ua, ref))
+    if (vlc_http_res_init(&file->resource, &vlc_http_file_callbacks, mgr,
+                          uri, ua, ref))
     {
         free(file);
         return NULL;
     }
 
-    file->resp = NULL;
     file->offset = 0;
-    file->failed = false;
-    return file;
+    return &file->resource;
 }
 
-int vlc_http_file_get_status(struct vlc_http_file *file)
+uintmax_t vlc_http_file_get_size(struct vlc_http_resource *res)
 {
-    if (file->resp == NULL)
-    {
-        if (file->failed)
-            return -1;
-        file->resp = vlc_http_file_open(file, file->offset);
-        if (file->resp == NULL)
-        {
-            file->failed = true;
-            return -1;
-        }
-    }
-    return vlc_http_msg_get_status(file->resp);
-}
-
-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);
-}
-
-uintmax_t vlc_http_file_get_size(struct vlc_http_file *file)
-{
-    int status = vlc_http_file_get_status(file);
+    int status = vlc_http_res_get_status(res);
     if (status < 0)
         return -1;
 
-    const char *range = vlc_http_msg_get_header(file->resp, "Content-Range");
+    const char *range = vlc_http_msg_get_header(res->response,
+                                                "Content-Range");
 
     if (status == 206 /* Partial Content */)
     {   /* IETF RFC7233 §4.1 */
-        assert(range != NULL); /* checked by vlc_http_file_open() */
+        assert(range != NULL); /* checked by vlc_http_file_resp() */
 
         uintmax_t end, total;
 
@@ -183,7 +153,7 @@ uintmax_t vlc_http_file_get_size(struct vlc_http_file *file)
             case 2:
                 return total;
         }
-        vlc_assert_unreachable(); /* checked by vlc_http_file_open() */
+        vlc_assert_unreachable(); /* checked by vlc_http_file_resp() */
     }
 
     if (status == 416 /* Range Not Satisfiable */)
@@ -202,36 +172,31 @@ uintmax_t vlc_http_file_get_size(struct vlc_http_file *file)
 
     /* 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);
+    return vlc_http_msg_get_size(res->response);
 }
 
-bool vlc_http_file_can_seek(struct vlc_http_file *file)
+bool vlc_http_file_can_seek(struct vlc_http_resource *res)
 {   /* See IETF RFC7233 */
-    int status = vlc_http_file_get_status(file);
+    int status = vlc_http_res_get_status(res);
     if (status < 0)
         return false;
     if (status == 206 || status == 416)
         return true; /* Partial Content */
 
-    return vlc_http_msg_get_token(file->resp, "Accept-Ranges",
+    return vlc_http_msg_get_token(res->response, "Accept-Ranges",
                                   "bytes") != NULL;
 }
 
-char *vlc_http_file_get_type(struct vlc_http_file *file)
+int vlc_http_file_seek(struct vlc_http_resource *res, uintmax_t offset)
 {
-    if (vlc_http_file_get_status(file) < 0)
-        return NULL;
-    return vlc_http_res_get_type(file->resp);
-}
-
-int vlc_http_file_seek(struct vlc_http_file *file, uintmax_t offset)
-{
-    struct vlc_http_msg *resp = vlc_http_file_open(file, offset);
+    struct vlc_http_msg *resp = vlc_http_res_open(res, &offset);
     if (resp == NULL)
         return -1;
 
+    struct vlc_http_file *file = (struct vlc_http_file *)res;
+
     int status = vlc_http_msg_get_status(resp);
-    if (file->resp != NULL)
+    if (res->response != 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),
@@ -242,26 +207,24 @@ int vlc_http_file_seek(struct vlc_http_file *file, uintmax_t offset)
             vlc_http_msg_destroy(resp);
             return -1;
         }
-        vlc_http_msg_destroy(file->resp);
+        vlc_http_msg_destroy(res->response);
     }
 
-    file->resp = resp;
+    res->response = resp;
     file->offset = offset;
     return 0;
 }
 
-block_t *vlc_http_file_read(struct vlc_http_file *file)
+block_t *vlc_http_file_read(struct vlc_http_resource *res)
 {
-    if (vlc_http_file_get_status(file) < 0)
-        return NULL;
-
-    block_t *block = vlc_http_res_read(file->resp);
+    struct vlc_http_file *file = (struct vlc_http_file *)res;
+    block_t *block = vlc_http_res_read(res);
 
     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 (vlc_http_file_can_seek(res)
+         && vlc_http_file_seek(res, file->offset) == 0)
+            block = vlc_http_res_read(res);
 
         if (block == NULL)
             return NULL;
index f47795d..802cf8f 100644 (file)
@@ -27,8 +27,8 @@
  * @{
  */
 
-struct vlc_http_file;
 struct vlc_http_mgr;
+struct vlc_http_resource;
 struct block_t;
 
 /**
@@ -39,29 +39,12 @@ struct block_t;
  * @param url URL of the file to read
  * @param ua user agent string (or NULL to ignore)
  * @param ref referral URL (or NULL to ignore)
- */
-struct vlc_http_file *vlc_http_file_create(struct vlc_http_mgr *mgr,
-                                           const char *url, const char *ua,
-                                           const char *ref);
-
-/**
- * Destroys an HTTP file.
  *
- * Releases all resources allocated or held by the HTTP file object.
+ * @return an HTTP resource object pointer, or NULL on error
  */
-void vlc_http_file_destroy(struct vlc_http_file *);
-
-int vlc_http_file_get_status(struct vlc_http_file *);
-
-/**
- * Gets redirection URL.
- *
- * Checks if the file URL lead to a redirection. If so, return the redirect
- * location.
- *
- * @return Heap-allocated URL or NULL if no redirection.
- */
-char *vlc_http_file_get_redirect(struct vlc_http_file *);
+struct vlc_http_resource *vlc_http_file_create(struct vlc_http_mgr *mgr,
+                                               const char *url, const char *ua,
+                                               const char *ref);
 
 /**
  * Gets file size.
@@ -70,7 +53,7 @@ char *vlc_http_file_get_redirect(struct vlc_http_file *);
  *
  * @return Bytes count or (uintmax_t)-1 if unknown.
  */
-uintmax_t vlc_http_file_get_size(struct vlc_http_file *);
+uintmax_t vlc_http_file_get_size(struct vlc_http_resource *);
 
 /**
  * Checks seeking support.
@@ -78,14 +61,7 @@ uintmax_t vlc_http_file_get_size(struct vlc_http_file *);
  * @retval true if file supports seeking
  * @retval false if file does not support seeking
  */
-bool vlc_http_file_can_seek(struct vlc_http_file *);
-
-/**
- * Gets MIME type.
- *
- * @return Heap-allocated MIME type string, or NULL if unknown.
- */
-char *vlc_http_file_get_type(struct vlc_http_file *);
+bool vlc_http_file_can_seek(struct vlc_http_resource *);
 
 /**
  * Sets the read offset.
@@ -94,11 +70,18 @@ char *vlc_http_file_get_type(struct vlc_http_file *);
  * @retval 0 if seek succeeded
  * @retval -1 if seek failed
  */
-int vlc_http_file_seek(struct vlc_http_file *, uintmax_t offset);
+int vlc_http_file_seek(struct vlc_http_resource *, uintmax_t offset);
 
 /**
  * Reads data.
+ *
+ * Reads data from a file and update the file offset.
  */
-struct block_t *vlc_http_file_read(struct vlc_http_file *);
+struct block_t *vlc_http_file_read(struct vlc_http_resource *);
+
+#define vlc_http_file_get_status vlc_http_res_get_status
+#define vlc_http_file_get_redirect vlc_http_res_get_redirect
+#define vlc_http_file_get_type vlc_http_res_get_type
+#define vlc_http_file_destroy vlc_http_res_destroy
 
 /** @} */
index acc2aa9..eb35257 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <vlc_common.h>
 #include <vlc_http.h>
+#include "resource.h"
 #include "file.h"
 #include "message.h"
 
@@ -50,7 +51,7 @@ static vlc_http_cookie_jar_t *jar;
 
 int main(void)
 {
-    struct vlc_http_file *f;
+    struct vlc_http_resource *f;
     char *str;
 
     jar = vlc_http_cookies_new();
@@ -65,7 +66,7 @@ int main(void)
     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);
+    vlc_http_res_destroy(f);
 
     /* Non-seekable stream test */
     replies[0] = "HTTP/1.1 200 OK\r\n"
index 8a620e8..3ef1870 100644 (file)
 
 #pragma GCC visibility push(default)
 
-struct vlc_http_live
-{
-    struct vlc_http_resource resource;
-    struct vlc_http_msg *resp;
-    bool failed;
-};
-
-static int vlc_http_live_req(struct vlc_http_msg *req,
-                             const struct vlc_http_resource *res, void *opaque)
+static int vlc_http_live_req(const struct vlc_http_resource *res,
+                             struct vlc_http_msg *req, void *opaque)
 {
     vlc_http_msg_add_header(req, "Accept-Encoding", "gzip, deflate");
     (void) res;
@@ -47,82 +40,47 @@ static int vlc_http_live_req(struct vlc_http_msg *req,
     return 0;
 }
 
-static struct vlc_http_msg *vlc_http_live_open(struct vlc_http_live *live)
+static int vlc_http_live_resp(const struct vlc_http_resource *res,
+                              const struct vlc_http_msg *resp, void *opaque)
 {
-    return vlc_http_res_open(&live->resource, vlc_http_live_req, NULL);
+    (void) res;
+    (void) resp;
+    (void) opaque;
+    return 0;
 }
 
-void vlc_http_live_destroy(struct vlc_http_live *live)
+static const struct vlc_http_resource_cbs vlc_http_live_callbacks =
 {
-    if (live->resp != NULL)
-        vlc_http_msg_destroy(live->resp);
-    vlc_http_res_deinit(&live->resource);
-    free(live);
-}
+    vlc_http_live_req,
+    vlc_http_live_resp,
+};
 
-struct vlc_http_live *vlc_http_live_create(struct vlc_http_mgr *mgr,
-                                           const char *uri, const char *ua,
-                                           const char *ref)
+struct vlc_http_resource *vlc_http_live_create(struct vlc_http_mgr *mgr,
+                                               const char *uri, const char *ua,
+                                               const char *ref)
 {
-    struct vlc_http_live *live = malloc(sizeof (*live));
-    if (unlikely(live == NULL))
+    struct vlc_http_resource *res = malloc(sizeof (*res));
+    if (unlikely(res == NULL))
         return NULL;
 
-    if (vlc_http_res_init(&live->resource, mgr, uri, ua, ref))
+    if (vlc_http_res_init(res, &vlc_http_live_callbacks, mgr, uri, ua, ref))
     {
-        free(live);
-        return NULL;
+        free(res);
+        res = NULL;
     }
 
-    live->resp = NULL;
-    live->failed = false;
-    return live;
+    return res;
 }
 
-int vlc_http_live_get_status(struct vlc_http_live *live)
+block_t *vlc_http_live_read(struct vlc_http_resource *res)
 {
-    if (live->resp == NULL)
-    {
-        if (live->failed)
-            return -1;
-        live->resp = vlc_http_live_open(live);
-        if (live->resp == NULL)
-        {
-            live->failed = true;
-            return -1;
-        }
-    }
-    return vlc_http_msg_get_status(live->resp);
-}
-
-char *vlc_http_live_get_redirect(struct vlc_http_live *live)
-{
-    if (vlc_http_live_get_status(live) < 0)
-        return NULL;
-    return vlc_http_res_get_redirect(&live->resource, live->resp);
-}
-
-char *vlc_http_live_get_type(struct vlc_http_live *live)
-{
-    if (vlc_http_live_get_status(live) < 0)
-        return NULL;
-    return vlc_http_res_get_type(live->resp);
-}
-
-block_t *vlc_http_live_read(struct vlc_http_live *live)
-{
-    if (vlc_http_live_get_status(live) < 0)
-        return NULL;
-
-    struct block_t *block = vlc_http_res_read(live->resp);
+    struct block_t *block = vlc_http_res_read(res);
     if (block != NULL)
         return block;
 
     /* Automatically try to reconnect */
     /* TODO: Retry-After parsing, loop and pacing timer */
-    vlc_http_msg_destroy(live->resp);
-    live->resp = NULL;
-    if (vlc_http_live_get_status(live) < 0)
-        return NULL;
-    return vlc_http_res_read(live->resp);
+    vlc_http_msg_destroy(res->response);
+    res->response = NULL;
+    return vlc_http_res_read(res);
 }
index a81e9e2..552df6c 100644 (file)
  * @{
  */
 
-struct vlc_http_live;
+struct vlc_http_resource;
 struct block_t;
 
-struct vlc_http_live *vlc_http_live_create(struct vlc_http_mgr *mgr,
-                                           const char *uri, const char *ua,
-                                           const char *ref);
-void vlc_http_live_destroy(struct vlc_http_live *live);
+struct vlc_http_resource *vlc_http_live_create(struct vlc_http_mgr *mgr,
+                                               const char *uri, const char *ua,
+                                               const char *ref);
+struct block_t *vlc_http_live_read(struct vlc_http_resource *);
 
-int vlc_http_live_get_status(struct vlc_http_live *live);
-char *vlc_http_live_get_redirect(struct vlc_http_live *live);
-char *vlc_http_live_get_type(struct vlc_http_live *live);
-block_t *vlc_http_live_read(struct vlc_http_live *live);
+#define vlc_http_live_get_status vlc_http_res_get_status
+#define vlc_http_live_get_redirect vlc_http_res_get_redirect
+#define vlc_http_live_get_type vlc_http_res_get_type
+#define vlc_http_live_destroye vlc_http_res_destroy
 
 /** @} */
index 5e360fb..e666df6 100644 (file)
@@ -37,7 +37,7 @@
 #include "resource.h"
 
 static struct vlc_http_msg *
-vlc_http_res_req(const struct vlc_http_resource *res)
+vlc_http_res_req(const struct vlc_http_resource *res, void *opaque)
 {
     struct vlc_http_msg *req;
 
@@ -71,25 +71,24 @@ vlc_http_res_req(const struct vlc_http_resource *res)
 
     /* 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;
 }
 
 struct vlc_http_msg *vlc_http_res_open(struct vlc_http_resource *res,
-    int (*request_cb)(struct vlc_http_msg *, const struct vlc_http_resource *,
-                      void *), void *opaque)
+                                       void *opaque)
 {
     struct vlc_http_msg *req;
 retry:
-    req = vlc_http_res_req(res);
+    req = vlc_http_res_req(res, opaque);
     if (unlikely(req == NULL))
         return NULL;
 
-    if (request_cb(req, res, opaque))
-    {
-        vlc_http_msg_destroy(req);
-        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);
@@ -119,19 +118,48 @@ retry:
         goto retry;
     }
 
+    if (res->cbs->response_validate(res, resp, opaque))
+        goto fail;
+
     return resp;
 fail:
     vlc_http_msg_destroy(resp);
     return NULL;
 }
 
-void vlc_http_res_deinit(struct vlc_http_resource *res)
+int vlc_http_res_get_status(struct vlc_http_resource *res)
+{
+    if (res->response == NULL)
+    {
+        if (res->failure)
+            return -1;
+
+        res->response = vlc_http_res_open(res, res + 1);
+        if (res->response == NULL)
+        {
+            res->failure = true;
+            return -1;
+        }
+    }
+    return vlc_http_msg_get_status(res->response);
+}
+
+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);
+}
+
+void vlc_http_res_destroy(struct vlc_http_resource *res)
+{
+    vlc_http_res_deinit(res);
+    free(res);
 }
 
 static char *vlc_http_authority(const char *host, unsigned port)
@@ -147,8 +175,9 @@ static char *vlc_http_authority(const char *host, unsigned port)
 }
 
 int vlc_http_res_init(struct vlc_http_resource *restrict res,
-                      struct vlc_http_mgr *mgr, const char *uri,
-                      const char *ua, const char *ref)
+                      const struct vlc_http_resource_cbs *cbs,
+                      struct vlc_http_mgr *mgr,
+                      const char *uri, const char *ua, const char *ref)
 {
     vlc_url_t url;
     bool secure;
@@ -170,8 +199,11 @@ int vlc_http_res_init(struct vlc_http_resource *restrict res,
         goto error;
     }
 
+    res->cbs = cbs;
+    res->response = NULL;
     res->secure = secure;
     res->negotiate = true;
+    res->failure = false;
     res->host = strdup(url.psz_host);
     res->port = url.i_port;
     res->authority = vlc_http_authority(url.psz_host, url.i_port);
@@ -205,23 +237,24 @@ error:
     return -1;
 }
 
-char *vlc_http_res_get_redirect(const struct vlc_http_resource *restrict res,
-                                const struct vlc_http_msg *resp)
+char *vlc_http_res_get_redirect(struct vlc_http_resource *restrict res)
 {
-    int status = vlc_http_msg_get_status(resp);
+    int status = vlc_http_res_get_status(res);
+    if (status < 0)
+        return NULL;
 
     if ((status / 100) == 2 && !res->secure)
     {
         char *url;
 
         /* HACK: Seems like an MMS server. Redirect to MMSH scheme. */
-        if (vlc_http_msg_get_token(resp, "Pragma", "features") != NULL
+        if (vlc_http_msg_get_token(res->response, "Pragma", "features") != NULL
          && asprintf(&url, "mmsh://%s%s", res->authority, res->path) >= 0)
             return url;
 
         /* HACK: Seems like an ICY server. Redirect to ICYX scheme. */
-        if ((vlc_http_msg_get_header(resp, "Icy-Name") != NULL
-          || vlc_http_msg_get_header(resp, "Icy-Genre") != NULL)
+        if ((vlc_http_msg_get_header(res->response, "Icy-Name") != NULL
+          || vlc_http_msg_get_header(res->response, "Icy-Genre") != NULL)
          && asprintf(&url, "icyx://%s%s", res->authority, res->path) >= 0)
             return url;
     }
@@ -236,7 +269,7 @@ char *vlc_http_res_get_redirect(const struct vlc_http_resource *restrict res,
      || status == 306 /* Switch Proxy (former) */)
         return NULL;
 
-    const char *location = vlc_http_msg_get_header(resp, "Location");
+    const char *location = vlc_http_msg_get_header(res->response, "Location");
     if (location == NULL)
         return NULL;
 
@@ -260,21 +293,21 @@ char *vlc_http_res_get_redirect(const struct vlc_http_resource *restrict res,
     return strndup(location, len);
 }
 
-char *vlc_http_res_get_type(const struct vlc_http_msg *resp)
+char *vlc_http_res_get_type(struct vlc_http_resource *res)
 {
-    int status = vlc_http_msg_get_status(resp);
+    int status = vlc_http_res_get_status(res);
     if (status < 200 || status >= 300)
         return NULL;
 
-    const char *type = vlc_http_msg_get_header(resp, "Content-Type");
+    const char *type = vlc_http_msg_get_header(res->response, "Content-Type");
     return (type != NULL) ? strdup(type) : NULL;
 }
 
-struct block_t *vlc_http_res_read(struct vlc_http_msg *resp)
+struct block_t *vlc_http_res_read(struct vlc_http_resource *res)
 {
-    int status = vlc_http_msg_get_status(resp);
+    int status = vlc_http_res_get_status(res);
     if (status < 200 || status >= 300)
         return NULL; /* do not "read" redirect or error message */
 
-    return vlc_http_msg_read(resp);
+    return vlc_http_msg_read(res->response);
 }
index 587df70..5f42dd4 100644 (file)
@@ -18,6 +18,9 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
+#ifndef VLC_HTTP_RESOURCE_H
+#define VLC_HTTP_RESOURCE_H 1
+
 /**
  * \defgroup http_res Resources
  * Remote HTTP resources identified by a URL
 
 struct vlc_http_msg;
 struct vlc_http_mgr;
+struct vlc_http_resource;
+
+struct vlc_http_resource_cbs
+{
+    int (*request_format)(const struct vlc_http_resource *,
+                          struct vlc_http_msg *, void *);
+    int (*response_validate)(const struct vlc_http_resource *,
+                             const struct vlc_http_msg *, void *);
+};
 
 struct vlc_http_resource
 {
+    const struct vlc_http_resource_cbs *cbs;
+    struct vlc_http_msg *response;
     struct vlc_http_mgr *manager;
-    char *host;
-    unsigned port;
     bool secure;
     bool negotiate;
+    bool failure;
+    char *host;
+    unsigned port;
     char *authority;
     char *path;
     char *agent;
     char *referrer;
 };
 
-int vlc_http_res_init(struct vlc_http_resource *, struct vlc_http_mgr *mgr,
-                      const char *uri,const char *ua, const char *ref);
-void vlc_http_res_deinit(struct vlc_http_resource *);
+int vlc_http_res_init(struct vlc_http_resource *,
+                      const struct vlc_http_resource_cbs *cbs,
+                      struct vlc_http_mgr *mgr,
+                      const char *uri, const char *ua, const char *ref);
+
+/**
+ * Destroys an HTTP resource.
+ *
+ * Releases all underlying resources allocated or held by the HTTP resource
+ * object.
+ */
+void vlc_http_res_destroy(struct vlc_http_resource *);
+
+struct vlc_http_msg *vlc_http_res_open(struct vlc_http_resource *res, void *);
+int vlc_http_res_get_status(struct vlc_http_resource *res);
+
+/**
+ * Gets redirection URL.
+ *
+ * Checks if the resource URL lead to a redirection. If so, return the redirect
+ * location.
+ *
+ * @return Heap-allocated URL or NULL if no redirection.
+ */
+char *vlc_http_res_get_redirect(struct vlc_http_resource *);
+
+/**
+ * Gets MIME type.
+ *
+ * @return Heap-allocated MIME type string, or NULL if unknown.
+ */
+char *vlc_http_res_get_type(struct vlc_http_resource *);
 
-struct vlc_http_msg *vlc_http_res_open(struct vlc_http_resource *res,
-    int (*cb)(struct vlc_http_msg *req, const struct vlc_http_resource *,
-              void *), void *);
-char *vlc_http_res_get_redirect(const struct vlc_http_resource *,
-                                const struct vlc_http_msg *resp);
-char *vlc_http_res_get_type(const struct vlc_http_msg *resp);
-struct block_t *vlc_http_res_read(struct vlc_http_msg *resp);
+/**
+ * Reads data.
+ */
+struct block_t *vlc_http_res_read(struct vlc_http_resource *);
 
 /** @} */
+#endif