aboutsummaryrefslogtreecommitdiff
path: root/lib/cookie.c
diff options
context:
space:
mode:
authorYAMADA Yasuharu <yasuharu.yamada@access-company.com>2013-06-12 11:19:56 +0200
committerDaniel Stenberg <daniel@haxx.se>2013-06-12 11:19:56 +0200
commitf24dc09d209a2f91ca38d854f0c15ad93f3d7e2d (patch)
tree57921a2f3f0a6c02aa4bfdd0edc32663b0b1fbcc /lib/cookie.c
parent9e10963c207b43e57d0898b924f9e661385db40f (diff)
cookies: follow-up fix for path checking
The initial fix to only compare full path names were done in commit 04f52e9b4db0 but found out to be incomplete. This takes should make the change more complete and there's now two additional tests to verify (test 31 and 62).
Diffstat (limited to 'lib/cookie.c')
-rw-r--r--lib/cookie.c143
1 files changed, 123 insertions, 20 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 */