Hi,

I'd like to backport my fixes from the main branch. Patch attached --
original commits were:

c59654d67d1afde3fac24021ef0fd9d18cf38455
fca085187940a169b7a43d096009f7dac315f9ac
7859618affe574c9de7f240d2ddc016f917c37bd

Thanks in advance!
-- 
"The mark of an immature man is that he wants to die nobly for a
cause, while the mark of the mature man is that he wants to live
humbly for one."   --W. Stekel
From dec8b5b1033c63906e7b1e783bd50a2be287d8d5 Mon Sep 17 00:00:00 2001
From: Micah Galizia <micahgali...@gmail.com>
Date: Thu, 26 Mar 2015 20:16:34 +1100
Subject: [PATCH] backport hls and cookie fixes

---
 libavformat/hls.c  | 25 +++++++++++----------
 libavformat/http.c | 65 +++++++++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 65 insertions(+), 25 deletions(-)

diff --git a/libavformat/hls.c b/libavformat/hls.c
index 5e8e1b2..af890bd 100644
--- a/libavformat/hls.c
+++ b/libavformat/hls.c
@@ -903,6 +903,14 @@ static void intercept_id3(struct playlist *pls, uint8_t *buf,
         pls->is_id3_timestamped = (pls->id3_mpegts_timestamp != AV_NOPTS_VALUE);
 }
 
+static void update_options(char **dest, const char *name, void *src)
+{
+    av_freep(dest);
+    av_opt_get(src, name, 0, (uint8_t**)dest);
+    if (*dest && !strlen(*dest))
+        av_freep(dest);
+}
+
 static int open_input(HLSContext *c, struct playlist *pls)
 {
     AVDictionary *opts = NULL;
@@ -944,6 +952,8 @@ static int open_input(HLSContext *c, struct playlist *pls)
                     av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n",
                            seg->key);
                 }
+                update_options(&c->cookies, "cookies", uc->priv_data);
+                av_dict_set(&opts, "cookies", c->cookies, 0);
                 ffurl_close(uc);
             } else {
                 av_log(NULL, AV_LOG_ERROR, "Unable to open key file %s\n",
@@ -1252,22 +1262,13 @@ static int hls_read_header(AVFormatContext *s)
     // if the URL context is good, read important options we must broker later
     if (u && u->prot->priv_data_class) {
         // get the previous user agent & set back to null if string size is zero
-        av_freep(&c->user_agent);
-        av_opt_get(u->priv_data, "user-agent", 0, (uint8_t**)&(c->user_agent));
-        if (c->user_agent && !strlen(c->user_agent))
-            av_freep(&c->user_agent);
+        update_options(&c->user_agent, "user-agent", u->priv_data);
 
         // get the previous cookies & set back to null if string size is zero
-        av_freep(&c->cookies);
-        av_opt_get(u->priv_data, "cookies", 0, (uint8_t**)&(c->cookies));
-        if (c->cookies && !strlen(c->cookies))
-            av_freep(&c->cookies);
+        update_options(&c->cookies, "cookies", u->priv_data);
 
         // get the previous headers & set back to null if string size is zero
-        av_freep(&c->headers);
-        av_opt_get(u->priv_data, "headers", 0, (uint8_t**)&(c->headers));
-        if (c->headers && !strlen(c->headers))
-            av_freep(&c->headers);
+        update_options(&c->headers, "headers", u->priv_data);
     }
 
     if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0)
diff --git a/libavformat/http.c b/libavformat/http.c
index 55dcb6e..f4ac90c 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -77,6 +77,8 @@ typedef struct HTTPContext {
     int is_akamai;
     int is_mediagateway;
     char *cookies;          ///< holds newline (\n) delimited Set-Cookie header field values (without the "Set-Cookie: " field name)
+    /* A dictionary containing cookies keyed by cookie name */
+    AVDictionary *cookie_dict;
     int icy;
     /* how much data was read since the last ICY metadata packet */
     int icy_data_read;
@@ -464,6 +466,43 @@ static int parse_icy(HTTPContext *s, const char *tag, const char *p)
     return 0;
 }
 
+static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies)
+{
+    char *eql, *name;
+
+    // duplicate the cookie name (dict will dupe the value)
+    if (!(eql = strchr(p, '='))) return AVERROR(EINVAL);
+    if (!(name = av_strndup(p, eql - p))) return AVERROR(ENOMEM);
+
+    // add the cookie to the dictionary
+    av_dict_set(cookies, name, eql, AV_DICT_DONT_STRDUP_KEY);
+
+    return 0;
+}
+
+static int cookie_string(AVDictionary *dict, char **cookies)
+{
+    AVDictionaryEntry *e = NULL;
+    int len = 1;
+
+    // determine how much memory is needed for the cookies string
+    while (e = av_dict_get(dict, "", e, AV_DICT_IGNORE_SUFFIX))
+        len += strlen(e->key) + strlen(e->value) + 1;
+
+    // reallocate the cookies
+    e = NULL;
+    if (*cookies) av_free(*cookies);
+    *cookies = av_malloc(len);
+    if (!cookies) return AVERROR(ENOMEM);
+    *cookies[0] = '\0';
+
+    // write out the cookies
+    while (e = av_dict_get(dict, "", e, AV_DICT_IGNORE_SUFFIX))
+        av_strlcatf(*cookies, len, "%s%s\n", e->key, e->value);
+
+    return 0;
+}
+
 static int process_line(URLContext *h, char *line, int line_count,
                         int *new_location)
 {
@@ -535,19 +574,8 @@ static int process_line(URLContext *h, char *line, int line_count,
             av_free(s->mime_type);
             s->mime_type = av_strdup(p);
         } else if (!av_strcasecmp(tag, "Set-Cookie")) {
-            if (!s->cookies) {
-                if (!(s->cookies = av_strdup(p)))
-                    return AVERROR(ENOMEM);
-            } else {
-                char *tmp = s->cookies;
-                size_t str_size = strlen(tmp) + strlen(p) + 2;
-                if (!(s->cookies = av_malloc(str_size))) {
-                    s->cookies = tmp;
-                    return AVERROR(ENOMEM);
-                }
-                snprintf(s->cookies, str_size, "%s\n%s", tmp, p);
-                av_free(tmp);
-            }
+            if (parse_cookie(s, p, &s->cookie_dict))
+                av_log(h, AV_LOG_WARNING, "Unable to parse '%s'\n", p);
         } else if (!av_strcasecmp(tag, "Icy-MetaInt")) {
             s->icy_metaint = strtoll(p, NULL, 10);
         } else if (!av_strncasecmp(tag, "Icy-", 4)) {
@@ -578,12 +606,19 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path,
 
     if (!set_cookies) return AVERROR(EINVAL);
 
+    // destroy any cookies in the dictionary.
+    av_dict_free(&s->cookie_dict);
+
     *cookies = NULL;
     while ((cookie = av_strtok(set_cookies, "\n", &next))) {
         int domain_offset = 0;
         char *param, *next_param, *cdomain = NULL, *cpath = NULL, *cvalue = NULL;
         set_cookies = NULL;
 
+        // store the cookie in a dict in case it is updated in the response
+        if (parse_cookie(s, cookie, &s->cookie_dict))
+            av_log(s, AV_LOG_WARNING, "Unable to parse '%s'\n", cookie);
+
         while ((param = av_strtok(cookie, "; ", &next_param))) {
             if (cookie) {
                 // first key-value pair is the actual cookie value
@@ -691,6 +726,10 @@ static int http_read_header(URLContext *h, int *new_location)
     if (s->seekable == -1 && s->is_mediagateway && s->filesize == 2000000000)
         h->is_streamed = 1; /* we can in fact _not_ seek */
 
+    // add any new cookies into the existing cookie string
+    cookie_string(s->cookie_dict, &s->cookies);
+    av_dict_free(&s->cookie_dict);
+
     return err;
 }
 
-- 
2.1.0

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to