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