[FFmpeg-devel] [PATCH] Ignore expired cookies

Michael Niedermayer michael at niedermayer.cc
Sat Apr 29 04:10:04 EEST 2017


On Wed, Apr 26, 2017 at 09:48:09PM -0400, Micah Galizia wrote:
> Signed-off-by: Micah Galizia <micahgalizia at 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_MUTLI    2
> +#define MAX_EXPIRY    19
> +#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 = &cstr[strlen(cstr)-1];
> +    while (strchr(WHITESPACES, *back)) {
> +        *back='\0';
> +        back--;
> +    }
> +
> +    next_param = cstr;
> +    while ((param = av_strtok(next_param, ";", &next_param))) {
> +        char *name, *value;
> +        param += strspn(param, WHITESPACES);
> +        if ((name = av_strtok(param, "=", &value))) {
> +            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(&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;
> +    while ((cookie = av_strtok(next, "\n", &next))) {
> +        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, &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
> -                cvalue = av_strdup(param);
> -                cookie = NULL;
> -            } else if (!av_strncasecmp("path=",   param, 5)) {
> -                av_free(cpath);
> -                cpath = av_strdup(&param[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(&param[7+leading_dot]);
> -            } else {
> -                // ignore unknown attributes
> -            }
> +        // continue on to the next cookie if this one cannot be parsed
> +        if (parse_set_cookie(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(&cookie_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 = av_dict_get(cookie_params, "expires", NULL, 0)) && e->value) {
> +            struct tm tm_buf = {0};
> +            if (!parse_set_cookie_expiry_time(e->value, &tm_buf)) {
> +                if (av_timegm(&tm_buf) < av_gettime() / 1000000) {
> +                    av_dict_free(&cookie_params);
> +                    continue;
> +                }
> +            }
>          }
>  
> -        // check if the request path matches the cookie path
> -        if (av_strncasecmp(path, cpath, strlen(cpath)))
> -            goto done_cookie;
> +        // if no domain in the cookie assume it appied to this request
> +        if ((e = av_dict_get(cookie_params, "domain", NULL, 0)) && e->value) {
> +            // find the offset comparison is on the min domain (b.com, not a.b.com)
> +            int domain_offset = strlen(domain) - strlen(e->value);
> +            if (domain_offset < 0) {
> +                av_dict_free(&cookie_params);
> +                continue;
> +            }
>  
> -        // the domain should be at least the size of our cookie domain
> -        domain_offset = strlen(domain) - strlen(cdomain);
> -        if (domain_offset < 0)
> -            goto done_cookie;
> +            // match the cookie domain
> +            if (av_strcasecmp(&domain[domain_offset], e->value)) {
> +                av_dict_free(&cookie_params);
> +                continue;
> +            }
> +        }
>  
> -        // match the cookie domain
> -        if (av_strcasecmp(&domain[domain_offset], cdomain))
> -            goto done_cookie;
> +        // ensure this cookie matches the path
> +        e = av_dict_get(cookie_params, "path", NULL, 0);
> +        if (!e || av_strncasecmp(path, e->value, strlen(e->value))) {
> +            av_dict_free(&cookie_params);
> +            continue;
> +        }
>  
>          // cookie parameters match, so copy the value
>          if (!*cookies) {
> -            if (!(*cookies = av_strdup(cvalue))) {
> +            if (!(*cookies = av_asprintf("%s=%s", cookie_entry->key, cookie_entry->value))) {
>                  ret = AVERROR(ENOMEM);
> -                goto done_cookie;
> +                break;
>              }
>          } else {

>              char *tmp = *cookies;
> -            size_t str_size = strlen(cvalue) + strlen(*cookies) + 3;
> +            size_t str_size = strlen(cookie_entry->key) + strlen(cookie_entry->value) + strlen(*cookies) + 4;
>              if (!(*cookies = av_malloc(str_size))) {
>                  ret = AVERROR(ENOMEM);
> -                goto done_cookie;
> +                break;

This looks like it was already there but tmp leaks here i think

feel free to ignore or fix in a seperate patch as its unrelated to
this patch


[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

Those who would give up essential Liberty, to purchase a little
temporary Safety, deserve neither Liberty nor Safety -- Benjamin Franklin
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 181 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20170429/5827f3ba/attachment.sig>


More information about the ffmpeg-devel mailing list