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
On Wed, Apr 26, 2017 at 09:48:09PM -0400, Micah Galizia wrote: > Signed-off-by: Micah Galizia> --- > libavformat/http.c | 212 > +++-- > 1 file changed, 155 insertions(+), 57 deletions(-) forgot to mention the commit message "Ignore expired cookies" needs lib & file/ module prefix no major issue, i add these on pushing unless i forget [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB I have often repented speaking, but never of holding my tongue. -- Xenocrates signature.asc Description: Digital signature ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] Ignore expired cookies
On Wed, Apr 26, 2017 at 09:48:09PM -0400, Micah Galizia wrote: > Signed-off-by: Micah Galizia> --- > 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; this leaks cstr [...] > @@ -876,87 +979,82 @@ static int get_cookies(HTTPContext *s, char **cookies, > const char *path, > av_dict_free(>cookie_dict); > > *cookies = NULL; > -while ((cookie = av_strtok(set_cookies, "\n", ))) { > -int domain_offset = 0; > -char *param, *next_param, *cdomain = NULL, *cpath = NULL, *cvalue = > NULL; > -set_cookies = NULL; > +while ((cookie = av_strtok(next, "\n", ))) { > +AVDictionary *cookie_params = NULL; > +AVDictionaryEntry *cookie_entry, *e; > > // 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))) { > -if (cookie) { > -// first key-value pair is the actual cookie value > -cvalue = av_strdup(param); > -cookie = NULL; > -} else if (!av_strncasecmp("path=", param, 5)) { > -av_free(cpath); > -cpath = av_strdup([5]); > -} else if (!av_strncasecmp("domain=", param, 7)) { > -// if the cookie specifies a sub-domain, skip the leading > dot thereby > -// supporting URLs that point to sub-domains and the master > domain > -int leading_dot = (param[7] == '.'); > -av_free(cdomain); > -cdomain = av_strdup([7+leading_dot]); > -} else { > -// ignore unknown attributes > -} > +// continue on to the next cookie if this one cannot be parsed > +if (parse_set_cookie(cookie, _params)) > +continue; > + > +// if the cookie has no value, skip it > +cookie_entry = av_dict_get(cookie_params, "", NULL, > AV_DICT_IGNORE_SUFFIX); > +if (!cookie_entry || !cookie_entry->value) { > +av_dict_free(_params); > +continue; > } > -if (!cdomain) > -cdomain = av_strdup(domain); > - > -// ensure all of the necessary values are valid > -if (!cdomain || !cpath || !cvalue) { > -av_log(s, AV_LOG_WARNING, > - "Invalid cookie found, no value, path or domain > specified\n"); > -goto done_cookie; > + > +// if the cookie has expired, don't add it > +if ((e =
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--- 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 = 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) return AVERROR(EINVAL); @@ -876,87 +979,82 @@ static
Re: [FFmpeg-devel] [PATCH] Ignore expired cookies
On Sat, Apr 08, 2017 at 09:05:46PM -0400, Micah Galizia wrote: > Signed-off-by: Micah Galizia> --- > 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); missing failure check also if you get no reviewes of patches and are interrested in the code, try to suggest to help with maintaining it, if noone objects send a patch that adds you to MAINTAINERs thx [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB It is what and why we do it that matters, not just one of them. signature.asc Description: Digital signature ___ 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: 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 GaliziaHello, 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] Ignore expired cookies
Signed-off-by: Micah Galizia--- 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_cookies = av_strdup(s->cookies), *cset_cookies = set_cookies; +char *cookie, *set_cookies = av_strdup(s->cookies), *next = set_cookies; if (!set_cookies) return AVERROR(EINVAL); @@ -876,87 +978,82 @@ static int get_cookies(HTTPContext *s, char
Re: [FFmpeg-devel] [PATCH] Ignore expired cookies
Hi Nicolas! On 2017-03-30 22:12 +0200, Nicolas George wrote: > 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. This code depends already on a 0-terminated string. Otherwise the call of strlen before would be wrong. Also the later loop is also written against a 0-terminated string. IMHO for this patch it's not really important to avoid relying on 0-terminated string. > 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. I am not in general against getting rid of 0-terminated string in some places. I often thought of this too. > All in all, 0-terminated strings were a terrible terrible idea. Yes, they probably still are a bad idea. Alexander ___ 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
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 signature.asc Description: Digital signature ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] Ignore expired cookies
Hi! On 2017-03-29 19:42 -0400, Micah Galizia wrote: > 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. I noticed one or two things while reading the patch. See below. > On Sat, Mar 25, 2017 at 7:27 PM, Micah Galiziawrote: > > Signed-off-by: Micah Galizia > > --- > > 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++; > > +} > > +} 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. > > +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; > > +} The patch seems a bit long for what it achieves. I don't really have any better idea for now. One thing that came to mind: you might be able to merge the skipping-day-of-week loop into the first loop that writes the stripped down date string into the buffer. Alexander > > } 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
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 Galiziawrote: > Signed-off-by: Micah Galizia > --- > 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--- 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
Re: [FFmpeg-devel] [PATCH] Ignore expired cookies
On Sat, 25 Mar 2017 10:31:00 -0400 Micah Galiziawrote: > Signed-off-by: Micah Galizia > --- > 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'; This can overflow sizeof(exp_buf). > + > +// 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... > +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; > } > ___ 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--- 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--- 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] Ignore expired cookies
On Sun, Feb 12, 2017 at 6:28 AM, Nicolas Georgewrote: > 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 whitespace-style characters could be present > here. > > More importantly, this code will happily skip the end-of-string marker > if there are no spaces at all, and that is a big no. > > Also, style nit for here and other places: the code base does not > usually use single-line loops or conditions. > >> +expiry++; >> +end = expiry+1; > >> +while (*end != ';') end++; > > Same problem here. > >> + >> +//
Re: [FFmpeg-devel] [PATCH] Ignore expired cookies
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. Did you test to see how real browsers handle it? > 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. 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. > +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 whitespace-style characters could be present here. More importantly, this code will happily skip the end-of-string marker if there are no spaces at all, and that is a big no. Also, style nit for here and other places: the code base does not usually use single-line loops or conditions. > +expiry++; > +end = expiry+1; > +while (*end != ';') end++; Same problem here. > + > +// ensure the time is parsable > +end = strptime(expiry, "%d %b %Y %H:%M:%S %Z", _buf); strptime() is an XSI extension, and as such not portable enough for the FFmpeg code base. You can look if av_small_strptime() can do the trick. According to https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Date (which is more readable than https://tools.ietf.org/html/rfc6265#section-5.1.1) the correct date syntax starts with the abbreviated day name and a comma, i.e. "%a,". I suspect the code that skips until a space above is there to skip that component, but it should be part of the date parsing itself. Also, %Z is a non-standard GNU and BSD extension, not supported by av_small_strptime(). Fortunately, still according to MDN, only "GMT" is supported here. > + > +// 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)) { Since only GMT is supported, I think you need to use av_timegm(). > +av_log(s, AV_LOG_ERROR, "Ignoring cookie from the past '%s'\n", > p); > +av_free(name); > +return AVERROR(EINVAL); I think it does not need to be an error, but that depends on the general policy to deal with this kind of cases. > +} >
[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--- 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 GaliziaDate: Sat, 11 Feb 2017 21:18:41 -0500 Subject: [PATCH] Ignore expired cookies Signed-off-by: Micah Galizia --- 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