Re: [FFmpeg-devel] Backport HLS Cookie Authentication Fixes to 3.3
On 2017-06-01 09:04 PM, Michael Niedermayer wrote: On Tue, May 30, 2017 at 09:29:53PM -0400, Micah Galizia wrote: Hello, I'd like to backport the HLS cookie authentication fixes to 3.3 so that Kodi 18 picks them up. Originally, this was a three patch set but the first fix (to av_small_strptime) is already in 3.3 and doesn't need to be backported. The two that are still required are: - c4c73020f4bbf261f0b263be82de575c17fa5a60 (hls) - 28b24670741e1de25bfc7b5ea7c1d6dbae1aef6f (http) Hopefully this is acceptable - let me know if anything is out of order. applied thx Excellent, TYVM. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH 1/2] libavformat/http: Ignore expired cookies
Signed-off-by: Micah Galizia <micahgali...@gmail.com> Signed-off-by: Michael Niedermayer <mich...@niedermayer.cc> (cherry picked from commit 28b24670741e1de25bfc7b5ea7c1d6dbae1aef6f) Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/http.c | 213 +++-- 1 file changed, 156 insertions(+), 57 deletions(-) diff --git a/libavformat/http.c b/libavformat/http.c index 293a8a7204..d06103ab6d 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -29,6 +29,7 @@ #include "libavutil/avstring.h" #include "libavutil/opt.h" #include "libavutil/time.h" +#include "libavutil/parseutils.h" #include "avformat.h" #include "http.h" @@ -48,6 +49,8 @@ #define MAX_REDIRECTS 8 #define HTTP_SINGLE 1 #define HTTP_MUTLI2 +#define MAX_EXPIRY19 +#define WHITESPACES " \n\t\r" typedef enum { LOWER_PROTO, READ_HEADERS, @@ -680,10 +683,112 @@ static int parse_icy(HTTPContext *s, const char *tag, const char *p) return 0; } +static int parse_set_cookie_expiry_time(const char *exp_str, struct tm *buf) +{ +char exp_buf[MAX_EXPIRY]; +int i, j, exp_buf_len = MAX_EXPIRY-1; +char *expiry; + +// strip off any punctuation or whitespace +for (i = 0, j = 0; exp_str[i] != '\0' && j < exp_buf_len; i++) { +if ((exp_str[i] >= '0' && exp_str[i] <= '9') || +(exp_str[i] >= 'A' && exp_str[i] <= 'Z') || +(exp_str[i] >= 'a' && exp_str[i] <= 'z')) { +exp_buf[j] = exp_str[i]; +j++; +} +} +exp_buf[j] = '\0'; +expiry = exp_buf; + +// move the string beyond the day of week +while ((*expiry < '0' || *expiry > '9') && *expiry != '\0') +expiry++; + +return av_small_strptime(expiry, "%d%b%Y%H%M%S", buf) ? 0 : AVERROR(EINVAL); +} + +static int parse_set_cookie(const char *set_cookie, AVDictionary **dict) +{ +char *param, *next_param, *cstr, *back; + +if (!(cstr = av_strdup(set_cookie))) +return AVERROR(EINVAL); + +// strip any trailing whitespace +back = [strlen(cstr)-1]; +while (strchr(WHITESPACES, *back)) { +*back='\0'; +back--; +} + +next_param = cstr; +while ((param = av_strtok(next_param, ";", _param))) { +char *name, *value; +param += strspn(param, WHITESPACES); +if ((name = av_strtok(param, "=", ))) { +if (av_dict_set(dict, name, value, 0) < 0) { +av_free(cstr); +return -1; +} +} +} + +av_free(cstr); +return 0; +} + static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies) { +AVDictionary *new_params = NULL; +AVDictionaryEntry *e, *cookie_entry; char *eql, *name; +// ensure the cookie is parsable +if (parse_set_cookie(p, _params)) +return -1; + +// if there is no cookie value there is nothing to parse +cookie_entry = av_dict_get(new_params, "", NULL, AV_DICT_IGNORE_SUFFIX); +if (!cookie_entry || !cookie_entry->value) { +av_dict_free(_params); +return -1; +} + +// ensure the cookie is not expired or older than an existing value +if ((e = av_dict_get(new_params, "expires", NULL, 0)) && e->value) { +struct tm new_tm = {0}; +if (!parse_set_cookie_expiry_time(e->value, _tm)) { +AVDictionaryEntry *e2; + +// if the cookie has already expired ignore it +if (av_timegm(_tm) < av_gettime() / 100) { +av_dict_free(_params); +return -1; +} + +// only replace an older cookie with the same name +e2 = av_dict_get(*cookies, cookie_entry->key, NULL, 0); +if (e2 && e2->value) { +AVDictionary *old_params = NULL; +if (!parse_set_cookie(p, _params)) { +e2 = av_dict_get(old_params, "expires", NULL, 0); +if (e2 && e2->value) { +struct tm old_tm = {0}; +if (!parse_set_cookie_expiry_time(e->value, _tm)) { +if (av_timegm(_tm) < av_timegm(_tm)) { +av_dict_free(_params); +av_dict_free(_params); +return -1; +} +} +} +} +av_dict_free(_params); +} +} +} + // 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); @@ -868,7 +973,7 @
[FFmpeg-devel] [PATCH 2/2] libavformat/hls: Observe Set-Cookie headers
Signed-off-by: Micah Galizia <micahgali...@gmail.com> Signed-off-by: Michael Niedermayer <mich...@niedermayer.cc> (cherry picked from commit c4c73020f4bbf261f0b263be82de575c17fa5a60) Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/hls.c | 12 ++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index bac53a4350..42022690f1 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -630,8 +630,16 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, ret = s->io_open(s, pb, url, AVIO_FLAG_READ, ); if (ret >= 0) { // update cookies on http response with setcookies. -void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; -update_options(>cookies, "cookies", u); +char *new_cookies = NULL; + +if (!(s->flags & AVFMT_FLAG_CUSTOM_IO)) +av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, (uint8_t**)_cookies); + +if (new_cookies) { +av_free(c->cookies); +c->cookies = new_cookies; +} + av_dict_set(, "cookies", c->cookies, 0); } -- 2.11.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] Backport HLS Cookie Authentication Fixes to 3.3
Hello, I'd like to backport the HLS cookie authentication fixes to 3.3 so that Kodi 18 picks them up. Originally, this was a three patch set but the first fix (to av_small_strptime) is already in 3.3 and doesn't need to be backported. The two that are still required are: - c4c73020f4bbf261f0b263be82de575c17fa5a60 (hls) - 28b24670741e1de25bfc7b5ea7c1d6dbae1aef6f (http) Hopefully this is acceptable - let me know if anything is out of order. Thanks, ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] libavformat/hls: Observe Set-Cookie headers
On 2017-05-28 08:44 PM, Michael Niedermayer wrote: On Fri, May 26, 2017 at 09:29:04PM -0400, Micah Galizia wrote: On Sat, May 20, 2017 at 9:36 PM, Micah Galizia <micahgali...@gmail.com> wrote: On 2017-05-17 05:23 AM, wm4 wrote: On Sat, 6 May 2017 14:28:10 -0400 Micah Galizia <micahgali...@gmail.com> wrote: On 2017-05-05 09:28 PM, wm4 wrote: On Fri, 5 May 2017 20:55:05 -0400 Micah Galizia <micahgali...@gmail.com> wrote: Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/hls.c | 12 ++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index bac53a4350..bda9abecfa 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -630,8 +630,16 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, ret = s->io_open(s, pb, url, AVIO_FLAG_READ, ); if (ret >= 0) { // update cookies on http response with setcookies. -void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; -update_options(>cookies, "cookies", u); +char *new_cookies = NULL; + +if (s->flags ^ AVFMT_FLAG_CUSTOM_IO) +av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, (uint8_t**)_cookies); Did you mean & instead of ^? No, the original code was structured to set *u to null (and thus did not copy cookies) iff AVFMT_FLAG_CUSTOM_IO was set in the flags. So using ^ is logically equivalent -- cookies are copied only if AVFMT_FLAG_CUSTOM_IO is not set. Did you find out yet what difference AVFMT_FLAG_CUSTOM_IO is supposed to make in the existing code? Yes, I wrote back about it a day or two ago... here is the reference to its original inclusion: https://lists.ffmpeg.org/pipermail/ffmpeg-trac/2013-February/013020.html. When the code was originally implemented we were using s->pb->opaque, which in FFMPEG we could assume was a URLContext with options (one of them possibly being "cookies"). Based on the email above, that wasn't true for other apps like mplayer, and could cause crashes trying to treat opaque as a URLContext. So that is the purpose of checking the AVFMT_FLAG_CUSTOM_IO flag (way back in 2013). Now though, we don't seem to touch opaque at all. The options are stored in AVIOContext's av_class, which does have options. Based on this I think both patches are safe: this version has less change, but the original gets rid of the check against AVFMT_FLAG_CUSTOM_IO that I don't think we need anymore. I hope that clears things up. Sorry, I missed that. I guess this code is an artifact of some severely unclean hook up of the AVOPtion API to AVIOContext, that breaks with custom I/O. I guess your patch is fine then. I just wonder how an API user is supposed to pass along cookies then. My code passes an AVDictionary via a "cookies" entry when opening the HLS demuxer with custom I/O, so I was wondering whether the patch changes behavior here. I wouldn't have expected anyone to pass the cookies to the HLS demuxer directly -- there is an http protocol AVOption that should pass it along to the demuxer. But I guess thats the whole point of the custom IO, right? It'd replace the http demuxer? Even so, I don't think this is a good reason to hold up the the patch - it corrects the problem for apps that use the http protocol and maintains the existing behavior -- cookies are not (and were not) copied when the custom flag is set because u was set to null. Am I wrong in that interpretation of the existing behavior? Hi, What else do I need to do to get this fix checked in? patch applied thx TYVM! ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] libavformat/hls: Observe Set-Cookie headers
On Sat, May 20, 2017 at 9:36 PM, Micah Galizia <micahgali...@gmail.com> wrote: > On 2017-05-17 05:23 AM, wm4 wrote: >> >> On Sat, 6 May 2017 14:28:10 -0400 >> Micah Galizia <micahgali...@gmail.com> wrote: >> >>> On 2017-05-05 09:28 PM, wm4 wrote: >>>> >>>> On Fri, 5 May 2017 20:55:05 -0400 >>>> Micah Galizia <micahgali...@gmail.com> wrote: >>>> >>>>> >>>>> Signed-off-by: Micah Galizia <micahgali...@gmail.com> >>>>> --- >>>>>libavformat/hls.c | 12 ++-- >>>>>1 file changed, 10 insertions(+), 2 deletions(-) >>>>> >>>>> diff --git a/libavformat/hls.c b/libavformat/hls.c >>>>> index bac53a4350..bda9abecfa 100644 >>>>> --- a/libavformat/hls.c >>>>> +++ b/libavformat/hls.c >>>>> @@ -630,8 +630,16 @@ static int open_url(AVFormatContext *s, >>>>> AVIOContext **pb, const char *url, >>>>>ret = s->io_open(s, pb, url, AVIO_FLAG_READ, ); >>>>>if (ret >= 0) { >>>>>// update cookies on http response with setcookies. >>>>> -void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; >>>>> -update_options(>cookies, "cookies", u); >>>>> +char *new_cookies = NULL; >>>>> + >>>>> +if (s->flags ^ AVFMT_FLAG_CUSTOM_IO) >>>>> +av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, >>>>> (uint8_t**)_cookies); >>>> >>>> Did you mean & instead of ^? >>> >>> No, the original code was structured to set *u to null (and thus did not >>> copy cookies) iff AVFMT_FLAG_CUSTOM_IO was set in the flags. So using ^ >>> is logically equivalent -- cookies are copied only if >>> AVFMT_FLAG_CUSTOM_IO is not set. >>> >>>> Did you find out yet what difference AVFMT_FLAG_CUSTOM_IO is supposed >>>> to make in the existing code? >>> >>> Yes, I wrote back about it a day or two ago... here is the reference to >>> its original inclusion: >>> https://lists.ffmpeg.org/pipermail/ffmpeg-trac/2013-February/013020.html. >>> When the code was originally implemented we were using s->pb->opaque, >>> which in FFMPEG we could assume was a URLContext with options (one of >>> them possibly being "cookies"). >>> >>> Based on the email above, that wasn't true for other apps like mplayer, >>> and could cause crashes trying to treat opaque as a URLContext. So that >>> is the purpose of checking the AVFMT_FLAG_CUSTOM_IO flag (way back in >>> 2013). >>> >>> Now though, we don't seem to touch opaque at all. The options are stored >>> in AVIOContext's av_class, which does have options. Based on this I >>> think both patches are safe: this version has less change, but the >>> original gets rid of the check against AVFMT_FLAG_CUSTOM_IO that I don't >>> think we need anymore. >>> >>> I hope that clears things up. >> >> Sorry, I missed that. I guess this code is an artifact of some severely >> unclean hook up of the AVOPtion API to AVIOContext, that breaks with >> custom I/O. I guess your patch is fine then. >> >> I just wonder how an API user is supposed to pass along cookies then. >> My code passes an AVDictionary via a "cookies" entry when opening the >> HLS demuxer with custom I/O, so I was wondering whether the patch >> changes behavior here. > > > I wouldn't have expected anyone to pass the cookies to the HLS demuxer > directly -- there is an http protocol AVOption that should pass it along to > the demuxer. But I guess thats the whole point of the custom IO, right? It'd > replace the http demuxer? > > Even so, I don't think this is a good reason to hold up the the patch - it > corrects the problem for apps that use the http protocol and maintains the > existing behavior -- cookies are not (and were not) copied when the custom > flag is set because u was set to null. Am I wrong in that interpretation of > the existing behavior? Hi, What else do I need to do to get this fix checked in? Thanks -- "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 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] libavformat/hls: Observe Set-Cookie headers
On 2017-05-17 05:23 AM, wm4 wrote: On Sat, 6 May 2017 14:28:10 -0400 Micah Galizia <micahgali...@gmail.com> wrote: On 2017-05-05 09:28 PM, wm4 wrote: On Fri, 5 May 2017 20:55:05 -0400 Micah Galizia <micahgali...@gmail.com> wrote: Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/hls.c | 12 ++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index bac53a4350..bda9abecfa 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -630,8 +630,16 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, ret = s->io_open(s, pb, url, AVIO_FLAG_READ, ); if (ret >= 0) { // update cookies on http response with setcookies. -void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; -update_options(>cookies, "cookies", u); +char *new_cookies = NULL; + +if (s->flags ^ AVFMT_FLAG_CUSTOM_IO) +av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, (uint8_t**)_cookies); Did you mean & instead of ^? No, the original code was structured to set *u to null (and thus did not copy cookies) iff AVFMT_FLAG_CUSTOM_IO was set in the flags. So using ^ is logically equivalent -- cookies are copied only if AVFMT_FLAG_CUSTOM_IO is not set. Did you find out yet what difference AVFMT_FLAG_CUSTOM_IO is supposed to make in the existing code? Yes, I wrote back about it a day or two ago... here is the reference to its original inclusion: https://lists.ffmpeg.org/pipermail/ffmpeg-trac/2013-February/013020.html. When the code was originally implemented we were using s->pb->opaque, which in FFMPEG we could assume was a URLContext with options (one of them possibly being "cookies"). Based on the email above, that wasn't true for other apps like mplayer, and could cause crashes trying to treat opaque as a URLContext. So that is the purpose of checking the AVFMT_FLAG_CUSTOM_IO flag (way back in 2013). Now though, we don't seem to touch opaque at all. The options are stored in AVIOContext's av_class, which does have options. Based on this I think both patches are safe: this version has less change, but the original gets rid of the check against AVFMT_FLAG_CUSTOM_IO that I don't think we need anymore. I hope that clears things up. Sorry, I missed that. I guess this code is an artifact of some severely unclean hook up of the AVOPtion API to AVIOContext, that breaks with custom I/O. I guess your patch is fine then. I just wonder how an API user is supposed to pass along cookies then. My code passes an AVDictionary via a "cookies" entry when opening the HLS demuxer with custom I/O, so I was wondering whether the patch changes behavior here. I wouldn't have expected anyone to pass the cookies to the HLS demuxer directly -- there is an http protocol AVOption that should pass it along to the demuxer. But I guess thats the whole point of the custom IO, right? It'd replace the http demuxer? Even so, I don't think this is a good reason to hold up the the patch - it corrects the problem for apps that use the http protocol and maintains the existing behavior -- cookies are not (and were not) copied when the custom flag is set because u was set to null. Am I wrong in that interpretation of the existing behavior? Thanks, ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] libavformat/hls: Observe Set-Cookie headers
On 2017-05-16 04:57 PM, Michael Niedermayer wrote: On Sat, May 06, 2017 at 02:28:10PM -0400, Micah Galizia wrote: On 2017-05-05 09:28 PM, wm4 wrote: Did you mean & instead of ^? No, the original code was structured to set *u to null (and thus did not copy cookies) iff AVFMT_FLAG_CUSTOM_IO was set in the flags. So using ^ is logically equivalent -- cookies are copied only if AVFMT_FLAG_CUSTOM_IO is not set. it would also copy if another flag is set, is that intended ? ... I think that is what wm4 was getting at too. That is wrong and not intended. I'll resubmit with !(a) which is the proper logic. Thanks, ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] libavformat/hls: Observe Set-Cookie headers
Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/hls.c | 12 ++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index bac53a4350..42022690f1 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -630,8 +630,16 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, ret = s->io_open(s, pb, url, AVIO_FLAG_READ, ); if (ret >= 0) { // update cookies on http response with setcookies. -void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; -update_options(>cookies, "cookies", u); +char *new_cookies = NULL; + +if (!(s->flags & AVFMT_FLAG_CUSTOM_IO)) +av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, (uint8_t**)_cookies); + +if (new_cookies) { +av_free(c->cookies); +c->cookies = new_cookies; +} + av_dict_set(, "cookies", c->cookies, 0); } -- 2.11.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] libavformat/hls: Observe Set-Cookie headers
On 2017-05-06 02:28 PM, Micah Galizia wrote: On 2017-05-05 09:28 PM, wm4 wrote: On Fri, 5 May 2017 20:55:05 -0400 Micah Galizia <micahgali...@gmail.com> wrote: Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/hls.c | 12 ++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index bac53a4350..bda9abecfa 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -630,8 +630,16 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, ret = s->io_open(s, pb, url, AVIO_FLAG_READ, ); if (ret >= 0) { // update cookies on http response with setcookies. -void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; -update_options(>cookies, "cookies", u); +char *new_cookies = NULL; + +if (s->flags ^ AVFMT_FLAG_CUSTOM_IO) +av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, (uint8_t**)_cookies); Did you mean & instead of ^? No, the original code was structured to set *u to null (and thus did not copy cookies) iff AVFMT_FLAG_CUSTOM_IO was set in the flags. So using ^ is logically equivalent -- cookies are copied only if AVFMT_FLAG_CUSTOM_IO is not set. Did you find out yet what difference AVFMT_FLAG_CUSTOM_IO is supposed to make in the existing code? Yes, I wrote back about it a day or two ago... here is the reference to its original inclusion: https://lists.ffmpeg.org/pipermail/ffmpeg-trac/2013-February/013020.html. When the code was originally implemented we were using s->pb->opaque, which in FFMPEG we could assume was a URLContext with options (one of them possibly being "cookies"). Based on the email above, that wasn't true for other apps like mplayer, and could cause crashes trying to treat opaque as a URLContext. So that is the purpose of checking the AVFMT_FLAG_CUSTOM_IO flag (way back in 2013). Now though, we don't seem to touch opaque at all. The options are stored in AVIOContext's av_class, which does have options. Based on this I think both patches are safe: this version has less change, but the original gets rid of the check against AVFMT_FLAG_CUSTOM_IO that I don't think we need anymore. I hope that clears things up. Hi, is there anything further needed to get this fix committed? Thanks, ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] libavformat/hls: Observe Set-Cookie headers
On 2017-05-05 09:28 PM, wm4 wrote: On Fri, 5 May 2017 20:55:05 -0400 Micah Galizia <micahgali...@gmail.com> wrote: Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/hls.c | 12 ++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index bac53a4350..bda9abecfa 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -630,8 +630,16 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, ret = s->io_open(s, pb, url, AVIO_FLAG_READ, ); if (ret >= 0) { // update cookies on http response with setcookies. -void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; -update_options(>cookies, "cookies", u); +char *new_cookies = NULL; + +if (s->flags ^ AVFMT_FLAG_CUSTOM_IO) +av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, (uint8_t**)_cookies); Did you mean & instead of ^? No, the original code was structured to set *u to null (and thus did not copy cookies) iff AVFMT_FLAG_CUSTOM_IO was set in the flags. So using ^ is logically equivalent -- cookies are copied only if AVFMT_FLAG_CUSTOM_IO is not set. Did you find out yet what difference AVFMT_FLAG_CUSTOM_IO is supposed to make in the existing code? Yes, I wrote back about it a day or two ago... here is the reference to its original inclusion: https://lists.ffmpeg.org/pipermail/ffmpeg-trac/2013-February/013020.html. When the code was originally implemented we were using s->pb->opaque, which in FFMPEG we could assume was a URLContext with options (one of them possibly being "cookies"). Based on the email above, that wasn't true for other apps like mplayer, and could cause crashes trying to treat opaque as a URLContext. So that is the purpose of checking the AVFMT_FLAG_CUSTOM_IO flag (way back in 2013). Now though, we don't seem to touch opaque at all. The options are stored in AVIOContext's av_class, which does have options. Based on this I think both patches are safe: this version has less change, but the original gets rid of the check against AVFMT_FLAG_CUSTOM_IO that I don't think we need anymore. I hope that clears things up. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] libavformat/hls: Observe Set-Cookie headers
Hi, This is a simpler version of the other patch that still observes AVFMT_FLAG_CUSTOM_IO. Thanks in advance. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] libavformat/hls: Observe Set-Cookie headers
Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/hls.c | 12 ++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index bac53a4350..bda9abecfa 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -630,8 +630,16 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, ret = s->io_open(s, pb, url, AVIO_FLAG_READ, ); if (ret >= 0) { // update cookies on http response with setcookies. -void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; -update_options(>cookies, "cookies", u); +char *new_cookies = NULL; + +if (s->flags ^ AVFMT_FLAG_CUSTOM_IO) +av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, (uint8_t**)_cookies); + +if (new_cookies) { +av_free(c->cookies); +c->cookies = new_cookies; +} + av_dict_set(, "cookies", c->cookies, 0); } -- 2.11.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] libavformat/hls: Observe Set-Cookie headers
On 2017-05-02 09:04 PM, wm4 wrote: On Tue, 2 May 2017 20:47:06 -0400 Micah Galizia <micahgali...@gmail.com> wrote: Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/hls.c | 12 +--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index bac53a4350..643d50e1da 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -630,8 +630,14 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, ret = s->io_open(s, pb, url, AVIO_FLAG_READ, ); if (ret >= 0) { // update cookies on http response with setcookies. -void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; -update_options(>cookies, "cookies", u); +char *new_cookies = NULL; + +av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, (uint8_t**)_cookies); +if (new_cookies) { +av_free(c->cookies); +c->cookies = new_cookies; +} + av_dict_set(, "cookies", c->cookies, 0); } @@ -1608,7 +1614,7 @@ static int hls_close(AVFormatContext *s) static int hls_read_header(AVFormatContext *s) { -void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; +void *u = s->pb; HLSContext *c = s->priv_data; int ret = 0, i; int highest_cur_seq_no = 0; Not comfortable with this without knowing what the purpose of this CUSTOM_IO check was. Sorry, I misunderstood a prior email. Regarding why we check the custom IO flags, I was able to track down the following: https://lists.ffmpeg.org/pipermail/ffmpeg-trac/2013-February/013020.html for the hls_read_header. It was originally added in commit db6e2e848b21d988fb108995387a8c7836da4dc7 back in 2013. After reading that, I think the problem it was trying to solve was about treating pb->opaque as a urlcontext -- but the code no longer does that, unless I've misunderstood all the casting in av_opt_get. What I believe it does now is call av_opt_get(*pb...), which eventually winds up in av_opt_find2 where it pulls options out the AVClass (av_class) contained in AVIOContext and starts reading its options. It doesn't seem to be touching opaque field in AVIOContext anymore. Given this, I _think_ what I did is still ok. However, I can also change the patch to leave hls_read_header alone and add an if (s->flags ^ AVFMT_FLAG_CUSTOM_IO) before getting the new_cookies. This, effectively, fixes the bug without disregarding the check against AVFMT_FLAG_CUSTOM_IO -- best of both worlds and a smaller patch. If nobody can confirm my analysis that opaque is now being left alone (thus, no longer requiring the check against the custom IO flag) then I'll just put the smaller patch up. Thanks, ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] libavformat/hls: Observe Set-Cookie headers
Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/hls.c | 12 +--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index bac53a4350..643d50e1da 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -630,8 +630,14 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, ret = s->io_open(s, pb, url, AVIO_FLAG_READ, ); if (ret >= 0) { // update cookies on http response with setcookies. -void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; -update_options(>cookies, "cookies", u); +char *new_cookies = NULL; + +av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, (uint8_t**)_cookies); +if (new_cookies) { +av_free(c->cookies); +c->cookies = new_cookies; +} + av_dict_set(, "cookies", c->cookies, 0); } @@ -1608,7 +1614,7 @@ static int hls_close(AVFormatContext *s) static int hls_read_header(AVFormatContext *s) { -void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; +void *u = s->pb; HLSContext *c = s->priv_data; int ret = 0, i; int highest_cur_seq_no = 0; -- 2.11.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] Observe Set-Cookie headers in HLS streams
Hi, I was hoping to get this one in too so I've named the patch appropriately. With this change, cookie authenticated streams (eg: Neulion) should play properly again. Thanks, ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH 2/2] Add http cookie tests cases to fate
Hello, Same patch with corrected name. Thanks in advance. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH 2/2] libavformat/tests: Add http cookie tests cases to fate
Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/Makefile | 1 + libavformat/tests/http.c | 186 + tests/fate/libavformat.mak | 5 ++ tests/ref/fate/http| 30 4 files changed, 222 insertions(+) create mode 100644 libavformat/tests/http.c create mode 100644 tests/ref/fate/http diff --git a/libavformat/Makefile b/libavformat/Makefile index 6bdfbe6789..640a348c2f 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -598,6 +598,7 @@ SKIPHEADERS-$(CONFIG_NETWORK)+= network.h rtsp.h TESTPROGS = seek\ url \ +http\ # async \ FIFO-MUXER-TESTPROGS-$(CONFIG_NETWORK) += fifo_muxer diff --git a/libavformat/tests/http.c b/libavformat/tests/http.c new file mode 100644 index 00..76a70ae814 --- /dev/null +++ b/libavformat/tests/http.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2017 Micah Galizia + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavformat/http.c" +#include "libavformat/avio.h" + +typedef struct GetCookiesTestCase { +const char *set_cookie; +const char *cookie_str; +const char *path; +const char *domain; +} GetCookiesTestCase; + +// Don't go past Tue, 19 Jan 2038 03:14:07 GMT or 32-bit time_t overflows +GetCookiesTestCase get_cookies_tests[] = { +/* Test good and expired cookie. Should be acceptable */ +{"first=\"good\"; Domain=.test.com; Path=/\nsecond=great; domain=.test.com; path=/; HttpOnly", + "first=\"good\"; second=great", "/hello", "cookie.test.com"}, + + /* Test good and expired cookie. Should be acceptable */ +{"expired=\"really_old\"; Domain=.test.com; Expires=Thu, 01 Jan 1970 00:00:10 GMT; Path=/\ngood=not_expired; domain=.test.com; path=/; expires=Tue, 19 Jan 2038 03:14:07 GMT; HttpOnly", + "good=not_expired", "/hello", "cookie.test.com"}, + +/* Test a good and expired cookie in the neulion format. + * Should be acceptable */ +{"expired=\"really_old\"; Domain=.test.com; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/\nneulion=not_expired; domain=.test.com; path=/; expires=Tue, 19-Jan-2038 03:14:07 GMT; HttpOnly", + "neulion=not_expired", "/hello", "cookie.test.com"}, + +/* Test an expiry date without the day of week specified */ +{"no_day=still_ok; domain=.test.com; path=/; expires=19 Jan 2038 03:14:07 GMT; HttpOnly", + "no_day=still_ok", "/hello", "cookie.test.com"}, + +/* Test a date that cannot be parsed. Allow the cookie */ +{"unparsable_date=allow_cookie; domain=.test.com; path=/; expires=19 Jon 2038 03:14:07 GMT; HttpOnly", + "unparsable_date=allow_cookie", "/hello", "cookie.test.com"}, + +/* Test a cookie that has a different domain. Do not use the cookie */ +{"different_domain=exclude; domain=.nottest.com; path=/; expires=19 Jan 2038 03:14:07 GMT; HttpOnly", + NULL, "/hello", "cookie.test.com"}, + +/* Test a set-cookie that has no spaces */ + {"no_spaces=no_big_deal;domain=.test.com;path=/;expires=Tue,19Jan203803:14:07GMT;HttpOnly", + "no_spaces=no_big_deal", "/hello", "cookie.test.com"}, + +/* Test a set-cookie that has no spaces and is expired. Excluded */ + {"no_spaces_expired=not_ok;domain=.test.com;path=/;expires=Thu01Jan197010GMT;HttpOnly", + NULL, "/hello", "cookie.test.com"}, + +/* Test a set-cookie with a date that is too long. */ +{"long=handled;domain=.test.com;path=/;expires=Tue, 19 Jan 2038 03:14:07GMTGMTGMTGMTGMTGMT;HttpOnly", + "long=handled", "/hello", "cookie.test.com"}, + +/* Test a set-cookie wit
Re: [FFmpeg-devel] [PATCH] libavformat/http: Ignore expired cookies
On 2017-05-01 12:09 PM, Michael Niedermayer wrote: On Sun, Apr 30, 2017 at 02:25:29PM -0400, Micah Galizia wrote: Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/http.c | 213 +++-- 1 file changed, 156 insertions(+), 57 deletions(-) applied thx TYVM. If I fix the name of on the second patch (for the unit tests) can I get that in too? I figure it can only help prevent future breaks. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] libavformat/http: Ignore expired cookies
Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/http.c | 213 +++-- 1 file changed, 156 insertions(+), 57 deletions(-) diff --git a/libavformat/http.c b/libavformat/http.c index 293a8a7204..d06103ab6d 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -29,6 +29,7 @@ #include "libavutil/avstring.h" #include "libavutil/opt.h" #include "libavutil/time.h" +#include "libavutil/parseutils.h" #include "avformat.h" #include "http.h" @@ -48,6 +49,8 @@ #define MAX_REDIRECTS 8 #define HTTP_SINGLE 1 #define HTTP_MUTLI2 +#define MAX_EXPIRY19 +#define WHITESPACES " \n\t\r" typedef enum { LOWER_PROTO, READ_HEADERS, @@ -680,10 +683,112 @@ static int parse_icy(HTTPContext *s, const char *tag, const char *p) return 0; } +static int parse_set_cookie_expiry_time(const char *exp_str, struct tm *buf) +{ +char exp_buf[MAX_EXPIRY]; +int i, j, exp_buf_len = MAX_EXPIRY-1; +char *expiry; + +// strip off any punctuation or whitespace +for (i = 0, j = 0; exp_str[i] != '\0' && j < exp_buf_len; i++) { +if ((exp_str[i] >= '0' && exp_str[i] <= '9') || +(exp_str[i] >= 'A' && exp_str[i] <= 'Z') || +(exp_str[i] >= 'a' && exp_str[i] <= 'z')) { +exp_buf[j] = exp_str[i]; +j++; +} +} +exp_buf[j] = '\0'; +expiry = exp_buf; + +// move the string beyond the day of week +while ((*expiry < '0' || *expiry > '9') && *expiry != '\0') +expiry++; + +return av_small_strptime(expiry, "%d%b%Y%H%M%S", buf) ? 0 : AVERROR(EINVAL); +} + +static int parse_set_cookie(const char *set_cookie, AVDictionary **dict) +{ +char *param, *next_param, *cstr, *back; + +if (!(cstr = av_strdup(set_cookie))) +return AVERROR(EINVAL); + +// strip any trailing whitespace +back = [strlen(cstr)-1]; +while (strchr(WHITESPACES, *back)) { +*back='\0'; +back--; +} + +next_param = cstr; +while ((param = av_strtok(next_param, ";", _param))) { +char *name, *value; +param += strspn(param, WHITESPACES); +if ((name = av_strtok(param, "=", ))) { +if (av_dict_set(dict, name, value, 0) < 0) { +av_free(cstr); +return -1; +} +} +} + +av_free(cstr); +return 0; +} + static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies) { +AVDictionary *new_params = NULL; +AVDictionaryEntry *e, *cookie_entry; char *eql, *name; +// ensure the cookie is parsable +if (parse_set_cookie(p, _params)) +return -1; + +// if there is no cookie value there is nothing to parse +cookie_entry = av_dict_get(new_params, "", NULL, AV_DICT_IGNORE_SUFFIX); +if (!cookie_entry || !cookie_entry->value) { +av_dict_free(_params); +return -1; +} + +// ensure the cookie is not expired or older than an existing value +if ((e = av_dict_get(new_params, "expires", NULL, 0)) && e->value) { +struct tm new_tm = {0}; +if (!parse_set_cookie_expiry_time(e->value, _tm)) { +AVDictionaryEntry *e2; + +// if the cookie has already expired ignore it +if (av_timegm(_tm) < av_gettime() / 100) { +av_dict_free(_params); +return -1; +} + +// only replace an older cookie with the same name +e2 = av_dict_get(*cookies, cookie_entry->key, NULL, 0); +if (e2 && e2->value) { +AVDictionary *old_params = NULL; +if (!parse_set_cookie(p, _params)) { +e2 = av_dict_get(old_params, "expires", NULL, 0); +if (e2 && e2->value) { +struct tm old_tm = {0}; +if (!parse_set_cookie_expiry_time(e->value, _tm)) { +if (av_timegm(_tm) < av_timegm(_tm)) { +av_dict_free(_params); +av_dict_free(_params); +return -1; +} +} +} +} +av_dict_free(_params); +} +} +} + // 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); @@ -868,7 +973,7 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, // cookie strings will look like Set-Cookie header field values. Multiple // Set-Cookie fields will result in mul
Re: [FFmpeg-devel] [PATCH] Ignore expired cookies
Hi, This version fixes the cstr leak and explicitly frees tmp when allocating cookies fails. Freeing tmp also means we don't need to free *cookies when ret is less than zero. I've also formatted the name properly, so it'll show up as a new thread. Thanks in advance. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] Ignore expired cookies
Thanks for the review, new fix checks av_dict_set return. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] Ignore expired cookies
Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/http.c | 212 +++-- 1 file changed, 155 insertions(+), 57 deletions(-) diff --git a/libavformat/http.c b/libavformat/http.c index 293a8a7204..58fc3902ab 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -29,6 +29,7 @@ #include "libavutil/avstring.h" #include "libavutil/opt.h" #include "libavutil/time.h" +#include "libavutil/parseutils.h" #include "avformat.h" #include "http.h" @@ -48,6 +49,8 @@ #define MAX_REDIRECTS 8 #define HTTP_SINGLE 1 #define HTTP_MUTLI2 +#define MAX_EXPIRY19 +#define WHITESPACES " \n\t\r" typedef enum { LOWER_PROTO, READ_HEADERS, @@ -680,10 +683,110 @@ static int parse_icy(HTTPContext *s, const char *tag, const char *p) return 0; } +static int parse_set_cookie_expiry_time(const char *exp_str, struct tm *buf) +{ +char exp_buf[MAX_EXPIRY]; +int i, j, exp_buf_len = MAX_EXPIRY-1; +char *expiry; + +// strip off any punctuation or whitespace +for (i = 0, j = 0; exp_str[i] != '\0' && j < exp_buf_len; i++) { +if ((exp_str[i] >= '0' && exp_str[i] <= '9') || +(exp_str[i] >= 'A' && exp_str[i] <= 'Z') || +(exp_str[i] >= 'a' && exp_str[i] <= 'z')) { +exp_buf[j] = exp_str[i]; +j++; +} +} +exp_buf[j] = '\0'; +expiry = exp_buf; + +// move the string beyond the day of week +while ((*expiry < '0' || *expiry > '9') && *expiry != '\0') +expiry++; + +return av_small_strptime(expiry, "%d%b%Y%H%M%S", buf) ? 0 : AVERROR(EINVAL); +} + +static int parse_set_cookie(const char *set_cookie, AVDictionary **dict) +{ +char *param, *next_param, *cstr, *back; + +if (!(cstr = av_strdup(set_cookie))) +return AVERROR(EINVAL); + +// strip any trailing whitespace +back = [strlen(cstr)-1]; +while (strchr(WHITESPACES, *back)) { +*back='\0'; +back--; +} + +next_param = cstr; +while ((param = av_strtok(next_param, ";", _param))) { +char *name, *value; +param += strspn(param, WHITESPACES); +if ((name = av_strtok(param, "=", ))) { +if (av_dict_set(dict, name, value, 0) < 0) +return -1; +} +} + +av_free(cstr); +return 0; +} + static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies) { +AVDictionary *new_params = NULL; +AVDictionaryEntry *e, *cookie_entry; char *eql, *name; +// ensure the cookie is parsable +if (parse_set_cookie(p, _params)) +return -1; + +// if there is no cookie value there is nothing to parse +cookie_entry = av_dict_get(new_params, "", NULL, AV_DICT_IGNORE_SUFFIX); +if (!cookie_entry || !cookie_entry->value) { +av_dict_free(_params); +return -1; +} + +// ensure the cookie is not expired or older than an existing value +if ((e = av_dict_get(new_params, "expires", NULL, 0)) && e->value) { +struct tm new_tm = {0}; +if (!parse_set_cookie_expiry_time(e->value, _tm)) { +AVDictionaryEntry *e2; + +// if the cookie has already expired ignore it +if (av_timegm(_tm) < av_gettime() / 100) { +av_dict_free(_params); +return -1; +} + +// only replace an older cookie with the same name +e2 = av_dict_get(*cookies, cookie_entry->key, NULL, 0); +if (e2 && e2->value) { +AVDictionary *old_params = NULL; +if (!parse_set_cookie(p, _params)) { +e2 = av_dict_get(old_params, "expires", NULL, 0); +if (e2 && e2->value) { +struct tm old_tm = {0}; +if (!parse_set_cookie_expiry_time(e->value, _tm)) { +if (av_timegm(_tm) < av_timegm(_tm)) { +av_dict_free(_params); +av_dict_free(_params); +return -1; +} +} +} +} +av_dict_free(_params); +} +} +} + // 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); @@ -868,7 +971,7 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, // cookie strings will look like Set-Cookie header field values. Multiple // Set-Cookie fields will result in multiple values delimited by a newline int ret
Re: [FFmpeg-devel] [PATCH] Ignore expired cookies
On 2017-04-08 09:05 PM, Micah Galizia wrote: Is there something I can do to get this reviewed? Thanks in advance. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] Ignore expired cookies
On 2017-04-08 09:05 PM, Micah Galizia wrote: Signed-off-by: Micah Galizia <micahgali...@gmail.com> Hello, Has anyone had a chance to review this? I was hoping to get the rework (if needed) done this weekend. Thanks, ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] Observe Set-Cookie headers in HLS streams
Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/hls.c | 12 +--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index bac53a4350..643d50e1da 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -630,8 +630,14 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, ret = s->io_open(s, pb, url, AVIO_FLAG_READ, ); if (ret >= 0) { // update cookies on http response with setcookies. -void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; -update_options(>cookies, "cookies", u); +char *new_cookies = NULL; + +av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, (uint8_t**)_cookies); +if (new_cookies) { +av_free(c->cookies); +c->cookies = new_cookies; +} + av_dict_set(, "cookies", c->cookies, 0); } @@ -1608,7 +1614,7 @@ static int hls_close(AVFormatContext *s) static int hls_read_header(AVFormatContext *s) { -void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; +void *u = s->pb; HLSContext *c = s->priv_data; int ret = 0, i; int highest_cur_seq_no = 0; -- 2.11.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] Observe Set-Cookie headers in HLS streams
Hi, This one gets rid of the check against AVFMT_FLAG_CUSTOM_IO. Let me know if anything else needs changing. Thanks, ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH 1/2] Ignore expired cookies
The original patch (possibly the implementation it replaced) had a bug that would include whitespace (eg: newline) when evaluating Set-Cookie values (eg: the domain). This is corrected in the modified version of that patch. Thanks ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] Ignore expired cookies
Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/http.c | 211 ++--- 1 file changed, 154 insertions(+), 57 deletions(-) diff --git a/libavformat/http.c b/libavformat/http.c index 293a8a7204..425711aab5 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -29,6 +29,7 @@ #include "libavutil/avstring.h" #include "libavutil/opt.h" #include "libavutil/time.h" +#include "libavutil/parseutils.h" #include "avformat.h" #include "http.h" @@ -48,6 +49,8 @@ #define MAX_REDIRECTS 8 #define HTTP_SINGLE 1 #define HTTP_MUTLI2 +#define MAX_EXPIRY19 +#define WHITESPACES " \n\t\r" typedef enum { LOWER_PROTO, READ_HEADERS, @@ -680,10 +683,109 @@ static int parse_icy(HTTPContext *s, const char *tag, const char *p) return 0; } +static int parse_set_cookie_expiry_time(const char *exp_str, struct tm *buf) +{ +char exp_buf[MAX_EXPIRY]; +int i, j, exp_buf_len = MAX_EXPIRY-1; +char *expiry; + +// strip off any punctuation or whitespace +for (i = 0, j = 0; exp_str[i] != '\0' && j < exp_buf_len; i++) { +if ((exp_str[i] >= '0' && exp_str[i] <= '9') || +(exp_str[i] >= 'A' && exp_str[i] <= 'Z') || +(exp_str[i] >= 'a' && exp_str[i] <= 'z')) { +exp_buf[j] = exp_str[i]; +j++; +} +} +exp_buf[j] = '\0'; +expiry = exp_buf; + +// move the string beyond the day of week +while ((*expiry < '0' || *expiry > '9') && *expiry != '\0') +expiry++; + +return av_small_strptime(expiry, "%d%b%Y%H%M%S", buf) ? 0 : AVERROR(EINVAL); +} + +static int parse_set_cookie(const char *set_cookie, AVDictionary **dict) +{ +char *param, *next_param, *cstr, *back; + +if (!(cstr = av_strdup(set_cookie))) +return AVERROR(EINVAL); + +// strip any trailing whitespace +back = [strlen(cstr)-1]; +while (strchr(WHITESPACES, *back)) { +*back='\0'; +back--; +} + +next_param = cstr; +while ((param = av_strtok(next_param, ";", _param))) { +char *name, *value; +param += strspn(param, WHITESPACES); +if ((name = av_strtok(param, "=", ))) { +av_dict_set(dict, name, value, 0); +} +} + +av_free(cstr); +return 0; +} + static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies) { +AVDictionary *new_params = NULL; +AVDictionaryEntry *e, *cookie_entry; char *eql, *name; +// ensure the cookie is parsable +if (parse_set_cookie(p, _params)) +return -1; + +// if there is no cookie value there is nothing to parse +cookie_entry = av_dict_get(new_params, "", NULL, AV_DICT_IGNORE_SUFFIX); +if (!cookie_entry || !cookie_entry->value) { +av_dict_free(_params); +return -1; +} + +// ensure the cookie is not expired or older than an existing value +if ((e = av_dict_get(new_params, "expires", NULL, 0)) && e->value) { +struct tm new_tm = {0}; +if (!parse_set_cookie_expiry_time(e->value, _tm)) { +AVDictionaryEntry *e2; + +// if the cookie has already expired ignore it +if (av_timegm(_tm) < av_gettime() / 100) { +av_dict_free(_params); +return -1; +} + +// only replace an older cookie with the same name +e2 = av_dict_get(*cookies, cookie_entry->key, NULL, 0); +if (e2 && e2->value) { +AVDictionary *old_params = NULL; +if (!parse_set_cookie(p, _params)) { +e2 = av_dict_get(old_params, "expires", NULL, 0); +if (e2 && e2->value) { +struct tm old_tm = {0}; +if (!parse_set_cookie_expiry_time(e->value, _tm)) { +if (av_timegm(_tm) < av_timegm(_tm)) { +av_dict_free(_params); +av_dict_free(_params); +return -1; +} +} +} +} +av_dict_free(_params); +} +} +} + // 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); @@ -868,7 +970,7 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, // cookie strings will look like Set-Cookie header field values. Multiple // Set-Cookie fields will result in multiple values delimited by a newline int ret = 0; -char *next, *cookie, *set_coo
Re: [FFmpeg-devel] [PATCH] Observe Set-Cookie headers in HLS streams
On 2017-04-07 02:48 AM, wm4 wrote: On Thu, 6 Apr 2017 22:48:59 -0400 Micah Galizia<micahgali...@gmail.com> <mailto:micahgali...@gmail.com> wrote: Signed-off-by: Micah Galizia<micahgali...@gmail.com> <mailto:micahgali...@gmail.com> --- libavformat/hls.c | 10 -- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index bac53a4..ab81863 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -630,8 +630,14 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, ret = s->io_open(s, pb, url, AVIO_FLAG_READ, ); if (ret >= 0) { // update cookies on http response with setcookies. -void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; -update_options(>cookies, "cookies", u); +char *new_cookies = NULL; + +av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, (uint8_t**)_cookies); +if (new_cookies) { +av_free(c->cookies); +c->cookies = new_cookies; +} + av_dict_set(, "cookies", c->cookies, 0); } So far, all code is doing the same thing by calling update_options() on pb, or NULL if it's a custom IO context. What you seem to change is always using the pb (even if it's a custom context), duplicating the update_options() code (subtly changing some corner case behavior), and, this is probably the important one, you use *pb instead of s->pb. True. But, the cookies option of *pb comes back NULL _unless_ they are updated, so we should check first before replacing. I could also update update_options, but that is probably overkill. I haven't really chased down the reason why the cookies sometimes come back (if they get changed) and sometimes don't. I suspect the latter is the only change that matters, and you probably want: void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : *pb; Yes, but then IIRC the flag was always set and we would actually try to pull cookies from NULL, which you allude to below. Also, without the ternary assignment, u is just *pb, so why create another variable? Now I have no idea why it checks "s->flags & AVFMT_FLAG_CUSTOM_IO", or what it means, but it feels very wrong. A common case is probably that the main playlist is accessed through a custom AVIOContext, but further nested playlists or actual .ts data probably use libavformat's code. I'm thinking that all uses of AVFMT_FLAG_CUSTOM_IO anywhere are probably bugs. I'm happy to take it out the check for AVFMT_FLAG_CUSTOM_IO -- there are only two and on the streams I tested it had no effect. However, I was hoping someone could explain why its there. If someone wants to write back and explain I'd appreciate it, otherwise, I'll send a patch to get rid of it. Thanks, ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] Observe Set-Cookie headers in HLS streams
Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/hls.c | 10 -- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index bac53a4..ab81863 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -630,8 +630,14 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, ret = s->io_open(s, pb, url, AVIO_FLAG_READ, ); if (ret >= 0) { // update cookies on http response with setcookies. -void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; -update_options(>cookies, "cookies", u); +char *new_cookies = NULL; + +av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, (uint8_t**)_cookies); +if (new_cookies) { +av_free(c->cookies); +c->cookies = new_cookies; +} + av_dict_set(, "cookies", c->cookies, 0); } -- 2.9.3 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] Observe Set-Cookie headers in HLS streams
Hello, I noticed some Set-Cookie headers are being ignored by the HLS demuxer. Patch attached fixes it. Previously, the cookies wouldn't get updated from the right AVIOContext, or not at all if AVFMT_FLAG_CUSTOM_IO is set -- I'm not really sure why that was done so please let me know if I overlooked something. Thanks in advance. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH 2/2] Add http cookie tests cases to fate
Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/Makefile | 1 + libavformat/tests/http.c | 186 + tests/fate/libavformat.mak | 5 ++ tests/ref/fate/http| 30 4 files changed, 222 insertions(+) create mode 100644 libavformat/tests/http.c create mode 100644 tests/ref/fate/http diff --git a/libavformat/Makefile b/libavformat/Makefile index f56ef16..a4abd1b 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -597,6 +597,7 @@ SKIPHEADERS-$(CONFIG_NETWORK)+= network.h rtsp.h TESTPROGS = seek\ url \ +http\ # async \ FIFO-MUXER-TESTPROGS-$(CONFIG_NETWORK) += fifo_muxer diff --git a/libavformat/tests/http.c b/libavformat/tests/http.c new file mode 100644 index 000..76a70ae --- /dev/null +++ b/libavformat/tests/http.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2017 Micah Galizia + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavformat/http.c" +#include "libavformat/avio.h" + +typedef struct GetCookiesTestCase { +const char *set_cookie; +const char *cookie_str; +const char *path; +const char *domain; +} GetCookiesTestCase; + +// Don't go past Tue, 19 Jan 2038 03:14:07 GMT or 32-bit time_t overflows +GetCookiesTestCase get_cookies_tests[] = { +/* Test good and expired cookie. Should be acceptable */ +{"first=\"good\"; Domain=.test.com; Path=/\nsecond=great; domain=.test.com; path=/; HttpOnly", + "first=\"good\"; second=great", "/hello", "cookie.test.com"}, + + /* Test good and expired cookie. Should be acceptable */ +{"expired=\"really_old\"; Domain=.test.com; Expires=Thu, 01 Jan 1970 00:00:10 GMT; Path=/\ngood=not_expired; domain=.test.com; path=/; expires=Tue, 19 Jan 2038 03:14:07 GMT; HttpOnly", + "good=not_expired", "/hello", "cookie.test.com"}, + +/* Test a good and expired cookie in the neulion format. + * Should be acceptable */ +{"expired=\"really_old\"; Domain=.test.com; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/\nneulion=not_expired; domain=.test.com; path=/; expires=Tue, 19-Jan-2038 03:14:07 GMT; HttpOnly", + "neulion=not_expired", "/hello", "cookie.test.com"}, + +/* Test an expiry date without the day of week specified */ +{"no_day=still_ok; domain=.test.com; path=/; expires=19 Jan 2038 03:14:07 GMT; HttpOnly", + "no_day=still_ok", "/hello", "cookie.test.com"}, + +/* Test a date that cannot be parsed. Allow the cookie */ +{"unparsable_date=allow_cookie; domain=.test.com; path=/; expires=19 Jon 2038 03:14:07 GMT; HttpOnly", + "unparsable_date=allow_cookie", "/hello", "cookie.test.com"}, + +/* Test a cookie that has a different domain. Do not use the cookie */ +{"different_domain=exclude; domain=.nottest.com; path=/; expires=19 Jan 2038 03:14:07 GMT; HttpOnly", + NULL, "/hello", "cookie.test.com"}, + +/* Test a set-cookie that has no spaces */ + {"no_spaces=no_big_deal;domain=.test.com;path=/;expires=Tue,19Jan203803:14:07GMT;HttpOnly", + "no_spaces=no_big_deal", "/hello", "cookie.test.com"}, + +/* Test a set-cookie that has no spaces and is expired. Excluded */ + {"no_spaces_expired=not_ok;domain=.test.com;path=/;expires=Thu01Jan197010GMT;HttpOnly", + NULL, "/hello", "cookie.test.com"}, + +/* Test a set-cookie with a date that is too long. */ +{"long=handled;domain=.test.com;path=/;expires=Tue, 19 Jan 2038 03:14:07GMTGMTGMTGMTGMTGMT;HttpOnly", + "long=handled", "/hello", "cookie.test.com"}, + +/* Test a set-cookie with a date that starts with t
[FFmpeg-devel] [PATCH 2/2] Add http cookie tests cases to fate
Hi, I didn't realize there was a year 2038 problem -- dates beyond it overflow a 32-bit time_t -- I've made the unit tests 32-bit compatible now. Thank you! ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH 2/2] Add http cookie tests cases to fate
Hi, No more passing null to strcmp -- hopefully this addresses the crash. Thanks in advance. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH 2/2] Add http cookie tests cases to fate
Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/Makefile | 1 + libavformat/tests/http.c | 185 + tests/fate/libavformat.mak | 5 ++ tests/ref/fate/http| 30 4 files changed, 221 insertions(+) create mode 100644 libavformat/tests/http.c create mode 100644 tests/ref/fate/http diff --git a/libavformat/Makefile b/libavformat/Makefile index f56ef16..a4abd1b 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -597,6 +597,7 @@ SKIPHEADERS-$(CONFIG_NETWORK)+= network.h rtsp.h TESTPROGS = seek\ url \ +http\ # async \ FIFO-MUXER-TESTPROGS-$(CONFIG_NETWORK) += fifo_muxer diff --git a/libavformat/tests/http.c b/libavformat/tests/http.c new file mode 100644 index 000..9652e71 --- /dev/null +++ b/libavformat/tests/http.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2017 Micah Galizia + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavformat/http.c" +#include "libavformat/avio.h" + +typedef struct GetCookiesTestCase { +const char *set_cookie; +const char *cookie_str; +const char *path; +const char *domain; +} GetCookiesTestCase; + +GetCookiesTestCase get_cookies_tests[] = { +/* Test good and expired cookie. Should be acceptable */ +{"first=\"good\"; Domain=.test.com; Path=/\nsecond=great; domain=.test.com; path=/; HttpOnly", + "first=\"good\"; second=great", "/hello", "cookie.test.com"}, + + /* Test good and expired cookie. Should be acceptable */ +{"expired=\"really_old\"; Domain=.test.com; Expires=Thu, 01 Jan 1970 00:00:10 GMT; Path=/\ngood=not_expired; domain=.test.com; path=/; expires=Fri, 12 Mar 2117 02:53:03 GMT; HttpOnly", + "good=not_expired", "/hello", "cookie.test.com"}, + +/* Test a good and expired cookie in the neulion format. + * Should be acceptable */ +{"expired=\"really_old\"; Domain=.test.com; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/\nneulion=not_expired; domain=.test.com; path=/; expires=Fri, 12-Mar-2117 02:53:03 GMT; HttpOnly", + "neulion=not_expired", "/hello", "cookie.test.com"}, + +/* Test an expiry date without the day of week specified */ +{"no_day=still_ok; domain=.test.com; path=/; expires=12-Mar-2117 02:53:03 GMT; HttpOnly", + "no_day=still_ok", "/hello", "cookie.test.com"}, + +/* Test a date that cannot be parsed. Allow the cookie */ +{"unparsable_date=allow_cookie; domain=.test.com; path=/; expires=12-Mur-2117 02:53:03 GMT; HttpOnly", + "unparsable_date=allow_cookie", "/hello", "cookie.test.com"}, + +/* Test a cookie that has a different domain. Do not use the cookie */ +{"different_domain=exclude; domain=.nottest.com; path=/; expires=12-Mar-2117 02:53:03 GMT; HttpOnly", + NULL, "/hello", "cookie.test.com"}, + +/* Test a set-cookie that has no spaces */ + {"no_spaces=no_big_deal;domain=.test.com;path=/;expires=Fri,12Mar211702:53:03GMT;HttpOnly", + "no_spaces=no_big_deal", "/hello", "cookie.test.com"}, + +/* Test a set-cookie that has no spaces and is expired. Excluded */ + {"no_spaces_expired=not_ok;domain=.test.com;path=/;expires=Thu01Jan197010GMT;HttpOnly", + NULL, "/hello", "cookie.test.com"}, + +/* Test a set-cookie with a date that is too long. */ +{"long=handled;domain=.test.com;path=/;expires=Fri, 12 Mar 2117 02:53:03GMTGMTGMTGMTGMTGMT;HttpOnly", + "long=handled", "/hello", "cookie.test.com"}, + +/* Test a set-cookie with a date that starts with too many characters */ +{"bad_start=ok;domain=
Re: [FFmpeg-devel] [PATCH 2/2] Add http cookie tests cases to fate
On 2017-03-31 06:10 AM, Michael Niedermayer wrote: On Thu, Mar 30, 2017 at 09:33:48PM -0400, Micah Galizia wrote: Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/Makefile | 1 + libavformat/tests/http.c | 182 + tests/fate/libavformat.mak | 5 ++ tests/ref/fate/http| 30 4 files changed, 218 insertions(+) create mode 100644 libavformat/tests/http.c create mode 100644 tests/ref/fate/http the test segfaults 'good=not_expired; domain=.test.com; path=/; expires=Fri, 12 Mar 2117 02:53:03 GMT; HttpOnly'->'expires'|'Fri, 12 Mar 2117 02:53:03 GMT' 'good=great'->'good'|'great' 0) 'first="good"; Domain=.test.com; Path=/ second=great; domain=.test.com; path=/; HttpOnly'=>'first="good"; second=great' Unable to parse 'expired="really_old"; Domain=.test.com; Expires=Thu, 01 Jan 1970 00:00:10 GMT; Path=/' 1) 'expired="really_old"; Domain=.test.com; Expires=Thu, 01 Jan 1970 00:00:10 GMT; Path=/ good=not_expired; domain=.test.com; path=/; expires=Fri, 12 Mar 2117 02:53:03 GMT; HttpOnly'=>'good=not_expired' Unable to parse 'expired="really_old"; Domain=.test.com; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/' 2) 'expired="really_old"; Domain=.test.com; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/ neulion=not_expired; domain=.test.com; path=/; expires=Fri, 12-Mar-2117 02:53:03 GMT; HttpOnly'=>'neulion=not_expired' 3) 'no_day=still_ok; domain=.test.com; path=/; expires=12-Mar-2117 02:53:03 GMT; HttpOnly'=>'no_day=still_ok' 4) 'unparsable_date=allow_cookie; domain=.test.com; path=/; expires=12-Mur-2117 02:53:03 GMT; HttpOnly'=>'unparsable_date=allow_cookie' 5) 'different_domain=exclude; domain=.nottest.com; path=/; expires=12-Mar-2117 02:53:03 GMT; HttpOnly'=>'(null)' Program received signal SIGSEGV, Segmentation fault. 0x75851166 in ?? () from /lib/x86_64-linux-gnu/libc.so.6 (gdb) bt #0 0x75851166 in ?? () from /lib/x86_64-linux-gnu/libc.so.6 #1 0x0041197c in test_get_cookies () at libavformat/tests/http.c:97 #2 0x0041056b in main () at libavformat/tests/http.c:173 [...] Thanks, I'm trying to reproduce your results here without success -- I can't get it to crash on my system. I'm on the same architecture as you are (x86_64) too... based on the backtrace I'm guessing maybe strcmp doesn't like s2 being null, even though it works on my system -- I'll add an explicit case for when they're both null so we're not comparing two null strings and resubmit. Thanks for running it/sorry for the crash. I'll try to send a fix today some time. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH 1/2] Ignore expired cookies
Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/http.c | 204 ++--- 1 file changed, 147 insertions(+), 57 deletions(-) diff --git a/libavformat/http.c b/libavformat/http.c index 293a8a7..a9f1b3f 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -29,6 +29,7 @@ #include "libavutil/avstring.h" #include "libavutil/opt.h" #include "libavutil/time.h" +#include "libavutil/parseutils.h" #include "avformat.h" #include "http.h" @@ -48,6 +49,8 @@ #define MAX_REDIRECTS 8 #define HTTP_SINGLE 1 #define HTTP_MUTLI2 +#define MAX_EXPIRY19 +#define WHITESPACES " \n\t\r" typedef enum { LOWER_PROTO, READ_HEADERS, @@ -680,10 +683,102 @@ static int parse_icy(HTTPContext *s, const char *tag, const char *p) return 0; } +static int parse_set_cookie_expiry_time(const char *exp_str, struct tm *buf) +{ +char exp_buf[MAX_EXPIRY]; +int i, j, exp_buf_len = MAX_EXPIRY-1; +char *expiry; + +// strip off any punctuation or whitespace +for (i = 0, j = 0; exp_str[i] != '\0' && j < exp_buf_len; i++) { +if ((exp_str[i] >= '0' && exp_str[i] <= '9') || +(exp_str[i] >= 'A' && exp_str[i] <= 'Z') || +(exp_str[i] >= 'a' && exp_str[i] <= 'z')) { +exp_buf[j] = exp_str[i]; +j++; +} +} +exp_buf[j] = '\0'; +expiry = exp_buf; + +// move the string beyond the day of week +while ((*expiry < '0' || *expiry > '9') && *expiry != '\0') +expiry++; + +return av_small_strptime(expiry, "%d%b%Y%H%M%S", buf) ? 0 : AVERROR(EINVAL); +} + +static int parse_set_cookie(const char *set_cookie, AVDictionary **dict) +{ +char *param, *next_param, *cstr; + +if (!(cstr = av_strdup(set_cookie))) +return AVERROR(EINVAL); + +next_param = cstr; +while ((param = av_strtok(next_param, ";", _param))) { +char *name, *value; +param += strspn(param, WHITESPACES); +if ((name = av_strtok(param, "=", ))) { +av_dict_set(dict, name, value, 0); +} +} + +av_free(cstr); +return 0; +} + static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies) { +AVDictionary *new_params = NULL; +AVDictionaryEntry *e, *cookie_entry; char *eql, *name; +// ensure the cookie is parsable +if (parse_set_cookie(p, _params)) +return -1; + +// if there is no cookie value there is nothing to parse +cookie_entry = av_dict_get(new_params, "", NULL, AV_DICT_IGNORE_SUFFIX); +if (!cookie_entry || !cookie_entry->value) { +av_dict_free(_params); +return -1; +} + +// ensure the cookie is not expired or older than an existing value +if ((e = av_dict_get(new_params, "expires", NULL, 0)) && e->value) { +struct tm new_tm = {0}; +if (!parse_set_cookie_expiry_time(e->value, _tm)) { +AVDictionaryEntry *e2; + +// if the cookie has already expired ignore it +if (av_timegm(_tm) < av_gettime() / 100) { +av_dict_free(_params); +return -1; +} + +// only replace an older cookie with the same name +e2 = av_dict_get(*cookies, cookie_entry->key, NULL, 0); +if (e2 && e2->value) { +AVDictionary *old_params = NULL; +if (!parse_set_cookie(p, _params)) { +e2 = av_dict_get(old_params, "expires", NULL, 0); +if (e2 && e2->value) { +struct tm old_tm = {0}; +if (!parse_set_cookie_expiry_time(e->value, _tm)) { +if (av_timegm(_tm) < av_timegm(_tm)) { +av_dict_free(_params); +av_dict_free(_params); +return -1; +} +} +} +} +av_dict_free(_params); +} +} +} + // 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); @@ -868,7 +963,7 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, // cookie strings will look like Set-Cookie header field values. Multiple // Set-Cookie fields will result in multiple values delimited by a newline int ret = 0; -char *next, *cookie, *set_cookies = av_strdup(s->cookies), *cset_cookies = set_cookies; +char *cookie, *set_cookies = av_strdup(s->cookies), *next = set_cookies; if (!set_cookies) re
[FFmpeg-devel] [PATCH 2/2] Add http cookie tests cases to fate
Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/Makefile | 1 + libavformat/tests/http.c | 182 + tests/fate/libavformat.mak | 5 ++ tests/ref/fate/http| 30 4 files changed, 218 insertions(+) create mode 100644 libavformat/tests/http.c create mode 100644 tests/ref/fate/http diff --git a/libavformat/Makefile b/libavformat/Makefile index f56ef16..a4abd1b 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -597,6 +597,7 @@ SKIPHEADERS-$(CONFIG_NETWORK)+= network.h rtsp.h TESTPROGS = seek\ url \ +http\ # async \ FIFO-MUXER-TESTPROGS-$(CONFIG_NETWORK) += fifo_muxer diff --git a/libavformat/tests/http.c b/libavformat/tests/http.c new file mode 100644 index 000..702cc86 --- /dev/null +++ b/libavformat/tests/http.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2017 Micah Galizia + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavformat/http.c" +#include "libavformat/avio.h" + +typedef struct GetCookiesTestCase { +const char *set_cookie; +const char *cookie_str; +const char *path; +const char *domain; +} GetCookiesTestCase; + +GetCookiesTestCase get_cookies_tests[] = { +/* Test good and expired cookie. Should be acceptable */ +{"first=\"good\"; Domain=.test.com; Path=/\nsecond=great; domain=.test.com; path=/; HttpOnly", + "first=\"good\"; second=great", "/hello", "cookie.test.com"}, + + /* Test good and expired cookie. Should be acceptable */ +{"expired=\"really_old\"; Domain=.test.com; Expires=Thu, 01 Jan 1970 00:00:10 GMT; Path=/\ngood=not_expired; domain=.test.com; path=/; expires=Fri, 12 Mar 2117 02:53:03 GMT; HttpOnly", + "good=not_expired", "/hello", "cookie.test.com"}, + +/* Test a good and expired cookie in the neulion format. + * Should be acceptable */ +{"expired=\"really_old\"; Domain=.test.com; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/\nneulion=not_expired; domain=.test.com; path=/; expires=Fri, 12-Mar-2117 02:53:03 GMT; HttpOnly", + "neulion=not_expired", "/hello", "cookie.test.com"}, + +/* Test an expiry date without the day of week specified */ +{"no_day=still_ok; domain=.test.com; path=/; expires=12-Mar-2117 02:53:03 GMT; HttpOnly", + "no_day=still_ok", "/hello", "cookie.test.com"}, + +/* Test a date that cannot be parsed. Allow the cookie */ +{"unparsable_date=allow_cookie; domain=.test.com; path=/; expires=12-Mur-2117 02:53:03 GMT; HttpOnly", + "unparsable_date=allow_cookie", "/hello", "cookie.test.com"}, + +/* Test a cookie that has a different domain. Do not use the cookie */ +{"different_domain=exclude; domain=.nottest.com; path=/; expires=12-Mar-2117 02:53:03 GMT; HttpOnly", + NULL, "/hello", "cookie.test.com"}, + +/* Test a set-cookie that has no spaces */ + {"no_spaces=no_big_deal;domain=.test.com;path=/;expires=Fri,12Mar211702:53:03GMT;HttpOnly", + "no_spaces=no_big_deal", "/hello", "cookie.test.com"}, + +/* Test a set-cookie that has no spaces and is expired. Excluded */ + {"no_spaces_expired=not_ok;domain=.test.com;path=/;expires=Thu01Jan197010GMT;HttpOnly", + NULL, "/hello", "cookie.test.com"}, + +/* Test a set-cookie with a date that is too long. */ +{"long=handled;domain=.test.com;path=/;expires=Fri, 12 Mar 2117 02:53:03GMTGMTGMTGMTGMTGMT;HttpOnly", + "long=handled", "/hello", "cookie.test.com"}, + +/* Test a set-cookie with a date that starts with too many characters */ +{"bad_start=ok;domain=
[FFmpeg-devel] [PATCH v2 0/2] Ignore expired cookies
Hello Again, This is another attempt to get the http protocol not to send expired cookies _and_ prevent it from updating good cookie values with expired cookie values sent by misbehaving servers. Previously its been recommended that we break each set-cookie into a dict to parse it properly; this version takes that approach and does refactor some of the older set-cookie parsing code. This time, I've also added unit tests in a second patch for the http protocol code I'm changing. Thanks in advance for the review. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] Ignore expired cookies
Thanks for those comments -- I'll get rid of the strlen in the upcoming patch but, Nicolas, you lost me there. Anyway, this patch only does half the job -- I have a new one that is unfortunately larger, but has taken prior advice to break cookies into dicts. On Thu, Mar 30, 2017 at 4:12 PM, Nicolas Georgewrote: > Le decadi 10 germinal, an CCXXV, Alexander Strasser a écrit : >> If expiry is zero terminated and you are going through it one byte at a time, >> you could omit the strlen call and just check if expiry[i] is non zero. >> >> It's maybe the more common idiom too. > > On the other hand, code that does not need a 0-terminated string is more > generic. > > I am thinking of the ideas I posted a few months ago about reworking the > options system to avoid escaping hell. Parsers for various types must be > able to work in the middle of strings with foreign delimiters. Code that > is already capable of working in the middle of a string would be easier > to integrate. > > Of course, all this is in the far future. I will not insist on all new > code to be able to work like that, but I would like it nonetheless. And > if it is already written that way, let us keep it. > > All in all, 0-terminated strings were a terrible terrible idea. > > Regards, > > -- > Nicolas George > > ___ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel > -- "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 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] Ignore expired cookies
Hi, I'm going to have to submit a v2 for this patch (hopefully soon) -- this version only accomplishes half the job: not sending expired cookies. The change should also prevent storing them in the first place. Regardless, thanks for your help on this one. On Sat, Mar 25, 2017 at 7:27 PM, Micah Galizia <micahgali...@gmail.com> wrote: > Signed-off-by: Micah Galizia <micahgali...@gmail.com> > --- > libavformat/http.c | 43 +++ > 1 file changed, 39 insertions(+), 4 deletions(-) > > diff --git a/libavformat/http.c b/libavformat/http.c > index 293a8a7..53fae2a 100644 > --- a/libavformat/http.c > +++ b/libavformat/http.c > @@ -29,6 +29,7 @@ > #include "libavutil/avstring.h" > #include "libavutil/opt.h" > #include "libavutil/time.h" > +#include "libavutil/parseutils.h" > > #include "avformat.h" > #include "http.h" > @@ -48,6 +49,8 @@ > #define MAX_REDIRECTS 8 > #define HTTP_SINGLE 1 > #define HTTP_MUTLI2 > +#define MAX_EXPIRY19 > +#define WHITESPACES " \n\t\r" > typedef enum { > LOWER_PROTO, > READ_HEADERS, > @@ -877,15 +880,20 @@ static int get_cookies(HTTPContext *s, char **cookies, > const char *path, > > *cookies = NULL; > while ((cookie = av_strtok(set_cookies, "\n", ))) { > -int domain_offset = 0; > +int domain_offset = 0, expired = 0; > char *param, *next_param, *cdomain = NULL, *cpath = NULL, *cvalue = > NULL; > +char exp_buf[MAX_EXPIRY]; > set_cookies = NULL; > > // store the cookie in a dict in case it is updated in the response > if (parse_cookie(s, cookie, >cookie_dict)) > av_log(s, AV_LOG_WARNING, "Unable to parse '%s'\n", cookie); > > -while ((param = av_strtok(cookie, "; ", _param))) { > +while ((param = av_strtok(cookie, ";", _param))) { > + > +// move past any leading whitespace > +param += strspn(param, WHITESPACES); > + > if (cookie) { > // first key-value pair is the actual cookie value > cvalue = av_strdup(param); > @@ -899,6 +907,33 @@ static int get_cookies(HTTPContext *s, char **cookies, > const char *path, > int leading_dot = (param[7] == '.'); > av_free(cdomain); > cdomain = av_strdup([7+leading_dot]); > +} else if (!av_strncasecmp("expires=", param, 8)) { > +int i, j, exp_len, exp_buf_len = MAX_EXPIRY-1; > +struct tm tm_buf = {0}; > +char *expiry = [8]; > + > +// strip off any punctuation or whitespace > +exp_len = strlen(expiry); > +for (i = 0, j = 0; i < exp_len && j < exp_buf_len; i++) { > +if ((expiry[i] >= '0' && expiry[i] <= '9') || > +(expiry[i] >= 'A' && expiry[i] <= 'Z') || > +(expiry[i] >= 'a' && expiry[i] <= 'z')) { > +exp_buf[j] = expiry[i]; > +j++; > +} > +} > +exp_buf[j] = '\0'; > +expiry = exp_buf; > + > +// move the string beyond the day of week > +while ((*expiry < '0' || *expiry > '9') && *expiry != '\0') > +expiry++; > + > +if (av_small_strptime(expiry, "%d%b%Y%H%M%S", _buf)) { > +time_t now = av_gettime() / 100; > +if (av_timegm(_buf) < now) > +expired = 1; > +} > } else { > // ignore unknown attributes > } > @@ -907,9 +942,9 @@ static int get_cookies(HTTPContext *s, char **cookies, > const char *path, > cdomain = av_strdup(domain); > > // ensure all of the necessary values are valid > -if (!cdomain || !cpath || !cvalue) { > +if (expired || !cdomain || !cpath || !cvalue ) { > av_log(s, AV_LOG_WARNING, > - "Invalid cookie found, no value, path or domain > specified\n"); > + "Invalid cookie found, expired or no value, path or > domain specified\n"); > goto done_cookie; > } > > -- > 2.9.3 > -- "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 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] Ignore expired cookies
On Sat, Mar 25, 2017 at 10:51 AM, wm4wrote: > This can overflow sizeof(exp_buf). Sorry, new patch cleans that up. >> + >> +// move the string beyond the day of week >> +i = 0; >> +while ((exp_buf[i] < '0' || exp_buf[i] > '9') && (i < j)) >> +i++; >> + >> +if (av_small_strptime(_buf[i], "%d%b%Y%H%M%SGMT", >> _buf)) { >> +time_t now = av_gettime() / 100; > > I don't know if av_gettime() has the same time base... I had to double-check but I think it's correct as it is. The av_gettime() is based on the time since the epoch, which is already in GMT/UTC. The cookies timestamp is also expressed in GMT/UTC per the HTTP spec (and per av_timegm), so I believe these are comparable. If you were not talking about the timezones when you said "same base", I'm not entirely sure what you're getting at. I tested on my system and av_gettime()/100 returns the same value as time(NULL). Thanks again. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] Ignore expired cookies
Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/http.c | 43 +++ 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/libavformat/http.c b/libavformat/http.c index 293a8a7..53fae2a 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -29,6 +29,7 @@ #include "libavutil/avstring.h" #include "libavutil/opt.h" #include "libavutil/time.h" +#include "libavutil/parseutils.h" #include "avformat.h" #include "http.h" @@ -48,6 +49,8 @@ #define MAX_REDIRECTS 8 #define HTTP_SINGLE 1 #define HTTP_MUTLI2 +#define MAX_EXPIRY19 +#define WHITESPACES " \n\t\r" typedef enum { LOWER_PROTO, READ_HEADERS, @@ -877,15 +880,20 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, *cookies = NULL; while ((cookie = av_strtok(set_cookies, "\n", ))) { -int domain_offset = 0; +int domain_offset = 0, expired = 0; char *param, *next_param, *cdomain = NULL, *cpath = NULL, *cvalue = NULL; +char exp_buf[MAX_EXPIRY]; set_cookies = NULL; // store the cookie in a dict in case it is updated in the response if (parse_cookie(s, cookie, >cookie_dict)) av_log(s, AV_LOG_WARNING, "Unable to parse '%s'\n", cookie); -while ((param = av_strtok(cookie, "; ", _param))) { +while ((param = av_strtok(cookie, ";", _param))) { + +// move past any leading whitespace +param += strspn(param, WHITESPACES); + if (cookie) { // first key-value pair is the actual cookie value cvalue = av_strdup(param); @@ -899,6 +907,33 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, int leading_dot = (param[7] == '.'); av_free(cdomain); cdomain = av_strdup([7+leading_dot]); +} else if (!av_strncasecmp("expires=", param, 8)) { +int i, j, exp_len, exp_buf_len = MAX_EXPIRY-1; +struct tm tm_buf = {0}; +char *expiry = [8]; + +// strip off any punctuation or whitespace +exp_len = strlen(expiry); +for (i = 0, j = 0; i < exp_len && j < exp_buf_len; i++) { +if ((expiry[i] >= '0' && expiry[i] <= '9') || +(expiry[i] >= 'A' && expiry[i] <= 'Z') || +(expiry[i] >= 'a' && expiry[i] <= 'z')) { +exp_buf[j] = expiry[i]; +j++; +} +} +exp_buf[j] = '\0'; +expiry = exp_buf; + +// move the string beyond the day of week +while ((*expiry < '0' || *expiry > '9') && *expiry != '\0') +expiry++; + +if (av_small_strptime(expiry, "%d%b%Y%H%M%S", _buf)) { +time_t now = av_gettime() / 100; +if (av_timegm(_buf) < now) +expired = 1; +} } else { // ignore unknown attributes } @@ -907,9 +942,9 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, cdomain = av_strdup(domain); // ensure all of the necessary values are valid -if (!cdomain || !cpath || !cvalue) { +if (expired || !cdomain || !cpath || !cvalue ) { av_log(s, AV_LOG_WARNING, - "Invalid cookie found, no value, path or domain specified\n"); + "Invalid cookie found, expired or no value, path or domain specified\n"); goto done_cookie; } -- 2.9.3 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] Ignore expired cookies
Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/http.c | 43 +++ 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/libavformat/http.c b/libavformat/http.c index 293a8a7..f7d1925 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -29,6 +29,7 @@ #include "libavutil/avstring.h" #include "libavutil/opt.h" #include "libavutil/time.h" +#include "libavutil/parseutils.h" #include "avformat.h" #include "http.h" @@ -48,6 +49,8 @@ #define MAX_REDIRECTS 8 #define HTTP_SINGLE 1 #define HTTP_MUTLI2 +#define MAX_EXPIRY30 +#define WHITESPACES " \n\t\r" typedef enum { LOWER_PROTO, READ_HEADERS, @@ -877,15 +880,20 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, *cookies = NULL; while ((cookie = av_strtok(set_cookies, "\n", ))) { -int domain_offset = 0; +int domain_offset = 0, expired = 0; char *param, *next_param, *cdomain = NULL, *cpath = NULL, *cvalue = NULL; +char exp_buf[MAX_EXPIRY]; set_cookies = NULL; // store the cookie in a dict in case it is updated in the response if (parse_cookie(s, cookie, >cookie_dict)) av_log(s, AV_LOG_WARNING, "Unable to parse '%s'\n", cookie); -while ((param = av_strtok(cookie, "; ", _param))) { +while ((param = av_strtok(cookie, ";", _param))) { + +// move past any leading whitespace +param += strspn(param, WHITESPACES); + if (cookie) { // first key-value pair is the actual cookie value cvalue = av_strdup(param); @@ -899,6 +907,33 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, int leading_dot = (param[7] == '.'); av_free(cdomain); cdomain = av_strdup([7+leading_dot]); +} else if (!av_strncasecmp("expires=", param, 8)) { +int i, j, exp_len; +struct tm tm_buf = {0}; +char *expiry = [8]; + +// strip off any punctuation or whitespace +exp_len = strlen(expiry); +for (i = 0, j = 0; i < exp_len; i++) { +if ((expiry[i] >= '0' && expiry[i] <= '9') || +(expiry[i] >= 'A' && expiry[i] <= 'Z') || +(expiry[i] >= 'a' && expiry[i] <= 'z')) { +exp_buf[j] = expiry[i]; +j++; +} +} +exp_buf[j] = '\0'; + +// move the string beyond the day of week +i = 0; +while ((exp_buf[i] < '0' || exp_buf[i] > '9') && (i < j)) +i++; + +if (av_small_strptime(_buf[i], "%d%b%Y%H%M%SGMT", _buf)) { +time_t now = av_gettime() / 100; +if (av_timegm(_buf) < now) +expired = 1; +} } else { // ignore unknown attributes } @@ -907,9 +942,9 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, cdomain = av_strdup(domain); // ensure all of the necessary values are valid -if (!cdomain || !cpath || !cvalue) { +if (expired || !cdomain || !cpath || !cvalue ) { av_log(s, AV_LOG_WARNING, - "Invalid cookie found, no value, path or domain specified\n"); + "Invalid cookie found, expired or no value, path or domain specified\n"); goto done_cookie; } -- 2.9.3 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] Ignore expired cookies
On 2017-03-25 07:11 AM, wm4 wrote: >> -while ((param = av_strtok(cookie, "; ", _param))) { >> +while ((param = av_strtok(cookie, ";", _param))) { >> + >> +// move past any leading whitespace >> +param += strspn(param, WHITESPACES); >> + > Not quite sure why this change is even needed, but seems ok. Its just a little more flexible than expecting a single space and only a space between each delimited field of a cookie. >> if (cookie) { >> // first key-value pair is the actual cookie value >> cvalue = av_strdup(param); >> @@ -899,6 +905,33 @@ static int get_cookies(HTTPContext *s, char **cookies, >> const char *path, >> int leading_dot = (param[7] == '.'); >> av_free(cdomain); >> cdomain = av_strdup([7+leading_dot]); >> +} else if (!av_strncasecmp("expires=", param, 8)) { >> +int i = 0, j = 0; >> +struct tm tm_buf = {0}; >> +char *expiry = av_strdup([8]); > Unchecked memory allocation that could fail. Thanks, resolved using the on-stack buffer described below. >> + >> +// strip off any punctuation or whitespace >> +for (; i < strlen(expiry); i++) { > A bit ugly stylistically: the i=0 initialization should be in here, and > the strlen should be cached in a variable, instead of recomputing it on > every loop. Fixed. >> +if ((expiry[i] >= '0' && expiry[i] <= '9') || >> +(expiry[i] >= 'A' && expiry[i] <= 'Z') || >> +(expiry[i] >= 'a' && expiry[i] <= 'z')) { >> +expiry[j] = expiry[i]; >> +j++; >> +} >> +} >> +expiry[j] = '\0'; > (To be honest I don't understand why the string is even strduped - you > could just make it with a fixed-sized on-stack buffer. Just discard the > remainder of the string if the buffer is unexpectedly too small - time > strings probably have an upper size bound anyway.) Changed. >> + >> +// move the string beyond the day of week >> +i = 0; >> +while ((expiry[i] < '0' || expiry[i] > '9') && (i < j)) >> +i++; >> + >> +if (av_small_strptime([i], "%d%b%Y%H%M%SGMT", >> _buf)) { >> +if (av_timegm(_buf) < time(NULL)) >> +expired = 1; > A bit unsure about this time() call. Also nervous about having this in > library code. I borrowed some code from parseutils to resolve this. Thanks for the prompt review. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] Ignore expired cookies
Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/http.c | 41 + 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/libavformat/http.c b/libavformat/http.c index 293a8a7..37bdacf 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -29,6 +29,7 @@ #include "libavutil/avstring.h" #include "libavutil/opt.h" #include "libavutil/time.h" +#include "libavutil/parseutils.h" #include "avformat.h" #include "http.h" @@ -48,6 +49,7 @@ #define MAX_REDIRECTS 8 #define HTTP_SINGLE 1 #define HTTP_MUTLI2 +#define WHITESPACES " \n\t\r" typedef enum { LOWER_PROTO, READ_HEADERS, @@ -877,7 +879,7 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, *cookies = NULL; while ((cookie = av_strtok(set_cookies, "\n", ))) { -int domain_offset = 0; +int domain_offset = 0, expired = 0; char *param, *next_param, *cdomain = NULL, *cpath = NULL, *cvalue = NULL; set_cookies = NULL; @@ -885,7 +887,11 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, if (parse_cookie(s, cookie, >cookie_dict)) av_log(s, AV_LOG_WARNING, "Unable to parse '%s'\n", cookie); -while ((param = av_strtok(cookie, "; ", _param))) { +while ((param = av_strtok(cookie, ";", _param))) { + +// move past any leading whitespace +param += strspn(param, WHITESPACES); + if (cookie) { // first key-value pair is the actual cookie value cvalue = av_strdup(param); @@ -899,6 +905,33 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, int leading_dot = (param[7] == '.'); av_free(cdomain); cdomain = av_strdup([7+leading_dot]); +} else if (!av_strncasecmp("expires=", param, 8)) { +int i = 0, j = 0; +struct tm tm_buf = {0}; +char *expiry = av_strdup([8]); + +// strip off any punctuation or whitespace +for (; i < strlen(expiry); i++) { +if ((expiry[i] >= '0' && expiry[i] <= '9') || +(expiry[i] >= 'A' && expiry[i] <= 'Z') || +(expiry[i] >= 'a' && expiry[i] <= 'z')) { +expiry[j] = expiry[i]; +j++; +} +} +expiry[j] = '\0'; + +// move the string beyond the day of week +i = 0; +while ((expiry[i] < '0' || expiry[i] > '9') && (i < j)) +i++; + +if (av_small_strptime([i], "%d%b%Y%H%M%SGMT", _buf)) { +if (av_timegm(_buf) < time(NULL)) +expired = 1; +} + +av_free(expiry); } else { // ignore unknown attributes } @@ -907,9 +940,9 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, cdomain = av_strdup(domain); // ensure all of the necessary values are valid -if (!cdomain || !cpath || !cvalue) { +if (expired || !cdomain || !cpath || !cvalue ) { av_log(s, AV_LOG_WARNING, - "Invalid cookie found, no value, path or domain specified\n"); + "Invalid cookie found, expired or no value, path or domain specified\n"); goto done_cookie; } -- 2.9.3 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] Ignore expired cookies
Hi, This is my second attempt at fixing how we are handling expired cookies. As a reminder, on some authenticated Neulion streams, they send a cookie from the past, like so: Set-Cookie: nlqptid=""; Domain=.neulion.com; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/ These expired cookies are ignored by other systems (eg: android). Please let me know if you want changes. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] add locale month names to av_small_strptime
On Sun, Feb 26, 2017 at 11:12 AM, Michael Niedermayer <mich...@niedermayer.cc> wrote: > On Thu, Feb 23, 2017 at 09:34:28PM -0500, Micah Galizia wrote: >> Hello, >> >> Is someone able to take a look at this and accept or reject it -- its >> been a few days since I submitted. > > applied > > thx Awesome -- thank you. On to the next one :) -- "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 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] add locale month names to av_small_strptime
Hello, Is someone able to take a look at this and accept or reject it -- its been a few days since I submitted. Sorry to pester -- thanks in advance. On Mon, Feb 20, 2017 at 7:48 PM, Micah Galizia <micahgali...@gmail.com> wrote: > Signed-off-by: Micah Galizia <micahgali...@gmail.com> > --- > libavutil/parseutils.c | 28 > libavutil/tests/parseutils.c | 7 +++ > tests/ref/fate/parseutils| 7 +++ > 3 files changed, 42 insertions(+) > > diff --git a/libavutil/parseutils.c b/libavutil/parseutils.c > index 86d3dac..7ca07b3 100644 > --- a/libavutil/parseutils.c > +++ b/libavutil/parseutils.c > @@ -140,6 +140,11 @@ static const VideoRateAbbr video_rate_abbrs[]= { > { "ntsc-film", { 24000, 1001 } }, > }; > > +static const char *months[12] = { > +"january", "february", "march", "april", "may", "june", "july", "august", > +"september", "october", "november", "december" > +}; > + > int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str) > { > int i; > @@ -466,6 +471,21 @@ static int date_get_num(const char **pp, > return val; > } > > +static int date_get_month(const char **pp) { > +int i = 0; > +for (; i < 12; i++) { > +if (!av_strncasecmp(*pp, months[i], 3)) { > +const char *mo_full = months[i] + 3; > +int len = strlen(mo_full); > +*pp += 3; > +if (len > 0 && !av_strncasecmp(*pp, mo_full, len)) > +*pp += len; > +return i; > +} > +} > +return -1; > +} > + > char *av_small_strptime(const char *p, const char *fmt, struct tm *dt) > { > int c, val; > @@ -525,6 +545,14 @@ char *av_small_strptime(const char *p, const char *fmt, > struct tm *dt) > if (!p) > return NULL; > break; > +case 'b': > +case 'B': > +case 'h': > +val = date_get_month(); > +if (val == -1) > +return NULL; > +dt->tm_mon = val; > +break; > case '%': > if (*p++ != '%') > return NULL; > diff --git a/libavutil/tests/parseutils.c b/libavutil/tests/parseutils.c > index 682b390..180f624 100644 > --- a/libavutil/tests/parseutils.c > +++ b/libavutil/tests/parseutils.c > @@ -138,6 +138,13 @@ static void test_av_small_strptime(void) > { "%Y - %m - %d","2012-12-21" }, > { "%Y-%m-%d %H:%M:%S", "2012-12-21 20:12:21" }, > { " %Y - %m - %d %H : %M : %S", " 2012 - 12 - 21 20 : 12 : 21" > }, > +{ " %Y - %b - %d %H : %M : %S", " 2012 - nOV - 21 20 : 12 : > 21" }, > +{ " %Y - %B - %d %H : %M : %S", " 2012 - nOVemBeR - 21 20 : 12 > : 21" }, > +{ " %Y - %B%d %H : %M : %S", " 2012 - may21 20 : 12 : 21" }, > +{ " %Y - %B%d %H : %M : %S", " 2012 - mby21 20 : 12 : 21" }, > +{ " %Y - %B - %d %H : %M : %S", " 2012 - JunE - 21 20 : 12 : > 21" }, > +{ " %Y - %B - %d %H : %M : %S", " 2012 - Jane - 21 20 : 12 : > 21" }, > +{ " %Y - %B - %d %H : %M : %S", " 2012 - January - 21 20 : 12 > : 21" }, > }; > > av_log_set_level(AV_LOG_DEBUG); > diff --git a/tests/ref/fate/parseutils b/tests/ref/fate/parseutils > index 1aad5ec..568b6d2 100644 > --- a/tests/ref/fate/parseutils > +++ b/tests/ref/fate/parseutils > @@ -68,6 +68,13 @@ fmt:'%Y-%m-%d' spec:'2012-12-21' -> 2012-12-21 00:00:00 > fmt:'%Y - %m - %d' spec:'2012-12-21' -> 2012-12-21 00:00:00 > fmt:'%Y-%m-%d %H:%M:%S' spec:'2012-12-21 20:12:21' -> 2012-12-21 20:12:21 > fmt:' %Y - %m - %d %H : %M : %S' spec:' 2012 - 12 - 21 20 : 12 : 21' > -> 2012-12-21 20:12:21 > +fmt:' %Y - %b - %d %H : %M : %S' spec:' 2012 - nOV - 21 20 : 12 : 21' > -> 2012-11-21 20:12:21 > +fmt:' %Y - %B - %d %H : %M : %S' spec:' 2012 - nOVemBeR - 21 20 : 12 : > 21' -> 2012-11-21 20:12:21 > +fmt:' %Y - %B%d %H : %M : %S' spec:' 2012 - may21 20 : 12 : 21' -> > 2012-05-21 20:12:21 > +fmt:' %Y - %B%d %H : %M : %S' spec:' 2012 - mby21 20 : 12 : 21' -> error > +fmt:' %Y - %B - %d %H : %M : %S' spec:' 2012 - JunE - 21 20 : 12 : 21' > -> 2012-06-21 20:12:21 > +fmt:' %Y - %B - %d %H : %M : %S' spec:' 2012 - Jane - 21 20 : 12 : 21' > -> error > +fmt:' %Y - %B - %d %H : %M : %S' spec:' 2012 - January - 21 20 : 12 : > 21' -> 2012-01-21 20:12:21 > > Testing av_parse_time() > (now is 2012-03-17 09:14:13.2 +0100, local time is UTC+1) > -- > 2.9.3 > -- "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 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] add locale month names to av_small_strptime
Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavutil/parseutils.c | 28 libavutil/tests/parseutils.c | 7 +++ tests/ref/fate/parseutils| 7 +++ 3 files changed, 42 insertions(+) diff --git a/libavutil/parseutils.c b/libavutil/parseutils.c index 86d3dac..7ca07b3 100644 --- a/libavutil/parseutils.c +++ b/libavutil/parseutils.c @@ -140,6 +140,11 @@ static const VideoRateAbbr video_rate_abbrs[]= { { "ntsc-film", { 24000, 1001 } }, }; +static const char *months[12] = { +"january", "february", "march", "april", "may", "june", "july", "august", +"september", "october", "november", "december" +}; + int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str) { int i; @@ -466,6 +471,21 @@ static int date_get_num(const char **pp, return val; } +static int date_get_month(const char **pp) { +int i = 0; +for (; i < 12; i++) { +if (!av_strncasecmp(*pp, months[i], 3)) { +const char *mo_full = months[i] + 3; +int len = strlen(mo_full); +*pp += 3; +if (len > 0 && !av_strncasecmp(*pp, mo_full, len)) +*pp += len; +return i; +} +} +return -1; +} + char *av_small_strptime(const char *p, const char *fmt, struct tm *dt) { int c, val; @@ -525,6 +545,14 @@ char *av_small_strptime(const char *p, const char *fmt, struct tm *dt) if (!p) return NULL; break; +case 'b': +case 'B': +case 'h': +val = date_get_month(); +if (val == -1) +return NULL; +dt->tm_mon = val; +break; case '%': if (*p++ != '%') return NULL; diff --git a/libavutil/tests/parseutils.c b/libavutil/tests/parseutils.c index 682b390..180f624 100644 --- a/libavutil/tests/parseutils.c +++ b/libavutil/tests/parseutils.c @@ -138,6 +138,13 @@ static void test_av_small_strptime(void) { "%Y - %m - %d","2012-12-21" }, { "%Y-%m-%d %H:%M:%S", "2012-12-21 20:12:21" }, { " %Y - %m - %d %H : %M : %S", " 2012 - 12 - 21 20 : 12 : 21" }, +{ " %Y - %b - %d %H : %M : %S", " 2012 - nOV - 21 20 : 12 : 21" }, +{ " %Y - %B - %d %H : %M : %S", " 2012 - nOVemBeR - 21 20 : 12 : 21" }, +{ " %Y - %B%d %H : %M : %S", " 2012 - may21 20 : 12 : 21" }, +{ " %Y - %B%d %H : %M : %S", " 2012 - mby21 20 : 12 : 21" }, +{ " %Y - %B - %d %H : %M : %S", " 2012 - JunE - 21 20 : 12 : 21" }, +{ " %Y - %B - %d %H : %M : %S", " 2012 - Jane - 21 20 : 12 : 21" }, +{ " %Y - %B - %d %H : %M : %S", " 2012 - January - 21 20 : 12 : 21" }, }; av_log_set_level(AV_LOG_DEBUG); diff --git a/tests/ref/fate/parseutils b/tests/ref/fate/parseutils index 1aad5ec..568b6d2 100644 --- a/tests/ref/fate/parseutils +++ b/tests/ref/fate/parseutils @@ -68,6 +68,13 @@ fmt:'%Y-%m-%d' spec:'2012-12-21' -> 2012-12-21 00:00:00 fmt:'%Y - %m - %d' spec:'2012-12-21' -> 2012-12-21 00:00:00 fmt:'%Y-%m-%d %H:%M:%S' spec:'2012-12-21 20:12:21' -> 2012-12-21 20:12:21 fmt:' %Y - %m - %d %H : %M : %S' spec:' 2012 - 12 - 21 20 : 12 : 21' -> 2012-12-21 20:12:21 +fmt:' %Y - %b - %d %H : %M : %S' spec:' 2012 - nOV - 21 20 : 12 : 21' -> 2012-11-21 20:12:21 +fmt:' %Y - %B - %d %H : %M : %S' spec:' 2012 - nOVemBeR - 21 20 : 12 : 21' -> 2012-11-21 20:12:21 +fmt:' %Y - %B%d %H : %M : %S' spec:' 2012 - may21 20 : 12 : 21' -> 2012-05-21 20:12:21 +fmt:' %Y - %B%d %H : %M : %S' spec:' 2012 - mby21 20 : 12 : 21' -> error +fmt:' %Y - %B - %d %H : %M : %S' spec:' 2012 - JunE - 21 20 : 12 : 21' -> 2012-06-21 20:12:21 +fmt:' %Y - %B - %d %H : %M : %S' spec:' 2012 - Jane - 21 20 : 12 : 21' -> error +fmt:' %Y - %B - %d %H : %M : %S' spec:' 2012 - January - 21 20 : 12 : 21' -> 2012-01-21 20:12:21 Testing av_parse_time() (now is 2012-03-17 09:14:13.2 +0100, local time is UTC+1) -- 2.9.3 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] add locale month names to av_small_strptime
Sorry about that -- this actually makes sense now -- I thought it was a bit odd that the test program had no asserts or anything to validate the output... I've addressed the fate issues in this patch -- thanks again for the review. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] add locale month names to av_small_strptime
Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavutil/parseutils.c | 28 libavutil/tests/parseutils.c | 7 +++ 2 files changed, 35 insertions(+) diff --git a/libavutil/parseutils.c b/libavutil/parseutils.c index 86d3dac..7ca07b3 100644 --- a/libavutil/parseutils.c +++ b/libavutil/parseutils.c @@ -140,6 +140,11 @@ static const VideoRateAbbr video_rate_abbrs[]= { { "ntsc-film", { 24000, 1001 } }, }; +static const char *months[12] = { +"january", "february", "march", "april", "may", "june", "july", "august", +"september", "october", "november", "december" +}; + int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str) { int i; @@ -466,6 +471,21 @@ static int date_get_num(const char **pp, return val; } +static int date_get_month(const char **pp) { +int i = 0; +for (; i < 12; i++) { +if (!av_strncasecmp(*pp, months[i], 3)) { +const char *mo_full = months[i] + 3; +int len = strlen(mo_full); +*pp += 3; +if (len > 0 && !av_strncasecmp(*pp, mo_full, len)) +*pp += len; +return i; +} +} +return -1; +} + char *av_small_strptime(const char *p, const char *fmt, struct tm *dt) { int c, val; @@ -525,6 +545,14 @@ char *av_small_strptime(const char *p, const char *fmt, struct tm *dt) if (!p) return NULL; break; +case 'b': +case 'B': +case 'h': +val = date_get_month(); +if (val == -1) +return NULL; +dt->tm_mon = val; +break; case '%': if (*p++ != '%') return NULL; diff --git a/libavutil/tests/parseutils.c b/libavutil/tests/parseutils.c index 682b390..180f624 100644 --- a/libavutil/tests/parseutils.c +++ b/libavutil/tests/parseutils.c @@ -138,6 +138,13 @@ static void test_av_small_strptime(void) { "%Y - %m - %d","2012-12-21" }, { "%Y-%m-%d %H:%M:%S", "2012-12-21 20:12:21" }, { " %Y - %m - %d %H : %M : %S", " 2012 - 12 - 21 20 : 12 : 21" }, +{ " %Y - %b - %d %H : %M : %S", " 2012 - nOV - 21 20 : 12 : 21" }, +{ " %Y - %B - %d %H : %M : %S", " 2012 - nOVemBeR - 21 20 : 12 : 21" }, +{ " %Y - %B%d %H : %M : %S", " 2012 - may21 20 : 12 : 21" }, +{ " %Y - %B%d %H : %M : %S", " 2012 - mby21 20 : 12 : 21" }, +{ " %Y - %B - %d %H : %M : %S", " 2012 - JunE - 21 20 : 12 : 21" }, +{ " %Y - %B - %d %H : %M : %S", " 2012 - Jane - 21 20 : 12 : 21" }, +{ " %Y - %B - %d %H : %M : %S", " 2012 - January - 21 20 : 12 : 21" }, }; av_log_set_level(AV_LOG_DEBUG); -- 2.9.3 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] add locale month names to av_small_strptime
--- libavutil/parseutils.c | 31 +++ libavutil/tests/parseutils.c | 5 + 2 files changed, 36 insertions(+) diff --git a/libavutil/parseutils.c b/libavutil/parseutils.c index 86d3dac..a273216 100644 --- a/libavutil/parseutils.c +++ b/libavutil/parseutils.c @@ -140,6 +140,12 @@ static const VideoRateAbbr video_rate_abbrs[]= { { "ntsc-film", { 24000, 1001 } }, }; +static const char *mo_abr[] = { "jan", "feb", "mar", "apr", "may", "jun", + "jul", "aug", "sep", "oct", "nov", "dec" }; + +static const char *mo_full[] = { "uary", "ruary", "ch", "il", NULL, "e", "y", +"ust", "tember", "ober", "ember", "ember" }; + int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str) { int i; @@ -466,6 +472,23 @@ static int date_get_num(const char **pp, return val; } +static int date_get_month(const char **pp) { +for (int i = 0; i < 12; i++) { +if (!av_strncasecmp(*pp, mo_abr[i], 3)) { +*pp += 3; +if (mo_full[i] != NULL) { +int len = strlen(mo_full[i]); +if (!av_strncasecmp(*pp, mo_full[i], len)) { +*pp += len; +return i; +} +} +return i; +} +} +return -1; +} + char *av_small_strptime(const char *p, const char *fmt, struct tm *dt) { int c, val; @@ -525,6 +548,14 @@ char *av_small_strptime(const char *p, const char *fmt, struct tm *dt) if (!p) return NULL; break; +case 'b': +case 'B': +case 'h': +val = date_get_month(); +if (val == -1) +return NULL; +dt->tm_mon = val; +break; case '%': if (*p++ != '%') return NULL; diff --git a/libavutil/tests/parseutils.c b/libavutil/tests/parseutils.c index 682b390..e9b9599 100644 --- a/libavutil/tests/parseutils.c +++ b/libavutil/tests/parseutils.c @@ -138,6 +138,11 @@ static void test_av_small_strptime(void) { "%Y - %m - %d","2012-12-21" }, { "%Y-%m-%d %H:%M:%S", "2012-12-21 20:12:21" }, { " %Y - %m - %d %H : %M : %S", " 2012 - 12 - 21 20 : 12 : 21" }, +{ " %Y - %b - %d %H : %M : %S", " 2012 - nOV - 21 20 : 12 : 21" }, +{ " %Y - %B - %d %H : %M : %S", " 2012 - nOVemBeR - 21 20 : 12 : 21" }, +{ " %Y - %B - %d %H : %M : %S", " 2012 - may - 21 20 : 12 : 21" }, +{ " %Y - %B - %d %H : %M : %S", " 2012 - JunE - 21 20 : 12 : 21" }, +{ " %Y - %B - %d %H : %M : %S", " 2012 - January - 21 20 : 12 : 21" }, }; av_log_set_level(AV_LOG_DEBUG); ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] add locale month names to av_small_strptime
Hello, In preparation for evaluating cookie expiry values, av_small_strptime needs to handle the month names. This patch adds said names (full and abbreviated). Thanks in advance, Micah ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] Ignore expired cookies
On Sun, Feb 12, 2017 at 6:28 AM, Nicolas George <geo...@nsup.org> wrote: > Thanks for the patch. See remarks below. > > Le tridi 23 pluviôse, an CCXXV, Micah Galizia a écrit : >> On some authenticated Neulion streams, they send a cookie from the past, >> like so: >> >> Set-Cookie: nlqptid=""; Domain=.neulion.com; Expires=Thu, 01-Jan-1970 >> 00:00:10 GMT; Path=/ >> >> As a result, the good cookie value is overwritten and authentication breaks >> immediately. I realise disqualifying a cookie over the date might open a >> can of worms when it comes to date formatting used by different systems, > > In principle, I would be in favour of correctly heeding all elements of > the protocol, and only on top of that provide users the option of > ignoring certain elements. Parsing the expires field certainly enters > this frame. > >> but I added Neulions wrong format and the http standard format. > > In that case, maybe ignoring the whole cookie because the date is > invalid would be a better idea. Maybe a more permissive approach would be better. Iff we _can_ parse the date format _AND_ it's expired then and only then ignore that cookie. This would maintain compatibility with how it works now, but correct the specific bug I'm observing. > Did you test to see how real browsers handle it? Browsers, no, but the Android video player, yes. They ignore the new cookie value if it shows up with an expiry in the past (well, at least an expiry date in 1970) and use the value it had already. Here is a charles dump if you want to see: https://dl.dropboxusercontent.com/u/83154919/snnow_full2.chls >> Please let me know if this is acceptable. I've run it against fate and >> there were no problems. > > That is good practice. Unfortunately, FATE tests almost nothing about > network protocols. If you did not, you need to check with a few web > servers that currently work. I tested it against the neulion stream I have access to. I don't have a whole lot else but hopefully if I minimize the situations in which cookies are ignored it wont matter. I'll also try to find a few other stream sources. > Now reviewing details of the latest version of the patch: > >> diff --git a/libavformat/http.c b/libavformat/http.c >> index 944a6cf..24368aa 100644 >> --- a/libavformat/http.c >> +++ b/libavformat/http.c >> @@ -682,12 +682,46 @@ static int parse_icy(HTTPContext *s, const char *tag, >> const char *p) >> >> static int parse_cookie(HTTPContext *s, const char *p, AVDictionary >> **cookies) >> { >> -char *eql, *name; >> +char *eql, *name, *expiry; >> >> // 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); >> >> +// ensure the expiry is sane > >> +if ((expiry = strstr(eql, "Expires="))) { > > I believe this is not correct. First, AFAIK, all the structure elements > in HTTP are case insensitive. Second, the string "Expires=" could > legitimately be part of the cookie value itself. > > I suggest to parse the subfields of the set-cookie field correctly: it > is a sequence of "key=value" pairs (with the "=value" part optional, but > can be quoted) separated by semicolons and optional spaces. Furthermore, > it would be useful for other fields too, such as content-type. > > I realize it is a little bit more work, but I think it is reasonable. I think this was proposed last time I was adding cookies into the HLS demuxer (years ago) but the problem is that you can't really pass around complex data structures between demuxers (http, hls, etc). AVOption was also quite restrictive last time I looked into doing something more advanced like that. One of the things Michael N. suggested back then was using a proper cookie jar -- is there any reason I can't keep parsed cookies in an in-memory global static variable scoped in http.c? Then we wouldn't even need to pass the cookies as options around between demuxers anymore since they'd have a perminant home in http.c, which should be the only place they're used. >> +struct tm tm_buf = {0}; >> +char *end; >> + >> +// get the start & the end of the expiry ('11 Feb 2017 09:41:35 >> GMT') >> +// this skips past the day of the week by finding the space >> following it > >> +expiry += 8 * sizeof(char); > > sizeof(char) = 1 by definition, thus writing it is always unnecessary, > and rarely useful for readability. > >> +while (*expiry != ' ') expiry++; > > I suspect tabs and other
[FFmpeg-devel] [PATCH] Ignore expired cookies
--- libavformat/http.c | 36 +++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/libavformat/http.c b/libavformat/http.c index 944a6cf..24368aa 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -682,12 +682,46 @@ static int parse_icy(HTTPContext *s, const char *tag, const char *p) static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies) { -char *eql, *name; +char *eql, *name, *expiry; // 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); +// ensure the expiry is sane +if ((expiry = strstr(eql, "Expires="))) { +struct tm tm_buf = {0}; +char *end; + +// get the start & the end of the expiry ('11 Feb 2017 09:41:35 GMT') +// this skips past the day of the week by finding the space following it +expiry += 8 * sizeof(char); +while (*expiry != ' ') expiry++; +expiry++; +end = expiry+1; +while (*end != ';') end++; + +// ensure the time is parsable +end = strptime(expiry, "%d %b %Y %H:%M:%S %Z", _buf); + +// ensure neulion's different format is parsable +if (!end) end = strptime(expiry, "%d-%b-%Y %H:%M:%S %Z", _buf); + +// if the expire is specified but unparsable, this cookie is invalid +if (!end) { +av_log(s, AV_LOG_ERROR, "Unable to parse expiry for cookie '%s'\n", p); +av_free(name); +return AVERROR(EINVAL); +} + +// no cookies from the past (neulion) +if (mktime(_buf) < time(NULL)) { +av_log(s, AV_LOG_ERROR, "Ignoring cookie from the past '%s'\n", p); +av_free(name); +return AVERROR(EINVAL); +} +} + // add the cookie to the dictionary av_dict_set(cookies, name, eql, AV_DICT_DONT_STRDUP_KEY); -- 2.9.3 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] Ignore expired cookies
This one fixes the memory leak -- sorry for all the spam. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] Ignore expired cookies
Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/http.c | 34 +- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/libavformat/http.c b/libavformat/http.c index 944a6cf..e7b8ac3 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -682,12 +682,44 @@ static int parse_icy(HTTPContext *s, const char *tag, const char *p) static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies) { -char *eql, *name; +char *eql, *name, *expiry; // 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); +// ensure the expiry is sane +if ((expiry = strstr(eql, "Expires="))) { +struct tm tm_buf = {0}; +char *end; + +// get the start & the end of the expiry ('11 Feb 2017 09:41:35 GMT') +// this skips past the day of the week by finding the space following it +expiry += 8 * sizeof(char); +while (*expiry != ' ') expiry++; +expiry++; +end = expiry+1; +while (*end != ';') end++; + +// ensure the time is parsable +end = strptime(expiry, "%d %b %Y %H:%M:%S %Z", _buf); + +// ensure neulion's different format is parsable +if (!end) end = strptime(expiry, "%d-%b-%Y %H:%M:%S %Z", _buf); + +// if the expire is specified but unparsable, this cookie is invalid +if (!end) { +av_log(s, AV_LOG_ERROR, "Unable to parse expiry for cookie '%s'\n", p); +return AVERROR(EINVAL); +} + +// no cookies from the past (neulion) +if (mktime(_buf) < time(NULL)) { +av_log(s, AV_LOG_ERROR, "Ignoring cookie from the past '%s'\n", p); +return AVERROR(EINVAL); +} +} + // add the cookie to the dictionary av_dict_set(cookies, name, eql, AV_DICT_DONT_STRDUP_KEY); -- 2.9.3 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] Ignore expired cookies
Appologies, gmail screwed up the patch. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] Ignore expired cookies
Hello, On some authenticated Neulion streams, they send a cookie from the past, like so: Set-Cookie: nlqptid=""; Domain=.neulion.com; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/ As a result, the good cookie value is overwritten and authentication breaks immediately. I realise disqualifying a cookie over the date might open a can of worms when it comes to date formatting used by different systems, but I added Neulions wrong format and the http standard format. Please let me know if this is acceptable. I've run it against fate and there were no problems. -- "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 1fecda5a7a36b530208a9428b86eebda66b0 Mon Sep 17 00:00:00 2001 From: Micah Galizia <micahgali...@gmail.com> Date: Sat, 11 Feb 2017 21:18:41 -0500 Subject: [PATCH] Ignore expired cookies Signed-off-by: Micah Galizia <micahgali...@gmail.com> --- libavformat/http.c | 34 +- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/libavformat/http.c b/libavformat/http.c index 944a6cf..e7b8ac3 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -682,12 +682,44 @@ static int parse_icy(HTTPContext *s, const char *tag, const char *p) static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies) { -char *eql, *name; +char *eql, *name, *expiry; // 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); +// ensure the expiry is sane +if ((expiry = strstr(eql, "Expires="))) { +struct tm tm_buf = {0}; +char *end; + +// get the start & the end of the expiry ('11 Feb 2017 09:41:35 GMT') +// this skips past the day of the week by finding the space following it +expiry += 8 * sizeof(char); +while (*expiry != ' ') expiry++; +expiry++; +end = expiry+1; +while (*end != ';') end++; + +// ensure the time is parsable +end = strptime(expiry, "%d %b %Y %H:%M:%S %Z", _buf); + +// ensure neulion's different format is parsable +if (!end) end = strptime(expiry, "%d-%b-%Y %H:%M:%S %Z", _buf); + +// if the expire is specified but unparsable, this cookie is invalid +if (!end) { +av_log(s, AV_LOG_ERROR, "Unable to parse expiry for cookie '%s'\n", p); +return AVERROR(EINVAL); +} + +// no cookies from the past (neulion) +if (mktime(_buf) < time(NULL)) { +av_log(s, AV_LOG_ERROR, "Ignoring cookie from the past '%s'\n", p); +return AVERROR(EINVAL); +} +} + // add the cookie to the dictionary av_dict_set(cookies, name, eql, AV_DICT_DONT_STRDUP_KEY); -- 2.9.3 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] hls merge cleanup
I've been watching an encrypted stream for the past 20 minutes and everything seems to be working fine. On Thu, Jul 30, 2015 at 1:10 PM, Michael Niedermayer mich...@niedermayer.cc wrote: On Thu, Jul 30, 2015 at 12:39:53PM -0400, Micah Galizia wrote: Cookies and user agent stuff all look the same to me (I'll test with an encrypted stream this weekend). the Cookies user agent stuff is still the code as it was previously best to look at the diff of the new code git show 0c73a5a53cc97f4291bbe9e1e68226edf6161744 and what was actually changed git diff ba12ba859aabfa7153ba397d869db13acdaba340^ ba12ba859aabfa7153ba397d869db13acdaba340 and thanks alot for looking into this [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB The misfortune of the wise is better than the prosperity of the fool. -- Epicurus -- 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 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] hls merge cleanup
Cookies and user agent stuff all look the same to me (I'll test with an encrypted stream this weekend). Also, its cool that he added renditions. On Thu, Jul 30, 2015 at 12:14 PM, Michael Niedermayer mich...@niedermayer.cc wrote: Hi all luca has reimplemented some of the option handling in hls like cookies and user agent ive merged this in ba12ba859aabfa7153ba397d869db13acdaba340 and used the new wraper functions where they fitted easily ive left the code using the previous tested and working option system Someone should look at the code and either drop the new avio_opts or the previous option fields like cookies. Or simplify it by any other means that seem appropriate I can also revert the merge if people prefer? Thanks -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB What does censorship reveal? It reveals fear. -- Julian Assange -- 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 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] replace cookies with updated values instead of appending forever (backport to 2.6)
Hi, One more -- backport code to replace cookie values instead appending to the header forever. -- 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 629e9028f40cbf6f54c4b481a274aea5219d7c10 Mon Sep 17 00:00:00 2001 From: Micah Galizia micahgali...@gmail.com Date: Tue, 17 Mar 2015 20:22:59 +1100 Subject: [PATCH 3/3] avformat/http: replace cookies with updated values instead of appending forever Signed-off-by: Michael Niedermayer michae...@gmx.at (cherry picked from commit c59654d67d1afde3fac24021ef0fd9d18cf38455) Signed-off-by: Micah Galizia micahgali...@gmail.com --- libavformat/http.c | 65 +++--- 1 file changed, 52 insertions(+), 13 deletions(-) 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 == 20) 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
[FFmpeg-devel] [PATCH] Refactor repeated HLS option updates (Backport to 2.6)
Hi, Backport code to refactor HLS option updates. TIA -- 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 cd2beeadf124c495497e665e6b95265ca9fcb3a8 Mon Sep 17 00:00:00 2001 From: Micah Galizia micahgali...@gmail.com Date: Mon, 16 Mar 2015 20:26:29 +1100 Subject: [PATCH 2/3] avformat/hls: refactor repeated HLS option updates Signed-off-by: Michael Niedermayer michae...@gmx.at (cherry picked from commit fca085187940a169b7a43d096009f7dac315f9ac) Signed-off-by: Micah Galizia micahgali...@gmail.com --- libavformat/hls.c | 28 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index 5ed7a24..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,10 +952,7 @@ static int open_input(HLSContext *c, struct playlist *pls) av_log(NULL, AV_LOG_ERROR, Unable to read key file %s\n, seg-key); } -av_freep(c-cookies); -av_opt_get(uc-priv_data, cookies, 0, (uint8_t**)(c-cookies)); -if (c-cookies !strlen(c-cookies)) -av_freep(c-cookies); +update_options(c-cookies, cookies, uc-priv_data); av_dict_set(opts, cookies, c-cookies, 0); ffurl_close(uc); } else { @@ -1257,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) -- 2.1.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] Backport hls and cookie fixes to the 2.6 branch
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
[FFmpeg-devel] Patches For 2.6 Branch
Hi, I had some code accepted on the master branch and I was wondering if they'd be suitable for inclusion in the 2.6 branch. I'd like them in the next version of xmbc. The commits were: c59654d67d1afde3fac24021ef0fd9d18cf38455 fca085187940a169b7a43d096009f7dac315f9ac 7859618affe574c9de7f240d2ddc016f917c37bd Assuming they make sense (I'd view them as fixes, not features), do I just merge them into the 2.6 branch and resubmit? -- 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 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] replace cookies with updated values
Hi, The current Set-Cookie handling appends cookies to the string without checking to see if a cookie with the same name should have its value updated. This is my second attempt to fix this issue -- last time it was a bit of a string parsing nightmare. This time its a little less complex (using a dictionary). Before we start the the existing implementation sucks, change it discussion I've looked into passing them around in their dictionary form (an only using the string to initialize cookies from an external source) but so far as I can tell, AVDictonary cannot be retrieved using av_opt_get or av_opt_find right now. Anyway, I hope this is sufficient for inclusion. TIA -- 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 18b00063d177965facd805d6b89eb96af371de94 Mon Sep 17 00:00:00 2001 From: Micah Galizia micahgali...@gmail.com Date: Tue, 17 Mar 2015 20:22:59 +1100 Subject: [PATCH 3/3] replace cookies with updated values instead of appending forever --- libavformat/http.c | 65 +++--- 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/libavformat/http.c b/libavformat/http.c index 86380b2..da3c9be 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; @@ -466,6 +468,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) { @@ -537,19 +576,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)) { @@ -580,12 +608,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 @@ -693,6 +728,10 @@ static int http_read_header(URLContext *h
Re: [FFmpeg-devel] [PATCH] Refactor repeated HLS option updates
Excellent. Thank you! On Mon, Mar 16, 2015 at 11:02 PM, Michael Niedermayer michae...@gmx.at wrote: On Mon, Mar 16, 2015 at 08:34:24PM +1100, Micah Galizia wrote: Hi, Attached patch puts repeated code into a function. TIA -- 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 hls.c | 28 1 file changed, 12 insertions(+), 16 deletions(-) b169e5c1a49fe7d16e0e44e897fdebe1e62f7d41 0002-refactor-repeated-HLS-option-updates.patch From 38b40bb622693f6b6f579092537aa9b7da28f9e1 Mon Sep 17 00:00:00 2001 From: Micah Galizia micahgali...@gmail.com Date: Mon, 16 Mar 2015 20:26:29 +1100 Subject: [PATCH 2/2] refactor repeated HLS option updates applied thanks [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB Concerning the gods, I have no means of knowing whether they exist or not or of what sort they may be, because of the obscurity of the subject, and the brevity of human life -- Protagoras ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel -- 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 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] Refactor repeated HLS option updates
Hi, Attached patch puts repeated code into a function. TIA -- 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 38b40bb622693f6b6f579092537aa9b7da28f9e1 Mon Sep 17 00:00:00 2001 From: Micah Galizia micahgali...@gmail.com Date: Mon, 16 Mar 2015 20:26:29 +1100 Subject: [PATCH 2/2] refactor repeated HLS option updates --- libavformat/hls.c | 28 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index 5ed7a24..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,10 +952,7 @@ static int open_input(HLSContext *c, struct playlist *pls) av_log(NULL, AV_LOG_ERROR, Unable to read key file %s\n, seg-key); } -av_freep(c-cookies); -av_opt_get(uc-priv_data, cookies, 0, (uint8_t**)(c-cookies)); -if (c-cookies !strlen(c-cookies)) -av_freep(c-cookies); +update_options(c-cookies, cookies, uc-priv_data); av_dict_set(opts, cookies, c-cookies, 0); ffurl_close(uc); } else { @@ -1257,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) -- 2.1.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] store cookies returned in HLS key responses
Excellent, thank you -- patch to refactor that repeated free/opt_get/free code (it happens four times) will be submitted shortly... On Mon, Mar 16, 2015 at 12:00 PM, Michael Niedermayer michae...@gmx.at wrote: On Sun, Mar 15, 2015 at 10:00:38AM +1100, Micah Galizia wrote: Hello, Neulion has added Set-Cookie fields in the response headers of their HLS key files. Those cookie values must be echoed back in the next key request or authentication on the subsequent key will fail. This fix will exacerbate the existing bug where the cookie field of ffmpeg requests keeps getting larger (since cookies are append when they should be replaced). However, those streams will fail sooner without this fix. Also, I have a fix for that bug too, but I'll start with this. 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 hls.c |5 + 1 file changed, 5 insertions(+) 0105a89eff5edb6fbc2751a369447dd743496476 0001-store-cookies-returned-in-HLS-key-response.patch From 7f2db07b91407a970b99655da96c8c2532e2c1ad Mon Sep 17 00:00:00 2001 From: Micah Galizia micahgali...@gmail.com Date: Sun, 15 Mar 2015 09:31:59 +1100 Subject: [PATCH] store cookies returned in HLS key response applied thanks [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB I know you won't believe me, but the highest form of Human Excellence is to question oneself and others. -- Socrates ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel -- 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 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] store cookies returned in HLS key responses
Hello, Neulion has added Set-Cookie fields in the response headers of their HLS key files. Those cookie values must be echoed back in the next key request or authentication on the subsequent key will fail. This fix will exacerbate the existing bug where the cookie field of ffmpeg requests keeps getting larger (since cookies are append when they should be replaced). However, those streams will fail sooner without this fix. Also, I have a fix for that bug too, but I'll start with this. 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 7f2db07b91407a970b99655da96c8c2532e2c1ad Mon Sep 17 00:00:00 2001 From: Micah Galizia micahgali...@gmail.com Date: Sun, 15 Mar 2015 09:31:59 +1100 Subject: [PATCH] store cookies returned in HLS key response --- libavformat/hls.c | 5 + 1 file changed, 5 insertions(+) diff --git a/libavformat/hls.c b/libavformat/hls.c index 5e8e1b2..5ed7a24 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -944,6 +944,11 @@ static int open_input(HLSContext *c, struct playlist *pls) av_log(NULL, AV_LOG_ERROR, Unable to read key file %s\n, seg-key); } +av_freep(c-cookies); +av_opt_get(uc-priv_data, cookies, 0, (uint8_t**)(c-cookies)); +if (c-cookies !strlen(c-cookies)) +av_freep(c-cookies); +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, -- 2.1.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] Reorganizing Cookies (was Re: [PATCH] Replace old cookies with new cookies of the same name)
On 18/08/14 21:36, Nicolas George wrote: Le primidi 1er fructidor, an CCXXII, Micah Galizia a écrit : Yes no. I agree its not an ideal implementation (it actually was mine to begin with) to just use a string full of cookies. But we can't pass around complex structures through avopts, which is where we would really see the benefit. As you Mark pointed out, we need to maintain compatibility with the current format, so why why go through parsing the cookie list each time if 1 in 100 requests actually sends back an updated cookie, and even then you'd have to dump it back out to a string and parse it again to pass it between http requests all this considered, I'd say I'm definitely leaning to no unless there is something I've overlooked. First, a small nitpick: if you read the option to get the updated values of the cookies after the request, then you are abusing the API, as the option does not have AV_OPT_FLAG_EXPORT. But for the sake of discussion we can assume it should be there and always was. But that does not mean that the string must be the authoritative value used internally. A lot of your code is spent updating the middle of the string while keeping the prefix and suffix constant. That makes a lot of tricky code, with reallocations and possible integer overflows everywhere. I am convinced that parsing the string as a whole, manipulating an internal data structure and rebuilding the string as a whole would give much simpler code. The parsing is needed for the actual Set-Cookie header; line-splitting is relatively easy. As for the rebuilding of the string, we have utilities that can take care of the reallocations and integer overflow for you; I think especially of AVBPrint. Here is a snippet of code: av_bprint_init(bp, 0, AV_BPRINT_SIZE_UNLIMITED); for (i = 0; i http-nb_cookies; i++) { Cookie *c = http-cookie[i]; if (i) av_bprintf(bp, \n); av_bprintf(bp, %s=%s, c-name, c-value); if (c-domain) av_bprintf(bp, ; domain=%s, c-domain); if (c-path) av_bprintf(bp, ; path=%s, c-path); if (c-extra) av_bprintf(bp, ; %s, c-extra); } if (!av_bprint_is_complete(bp)) return AVERROR(ENOMEM); return av_bprint_finalize(bp, http-cookies); Another point: I believe that having a callback on some options values may also be quite useful. That could be done as AV_OPT_FLAG_CALLBACK with a function pointer in AVClass. In this particular case, the callback could parse the string on the fly and re-generate it only when necessary. You lost me on the callback bit. I'm not sure I get how it'd really help. What do people think about that? I'd like to reorganize the cookies. Where I come up short is how to store them once they're parsed. Ideally, whatever their structure, they should be tied into the AVOption array for http so hls can copy them back and forth. That doesn't really leave me with a lot of choice for data structures -- and I'd rather not create a new AV_OPT_TYPE. Using what is available now I could keep the existing cookies option (newline delimited string) to allow external apps to set the cookies initially. After they are passed in I could break them into a second dictionary option (with the export flag) keyed by cookie name so at least replacement is easier. I'd probably unset the original cookie string too once they're broken into a dict so that there is no ambiguity over where they are stored. Then, hls (or any other code) could pass around the dict option instead of the string. I'm open to suggestions if I've overlooked an obvious way to tie generic structs into the AVOptions though. Alternatively, if the dictionary method is enough of an improvement I'll put in patchs to get it done that way. -- Micah ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] Replace old cookies with new cookies of the same name
On Sun, Aug 17, 2014 at 9:29 PM, Nicolas George geo...@nsup.org wrote: Le decadi 30 thermidor, an CCXXII, Micah Galizia a écrit : When new cookie values (with the same name as an existing cookie) are returned in an HLS stream, the current implementation will append the new cookie to the list of cookies. This causes FFMPEG to send multiple cookie values for the same cookie and in some cases exceed the http header size in some cases. The patch attached resolves the issue. Thanks for the patch. Below are a few technical remarks. But before that, a general remark: char *cookies; /// holds newline (\n) delimited Set-Cookie header field values (without the Set-Cookie: field name) Well, this is just awful. This is obviously not your fault, this is existing code, but it is no way of building anything: it can do for a quick-and-dirty first implementation to get things working, but it makes a very bad ground to build upon. It seems to me that most of your patch is there to deal with that awful data structure. A large part of the existing code too, for that matter. IMHO, it would be much better to rework the current code to use a proper data structure. A dynarray of structures with name, value, path and domain already split seems like the best option. I suspect it would even be simpler to do that than making sure your patch is correct in its current form. Are you interested in that? Yes no. I agree its not an ideal implementation (it actually was mine to begin with) to just use a string full of cookies. But we can't pass around complex structures through avopts, which is where we would really see the benefit. As you Mark pointed out, we need to maintain compatibility with the current format, so why why go through parsing the cookie list each time if 1 in 100 requests actually sends back an updated cookie, and even then you'd have to dump it back out to a string and parse it again to pass it between http requests all this considered, I'd say I'm definitely leaning to no unless there is something I've overlooked. I'll follow up separately on the issues in the patch. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] Replace old cookies with new cookies of the same name
When new cookie values (with the same name as an existing cookie) are returned in an HLS stream, the current implementation will append the new cookie to the list of cookies. This causes FFMPEG to send multiple cookie values for the same cookie and in some cases exceed the http header size in some cases. The patch attached resolves the issue. -- 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 ad65b070a7b49698e623f08365ec7e751d0bae08 Mon Sep 17 00:00:00 2001 From: Micah Galizia micahgali...@gmail.com Date: Sun, 17 Aug 2014 20:50:02 +1000 Subject: [PATCH] Replace old cookies with new cookies of the same name --- libavformat/http.c | 86 +- 1 file changed, 73 insertions(+), 13 deletions(-) diff --git a/libavformat/http.c b/libavformat/http.c index 7480834..f1b9c34 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -444,6 +444,77 @@ static int parse_icy(HTTPContext *s, const char *tag, const char *p) return 0; } +static int update_cookies(URLContext *h, char **cookies, char *new_cookie) { + +int prefix, offset, suffix, new_cookie_len = strlen(new_cookie); +char *name, *cookie, *next; + +// if the existing cookies are empty then just set it and forget it +if (!*cookies) { +if (!(*cookies = av_strdup(new_cookie))) +return AVERROR(ENOMEM); +return 0; +} + +// get the new cookies name +if (!(cookie = av_strdup(new_cookie))) +return AVERROR(ENOMEM); + +// if the new cookie format isnt valid just return (without error) +if (!(name = av_strtok(cookie, =, next))) { +av_log(h, AV_LOG_INFO, Invalid new cookie format.); +return 0; +} + +// copy the name and then free the copy of the cookies +name = av_asprintf(%s=, name); +av_free(cookie); + +// find the offset and free the name (we don't need it anymore) +next = av_stristr(*cookies, name); +av_free(name); + +// if no substring is found, just append +if (!next) { +cookie = av_asprintf(%s\n%s, *cookies, new_cookie); +av_free(*cookies); +*cookies = cookie; +return 0; +} + +prefix = next - *cookies; + +// no subsequent newline means this is the last cookie +if (!(next = av_stristr(next, \n))) { + +// old and new cookie plus null terminate +if (!(cookie = av_malloc(prefix + new_cookie_len + 1))) +return AVERROR(ENOMEM); + +strncpy(cookie, *cookies, prefix); +sprintf(cookie[prefix], %s, new_cookie); +av_free(*cookies); +*cookies = cookie; +return 0; +} + +offset = next - *cookies; +suffix = strlen(*cookies) - offset; + +if (!(cookie = av_malloc(prefix + suffix + new_cookie_len + 2))) +return AVERROR(ENOMEM); + +// copy in the prefix, new cookie, and suffix if they exist +if (prefix) strncpy(cookie, *cookies, prefix); +sprintf(cookie[prefix], %s, new_cookie); +if (suffix) strncpy(cookie[prefix + new_cookie_len], ((*cookies)[offset]), suffix); + +av_free(*cookies); +*cookies = cookie; + +return 0; +} + static int process_line(URLContext *h, char *line, int line_count, int *new_location) { @@ -515,19 +586,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); -} +update_cookies(h, s-cookies, p); +av_log(h, AV_LOG_VERBOSE, Cookies set to '%s'\n, s-cookies); } else if (!av_strcasecmp(tag, Icy-MetaInt)) { s-icy_metaint = strtoll(p, NULL, 10); } else if (!av_strncasecmp(tag, Icy-, 4)) { -- 1.9.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel