[vlc-devel] [PATCH] Proof of Concept: http: add range support

Francois Cartegnie fcvlcdev at free.fr
Mon Sep 12 20:07:32 CEST 2016


Variable hack for creating streamUrl with
Byte-Range support, required for switching
adaptive backend to regular access.

Also strips Range header for non ranged request.

Tests missing.
---
 modules/access/http/access.c    | 21 +++++++++++++---
 modules/access/http/file.c      | 55 ++++++++++++++++++++++++++++++-----------
 modules/access/http/file.h      |  3 ++-
 modules/access/http/file_test.c | 27 ++++++++++----------
 4 files changed, 74 insertions(+), 32 deletions(-)

diff --git a/modules/access/http/access.c b/modules/access/http/access.c
index 3f926db..d68273b 100644
--- a/modules/access/http/access.c
+++ b/modules/access/http/access.c
@@ -186,9 +186,18 @@ static int Open(vlc_object_t *obj)
     char *ua = var_InheritString(obj, "http-user-agent");
     char *referer = var_InheritString(obj, "http-referrer");
     bool live = var_InheritBool(obj, "http-continuous");
-
-    sys->resource = (live ? vlc_http_live_create : vlc_http_file_create)(
-        sys->manager, access->psz_url, ua, referer);
+    if(live)
+    {
+        sys->resource = vlc_http_live_create(sys->manager, access->psz_url,
+                                             ua, referer);
+    }
+    else
+    {
+        int64_t rangestart = var_InheritInteger(obj, "http-range-start");
+        int64_t rangeend = var_InheritInteger(obj, "http-range-end");
+        sys->resource = vlc_http_file_create( sys->manager, access->psz_url,
+                                              ua, referer, rangestart, ++rangeend);
+    }
     free(referer);
     free(ua);
 
@@ -314,4 +323,10 @@ vlc_module_begin()
                   "e.g. \"FooBar/1.2.3\"."), true)
         change_safe()
         change_private()
+    add_integer("http-range-start", 0, NULL, NULL, true)
+        change_safe()
+        change_volatile()
+    add_integer("http-range-end", -1, NULL, NULL, true)
+        change_safe()
+        change_volatile()
 vlc_module_end()
diff --git a/modules/access/http/file.c b/modules/access/http/file.c
index ce101f6..7a61765 100644
--- a/modules/access/http/file.c
+++ b/modules/access/http/file.c
@@ -38,18 +38,23 @@
 #include "file.h"
 
 #pragma GCC visibility push(default)
+struct vlc_http_file_range
+{
+    uintmax_t start;
+    uintmax_t endplusone;
+};
 
 struct vlc_http_file
 {
     struct vlc_http_resource resource;
-    uintmax_t offset;
+    struct vlc_http_file_range range;
 };
 
 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;
+    const struct vlc_http_file_range *range = opaque;
 
     if (file->resource.response != NULL)
     {
@@ -69,16 +74,27 @@ static int vlc_http_file_req(const struct vlc_http_resource *res,
         }
     }
 
-    if (vlc_http_msg_add_header(req, "Range", "bytes=%ju-", *offset)
-     && *offset != 0)
-        return -1;
+    if(range->start != 0 || range->endplusone)
+    {
+        if(range->endplusone)
+        {
+            if (vlc_http_msg_add_header(req, "Range", "bytes=%ju-%ju",
+                                        range->start, range->endplusone - 1))
+                return -1;
+        }
+        else if(vlc_http_msg_add_header(req, "Range", "bytes=%ju-", range->start))
+        {
+            return -1;
+        }
+    }
     return 0;
 }
 
 static int vlc_http_file_resp(const struct vlc_http_resource *res,
                               const struct vlc_http_msg *resp, void *opaque)
 {
-    const uintmax_t *offset = opaque;
+    const struct vlc_http_file_range *range = opaque;
+    struct vlc_http_file *file = (struct vlc_http_file *)res;
 
     if (vlc_http_msg_get_status(resp) == 206)
     {
@@ -90,13 +106,15 @@ static int vlc_http_file_resp(const struct vlc_http_resource *res,
 
         uintmax_t start, end;
         if (sscanf(str, "bytes %ju-%ju", &start, &end) != 2
-         || start != *offset || start > end)
+         || start != range->start || start > end
+         || (range->endplusone && end != range->endplusone - 1))
             /* A single range response is what we asked for, but not at that
              * start offset. */
             goto fail;
+        file->range.start = start;
+        file->range.endplusone = end + 1;
     }
 
-    (void) res;
     return 0;
 
 fail:
@@ -112,7 +130,9 @@ static const struct vlc_http_resource_cbs vlc_http_file_callbacks =
 
 struct vlc_http_resource *vlc_http_file_create(struct vlc_http_mgr *mgr,
                                                const char *uri, const char *ua,
-                                               const char *ref)
+                                               const char *ref,
+                                               uintmax_t rangestart,
+                                               uintmax_t rangeendplusone)
 {
     struct vlc_http_file *file = malloc(sizeof (*file));
     if (unlikely(file == NULL))
@@ -125,7 +145,8 @@ struct vlc_http_resource *vlc_http_file_create(struct vlc_http_mgr *mgr,
         return NULL;
     }
 
-    file->offset = 0;
+    file->range.start = rangestart;
+    file->range.endplusone = rangeendplusone;
     return &file->resource;
 }
 
@@ -203,7 +224,11 @@ bool vlc_http_file_can_seek(struct vlc_http_resource *res)
 
 int vlc_http_file_seek(struct vlc_http_resource *res, uintmax_t offset)
 {
-    struct vlc_http_msg *resp = vlc_http_res_open(res, &offset);
+    struct vlc_http_file_range range;
+    range.start = offset;
+    range.endplusone = 0;
+
+    struct vlc_http_msg *resp = vlc_http_res_open(res, &range);
     if (resp == NULL)
         return -1;
 
@@ -225,7 +250,7 @@ int vlc_http_file_seek(struct vlc_http_resource *res, uintmax_t offset)
     }
 
     res->response = resp;
-    file->offset = offset;
+    file->range = range;
     return 0;
 }
 
@@ -238,8 +263,8 @@ block_t *vlc_http_file_read(struct vlc_http_resource *res)
     {   /* Automatically reconnect on error if server supports seek */
         if (res->response != NULL
          && vlc_http_msg_can_seek(res->response)
-         && file->offset < vlc_http_msg_get_file_size(res->response)
-         && vlc_http_file_seek(res, file->offset) == 0)
+         && file->range.start < vlc_http_msg_get_file_size(res->response)
+         && vlc_http_file_seek(res, file->range.start) == 0)
             block = vlc_http_res_read(res);
 
         if (block == vlc_http_error)
@@ -249,6 +274,6 @@ block_t *vlc_http_file_read(struct vlc_http_resource *res)
     if (block == NULL)
         return NULL; /* End of stream */
 
-    file->offset += block->i_buffer;
+    file->range.start += block->i_buffer;
     return block;
 }
diff --git a/modules/access/http/file.h b/modules/access/http/file.h
index 802cf8f..6946f8f 100644
--- a/modules/access/http/file.h
+++ b/modules/access/http/file.h
@@ -44,7 +44,8 @@ struct block_t;
  */
 struct vlc_http_resource *vlc_http_file_create(struct vlc_http_mgr *mgr,
                                                const char *url, const char *ua,
-                                               const char *ref);
+                                               const char *ref,
+                                               uintmax_t, uintmax_t);
 
 /**
  * Gets file size.
diff --git a/modules/access/http/file_test.c b/modules/access/http/file_test.c
index 64fab07..6155df8 100644
--- a/modules/access/http/file_test.c
+++ b/modules/access/http/file_test.c
@@ -57,7 +57,7 @@ int main(void)
     jar = vlc_http_cookies_new();
 
     /* Request failure test */
-    f = vlc_http_file_create(NULL, url, ua, NULL);
+    f = vlc_http_file_create(NULL, url, ua, NULL, 0, 0);
     assert(f != NULL);
     vlc_http_res_set_login(f, NULL, NULL);
     vlc_http_res_set_login(f, "john", NULL);
@@ -81,7 +81,7 @@ int main(void)
 
     offset = 0;
     etags = true;
-    f = vlc_http_file_create(NULL, url, ua, NULL);
+    f = vlc_http_file_create(NULL, url, ua, NULL, 0, 0);
     assert(f != NULL);
     assert(vlc_http_file_get_status(f) == 200);
     assert(!vlc_http_file_can_seek(f));
@@ -104,7 +104,7 @@ int main(void)
                  "\r\n";
 
     offset = 0;
-    f = vlc_http_file_create(NULL, url, ua, NULL);
+    f = vlc_http_file_create(NULL, url, ua, NULL, 0, 0);
     assert(f != NULL);
     assert(vlc_http_file_can_seek(f));
     assert(vlc_http_file_get_size(f) == 2345);
@@ -139,7 +139,7 @@ int main(void)
                  "\r\n";
 
     offset = 0;
-    f = vlc_http_file_create(NULL, url, ua, NULL);
+    f = vlc_http_file_create(NULL, url, ua, NULL, 0, 0);
     assert(f != NULL);
     assert(!vlc_http_file_can_seek(f));
     assert(vlc_http_file_get_size(f) == (uintmax_t)-1);
@@ -156,7 +156,7 @@ int main(void)
                  "Content-Length: 9999\r\n"
                  "\r\n";
     offset = 0;
-    f = vlc_http_file_create(NULL, url, ua, NULL);
+    f = vlc_http_file_create(NULL, url, ua, NULL, 0, 0);
     assert(f != NULL);
     assert(vlc_http_file_get_size(f) == 9999);
     assert(vlc_http_file_get_redirect(f) == NULL);
@@ -170,7 +170,7 @@ int main(void)
 
     offset = 0;
     etags = false;
-    f = vlc_http_file_create(NULL, url, ua, NULL);
+    f = vlc_http_file_create(NULL, url, ua, NULL, 0, 0);
     assert(f != NULL);
     assert(vlc_http_file_can_seek(f));
 
@@ -187,7 +187,7 @@ int main(void)
                  "\r\n";
     offset = 0;
 
-    f = vlc_http_file_create(NULL, url, ua, NULL);
+    f = vlc_http_file_create(NULL, url, ua, NULL, 0, 0);
     assert(f != NULL);
     assert(vlc_http_file_get_size(f) == (uintmax_t)-1);
 
@@ -238,7 +238,7 @@ int main(void)
 
     secure = false;
     lang = -1;
-    f = vlc_http_file_create(NULL, url_http, ua, NULL);
+    f = vlc_http_file_create(NULL, url_http, ua, NULL, 0, 0);
     assert(f != NULL);
 
     /* Protocol redirect hacks - over insecure HTTP */
@@ -260,11 +260,11 @@ int main(void)
     vlc_http_file_destroy(f);
 
     /* Dummy API calls */
-    f = vlc_http_file_create(NULL, "ftp://localhost/foo", NULL, NULL);
+    f = vlc_http_file_create(NULL, "ftp://localhost/foo", NULL, NULL, 0, 0);
     assert(f == NULL);
-    f = vlc_http_file_create(NULL, "/foo", NULL, NULL);
+    f = vlc_http_file_create(NULL, "/foo", NULL, NULL, 0, 0);
     assert(f == NULL);
-    f = vlc_http_file_create(NULL, "http://www.example.com", NULL, NULL);
+    f = vlc_http_file_create(NULL, "http://www.example.com", NULL, NULL, 0, 0);
     assert(f != NULL);
     vlc_http_file_destroy(f);
 
@@ -370,8 +370,9 @@ struct vlc_http_msg *vlc_http_mgr_request(struct vlc_http_mgr *mgr, bool https,
         assert(str == NULL);
 
     str = vlc_http_msg_get_header(req, "Range");
-    assert(str != NULL && !strncmp(str, "bytes=", 6)
-        && strtoul(str + 6, &end, 10) == offset && *end == '-');
+    assert((str == NULL && offset == 0)
+           || (str != NULL && !strncmp(str, "bytes=", 6)
+           && strtoul(str + 6, &end, 10) == offset && *end == '-' ));
 
     time_t mtime = vlc_http_msg_get_time(req, "If-Unmodified-Since");
     str = vlc_http_msg_get_header(req, "If-Match");
-- 
2.7.4



More information about the vlc-devel mailing list