Always append a null character when reading HLS playlist
authorLuc Saillard <luc.saillard@sfr.com>
Wed, 20 Jul 2011 15:01:04 +0000 (17:01 +0200)
committerJean-Baptiste Kempf <jb@videolan.org>
Fri, 22 Jul 2011 00:18:32 +0000 (02:18 +0200)
The httplive module doesn't always append a null character after reading the
playlist. Many str* function is used on the playlist buffer (strstr, printf,
...). We must ensure that the buffer is null terminated, else we will read
random data.

We also have two functions readM3u8() and read_M3u8() that does the same
job. Rewrite it into read_M3U8_from_url() and read_M3U8_from_stream().

Signed-off-by: Jean-Baptiste Kempf <jb@videolan.org>
modules/stream_filter/httplive.c

index 28e0ba4..7994430 100644 (file)
@@ -40,6 +40,7 @@
 #include <vlc_arrays.h>
 #include <vlc_stream.h>
 #include <vlc_url.h>
+#include <vlc_memory.h>
 
 /*****************************************************************************
  * Module descriptor
@@ -135,8 +136,8 @@ static int  Read   (stream_t *, void *p_read, unsigned int i_read);
 static int  Peek   (stream_t *, const uint8_t **pp_peek, unsigned int i_peek);
 static int  Control(stream_t *, int i_query, va_list);
 
-static ssize_t read_M3U8(stream_t *s, vlc_url_t *url, uint8_t **buffer);
-static ssize_t ReadM3U8(stream_t *s, uint8_t **buffer);
+static ssize_t read_M3U8_from_stream(stream_t *s, uint8_t **buffer);
+static ssize_t read_M3U8_from_url(stream_t *s, vlc_url_t *url, uint8_t **buffer);
 static char *ReadLine(uint8_t *buffer, uint8_t **pos, size_t len);
 
 static int hls_Download(stream_t *s, segment_t *segment);
@@ -848,7 +849,7 @@ static int parse_M3U8(stream_t *s, vlc_array_t *streams, uint8_t *buffer, const
 
                     /* Download playlist file from server */
                     uint8_t *buf = NULL;
-                    ssize_t len = read_M3U8(s, &hls->url, &buf);
+                    ssize_t len = read_M3U8_from_url(s, &hls->url, &buf);
                     if (len < 0)
                         err = VLC_EGENERIC;
                     else
@@ -965,7 +966,7 @@ static int get_HTTPLiveMetaPlaylist(stream_t *s, vlc_array_t **streams)
 
     /* Download new playlist file from server */
     uint8_t *buffer = NULL;
-    ssize_t len = read_M3U8(s, &p_sys->m3u8, &buffer);
+    ssize_t len = read_M3U8_from_url(s, &p_sys->m3u8, &buffer);
     if (len < 0)
         return VLC_EGENERIC;
 
@@ -1411,79 +1412,64 @@ static int hls_Download(stream_t *s, segment_t *segment)
 }
 
 /* Read M3U8 file */
-static ssize_t read_M3U8(stream_t *s, vlc_url_t *url, uint8_t **buffer)
+static ssize_t read_M3U8_from_stream(stream_t *s, uint8_t **buffer)
 {
-    assert(*buffer == NULL);
+    int64_t total_bytes = 0;
+    int64_t total_allocated = 0;
+    uint8_t *p = NULL;
 
-    /* Construct URL */
-    char *psz_url = ConstructUrl(url);
-    if (psz_url == NULL)
-           return VLC_ENOMEM;
+    while (1)
+    {
+        char buf[4096];
+        int64_t bytes;
 
-    stream_t *p_m3u8 = stream_UrlNew(s, psz_url);
-    free(psz_url);
-    if (p_m3u8 == NULL)
-        return VLC_EGENERIC;
+        bytes = stream_Read(s, buf, sizeof(buf));
+        if (bytes == 0)
+            break;      /* EOF ? */
+        else if (bytes < 0)
+            return bytes;
 
-    int64_t size = stream_Size(p_m3u8);
-    if (size == 0) size = 8192; /* no Content-Length */
+        if ( (total_bytes + bytes + 1) > total_allocated )
+        {
+            if (total_allocated)
+                total_allocated *= 2;
+            else
+                total_allocated = __MIN(bytes+1, sizeof(buf));
 
-    *buffer = calloc(1, size);
-    if (*buffer == NULL)
-    {
-        stream_Delete(p_m3u8);
-        return VLC_ENOMEM;
+            p = realloc_or_free(p, total_allocated);
+            if (p == NULL)
+                return VLC_ENOMEM;
+        }
+
+        memcpy(p+total_bytes, buf, bytes);
+        total_bytes += bytes;
     }
 
-    int64_t len = 0, curlen = 0;
-    do {
-        int read = ((size - curlen) >= INT_MAX) ? INT_MAX : (size - curlen);
-        len = stream_Read(p_m3u8, *buffer + curlen, read);
-        if (len <= 0)
-            break;
-        curlen += len;
-        if (curlen >= size)
-        {
-            uint8_t *tmp = realloc(*buffer, size + 8192);
-            if (tmp == NULL)
-                break;
-            size += 8192;
-            *buffer = tmp;
-        }
-    } while (vlc_object_alive(s));
-    stream_Delete(p_m3u8);
+    if (total_allocated == 0)
+        return VLC_EGENERIC;
 
-    (*buffer)[curlen-1] = '\0';
-    return size;
+    p[total_bytes] = '\0';
+    *buffer = p;
+
+    return total_bytes;
 }
 
-static ssize_t ReadM3U8(stream_t *s, uint8_t **buffer)
+static ssize_t read_M3U8_from_url(stream_t *s, vlc_url_t *url, uint8_t **buffer)
 {
     assert(*buffer == NULL);
 
-    int64_t size = stream_Size(s->p_source);
-    if (size == 0) size = 1024; /* no Content-Length */
+    /* Construct URL */
+    char *psz_url = ConstructUrl(url);
+    if (psz_url == NULL)
+           return VLC_ENOMEM;
 
-    *buffer = calloc(1, size);
-    if (*buffer == NULL)
-        return VLC_ENOMEM;
+    stream_t *p_m3u8 = stream_UrlNew(s, psz_url);
+    free(psz_url);
+    if (p_m3u8 == NULL)
+        return VLC_EGENERIC;
 
-    int64_t len = 0, curlen = 0;
-    do {
-        int read = ((size - curlen) >= INT_MAX) ? INT_MAX : (size - curlen);
-        len = stream_Read(s->p_source, *buffer + curlen, read);
-        if (len <= 0)
-            break;
-        curlen += len;
-        if (curlen >= size)
-        {
-            uint8_t *tmp = realloc(*buffer, size + 1024);
-            if (tmp == NULL)
-                break;
-            size += 1024;
-            *buffer = tmp;
-        }
-    } while (vlc_object_alive(s));
+    ssize_t size = read_M3U8_from_stream(p_m3u8, buffer);
+    stream_Delete(p_m3u8);
 
     return size;
 }
@@ -1566,7 +1552,7 @@ static int Open(vlc_object_t *p_this)
 
     /* Parse HLS m3u8 content. */
     uint8_t *buffer = NULL;
-    ssize_t len = ReadM3U8(s, &buffer);
+    ssize_t len = read_M3U8_from_stream(s->p_source, &buffer);
     if (len < 0)
         goto fail;
     if (parse_M3U8(s, p_sys->hls_stream, buffer, len) != VLC_SUCCESS)