diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/cookie.c | 143 | ||||
| -rw-r--r-- | lib/cookie.h | 3 | 
2 files changed, 125 insertions, 21 deletions
| diff --git a/lib/cookie.c b/lib/cookie.c index 1ac97fa66..fc918136a 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -106,6 +106,8 @@ static void freecookie(struct Cookie *co)      free(co->domain);    if(co->path)      free(co->path); +  if(co->spath) +    free(co->spath);    if(co->name)      free(co->name);    if(co->value) @@ -143,32 +145,114 @@ static bool tailmatch(const char *cooke_domain, const char *hostname)    return FALSE;  } -static bool pathmatch(const char* cookie_path, const char* url_path) +/* + * matching cookie path and url path + * RFC6265 5.1.4 Paths and Path-Match + */ +static bool pathmatch(const char* cookie_path, const char* request_uri)  { -  size_t cookie_path_len = strlen(cookie_path); -  size_t url_path_len = strlen(url_path); +  size_t cookie_path_len; +  size_t uri_path_len; +  char* uri_path = NULL; +  char* pos; +  bool ret = FALSE; + +  /* cookie_path must not have last '/' separator. ex: /sample */ +  cookie_path_len = strlen(cookie_path); +  if(1 == cookie_path_len) { +    /* cookie_path must be '/' */ +    return TRUE; +  } -  if(url_path_len < cookie_path_len) +  uri_path = strdup(request_uri); +  if(!uri_path)      return FALSE; +  pos = strchr(uri_path, '?'); +  if(pos) +    *pos = 0x0; + +  /* #-fragments are already cut off! */ +  if(0 == strlen(uri_path) || uri_path[0] != '/') { +    free(uri_path); +    uri_path = strdup("/"); +    if(!uri_path) +      return FALSE; +  } + +  /* here, RFC6265 5.1.4 says +     4. Output the characters of the uri-path from the first character up +        to, but not including, the right-most %x2F ("/"). +     but URL path /hoge?fuga=xxx means /hoge/index.cgi?fuga=xxx in some site +     without redirect. +     Ignore this algorithm because /hoge is uri path for this case +     (uri path is not /). +   */ + +  uri_path_len = strlen(uri_path); + +  if(uri_path_len < cookie_path_len) { +    ret = FALSE; +    goto pathmatched; +  }    /* not using checkprefix() because matching should be case-sensitive */ -  if(strncmp(cookie_path, url_path, cookie_path_len)) -    return FALSE; +  if(strncmp(cookie_path, uri_path, cookie_path_len)) { +    ret = FALSE; +    goto pathmatched; +  } -  /* it is true if cookie_path and url_path are the same */ -  if(cookie_path_len == url_path_len) -    return TRUE; +  /* The cookie-path and the uri-path are identical. */ +  if(cookie_path_len == uri_path_len) { +    ret = TRUE; +    goto pathmatched; +  }    /* here, cookie_path_len < url_path_len */ +  if(uri_path[cookie_path_len] == '/') { +    ret = TRUE; +    goto pathmatched; +  } -  /* it is false if cookie path is /example and url path is /examples */ -  if(cookie_path[cookie_path_len - 1] != '/') { -    if(url_path[cookie_path_len] != '/') { -      return FALSE; -    } +  ret = FALSE; + +pathmatched: +  free(uri_path); +  return ret; +} + +/* + * cookie path sanitize + */ +static char *sanitize_cookie_path(const char *cookie_path) +{ +  size_t len; +  char *new_path = strdup(cookie_path); +  if(!new_path) +    return NULL; + +  /* some stupid site sends path attribute with '"'. */ +  if(new_path[0] == '\"') { +    memmove((void *)new_path, (const void *)(new_path + 1), strlen(new_path)); +  } +  if(new_path[strlen(new_path) - 1] == '\"') { +    new_path[strlen(new_path) - 1] = 0x0; +  } + +  /* RFC6265 5.2.4 The Path Attribute */ +  if(new_path[0] != '/') { +    /* Let cookie-path be the default-path. */ +    free(new_path); +    new_path = strdup("/"); +    return new_path; +  } + +  /* convert /hoge/ to /hoge */ +  len = strlen(new_path); +  if(1 < len && new_path[len - 1] == '/') { +    new_path[len - 1] = 0x0;    } -  /* matching! */ -  return TRUE; + +  return new_path;  }  /* @@ -319,6 +403,11 @@ Curl_cookie_add(struct SessionHandle *data,              badcookie = TRUE; /* out of memory bad */              break;            } +          co->spath = sanitize_cookie_path(co->path); +          if(!co->spath) { +            badcookie = TRUE; /* out of memory bad */ +            break; +          }          }          else if(Curl_raw_equal("domain", name)) {            /* Now, we make sure that our host is within the given domain, @@ -454,6 +543,9 @@ Curl_cookie_add(struct SessionHandle *data,          if(co->path) {            memcpy(co->path, path, pathlen);            co->path[pathlen]=0; /* zero terminate */ +          co->spath = sanitize_cookie_path(co->path); +          if(!co->spath) +            badcookie = TRUE; /* out of memory bad */          }          else            badcookie = TRUE; @@ -539,12 +631,21 @@ Curl_cookie_add(struct SessionHandle *data,            co->path = strdup(ptr);            if(!co->path)              badcookie = TRUE; +          else { +            co->spath = sanitize_cookie_path(co->path); +            if(!co->spath) { +              badcookie = TRUE; /* out of memory bad */ +            } +          }            break;          }          /* this doesn't look like a path, make one up! */          co->path = strdup("/");          if(!co->path)            badcookie = TRUE; +        co->spath = strdup("/"); +        if(!co->spath) +          badcookie = TRUE;          fields++; /* add a field and fall down to secure */          /* FALLTHROUGH */        case 3: @@ -615,14 +716,14 @@ Curl_cookie_add(struct SessionHandle *data,        if(replace_old) {          /* the domains were identical */ -        if(clist->path && co->path) { -          if(Curl_raw_equal(clist->path, co->path)) { +        if(clist->spath && co->spath) { +          if(Curl_raw_equal(clist->spath, co->spath)) {              replace_old = TRUE;            }            else              replace_old = FALSE;          } -        else if(!clist->path && !co->path) +        else if(!clist->spath && !co->spath)            replace_old = TRUE;          else            replace_old = FALSE; @@ -651,6 +752,8 @@ Curl_cookie_add(struct SessionHandle *data,            free(clist->domain);          if(clist->path)            free(clist->path); +        if(clist->spath) +          free(clist->spath);          if(clist->expirestr)            free(clist->expirestr); @@ -845,7 +948,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,          /* now check the left part of the path with the cookies path             requirement */ -        if(!co->path || pathmatch(co->path, path) ) { +        if(!co->spath || pathmatch(co->spath, path) ) {            /* and now, we know this is a match and we should create an               entry for the return-linked-list */ diff --git a/lib/cookie.h b/lib/cookie.h index d3b63f780..bd890827c 100644 --- a/lib/cookie.h +++ b/lib/cookie.h @@ -29,7 +29,8 @@ struct Cookie {    struct Cookie *next; /* next in the chain */    char *name;        /* <this> = value */    char *value;       /* name = <this> */ -  char *path;         /* path = <this> */ +  char *path;         /* path = <this> which is in Set-Cookie: */ +  char *spath;        /* sanitized cookie path */    char *domain;      /* domain = <this> */    curl_off_t expires;  /* expires = <this> */    char *expirestr;   /* the plain text version */ | 
