cookies: only consider full path matches
authorYAMADA Yasuharu <yasuharu.yamada@access-company.com>
Sat, 18 May 2013 20:51:31 +0000 (22:51 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Sat, 18 May 2013 20:54:48 +0000 (22:54 +0200)
I found a bug which cURL sends cookies to the path not to aim at.
For example:
- cURL sends a request to http://example.fake/hoge/
- server returns cookie which with path=/hoge;
  the point is there is NOT the '/' end of path string.
- cURL sends a request to http://example.fake/hogege/ with the cookie.

The reason for this old "feature" is because that behavior is what is
described in the original netscape cookie spec:
http://curl.haxx.se/rfc/cookie_spec.html

The current cookie spec (RFC6265) clarifies the situation:
http://tools.ietf.org/html/rfc6265#section-5.2.4

lib/cookie.c
tests/data/Makefile.am
tests/data/test1228 [new file with mode: 0644]
tests/data/test46
tests/data/test8

index a67204e..51c55de 100644 (file)
@@ -143,6 +143,34 @@ static bool tailmatch(const char *cooke_domain, const char *hostname)
   return FALSE;
 }
 
+static bool pathmatch(const char* cookie_path, const char* url_path)
+{
+  size_t cookie_path_len = strlen(cookie_path);
+  size_t url_path_len = strlen(url_path);
+
+  if(url_path_len < cookie_path_len)
+    return FALSE;
+
+  /* not using checkprefix() because matching should be case-sensitive */
+  if(strncmp(cookie_path, url_path, cookie_path_len))
+    return FALSE;
+
+  /* it is true if cookie_path and url_path are the same */
+  if(cookie_path_len == url_path_len)
+    return TRUE;
+
+  /* here, cookie_path_len < url_path_len */
+
+  /* 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;
+    }
+  }
+  /* matching! */
+  return TRUE;
+}
+
 /*
  * Load cookies from all given cookie files (CURLOPT_COOKIEFILE).
  */
@@ -858,10 +886,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 ||
-           /* not using checkprefix() because matching should be
-              case-sensitive */
-           !strncmp(co->path, path, strlen(co->path)) ) {
+        if(!co->path || pathmatch(co->path, path) ) {
 
           /* and now, we know this is a match and we should create an
              entry for the return-linked-list */
index 836be0a..8ccdb50 100644 (file)
@@ -93,6 +93,7 @@ test1200 test1201 test1202 test1203 test1204 test1205 test1206 test1207 \
 test1208 test1209 test1210 test1211 test1212 test1213 test1214 test1215 \
 test1216 test1217 test1218 test1219 \
 test1220 test1221 test1222 test1223 test1224 test1225 test1226 test1227 \
+test1228 \
 \
 test1300 test1301 test1302 test1303 test1304 test1305 test1306 test1307 \
 test1308 test1309 test1310 test1311 test1312 test1313 test1314 test1315 \
diff --git a/tests/data/test1228 b/tests/data/test1228
new file mode 100644 (file)
index 0000000..0a76b87
--- /dev/null
@@ -0,0 +1,54 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+cookies 
+cookie path
+</keywords>
+</info>
+<reply>
+<data>
+HTTP/1.1 200 OK
+Date: Tue, 25 Sep 2001 19:37:44 GMT
+Set-Cookie: path1=root; domain=.example.fake; path=/;
+Set-Cookie: path2=depth1; domain=.example.fake; path=/hoge;
+Content-Length: 34
+
+This server says cookie path test
+</data>
+</reply>
+
+# Client-side
+<client>
+<server>
+http
+</server>
+ <name>
+HTTP cookie path match
+ </name>
+ <command>
+http://example.fake/hoge/1228 http://example.fake/hogege/ -b nonexisting -x %HOSTIP:%HTTPPORT
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<strip>
+^User-Agent:.*
+</strip>
+<protocol>
+GET http://example.fake/hoge/1228 HTTP/1.1\r
+Host: example.fake\r
+Accept: */*\r
+Proxy-Connection: Keep-Alive\r
+\r
+GET http://example.fake/hogege/ HTTP/1.1\r
+Host: example.fake\r
+Accept: */*\r
+Proxy-Connection: Keep-Alive\r
+Cookie: path1=root\r
+\r
+</protocol>
+</verify>
+</testcase>
index f73acde..b6f8f83 100644 (file)
@@ -52,8 +52,8 @@ TZ=GMT
 www.fake.come  FALSE   /       FALSE   1022144953      cookiecliente   si
 www.loser.com  FALSE   /       FALSE   1139150993      UID     99
 %HOSTIP        FALSE   /       FALSE   1439150993      mooo    indeed
-#HttpOnly_%HOSTIP      FALSE   /w      FALSE   1439150993      mooo2   indeed2
-%HOSTIP        FALSE   /wa     FALSE   0       empty   
+#HttpOnly_%HOSTIP      FALSE   /want   FALSE   1439150993      mooo2   indeed2
+%HOSTIP        FALSE   /want   FALSE   0       empty   
 </file>
 </client>
 
@@ -77,8 +77,8 @@ Cookie: empty=; mooo2=indeed2; mooo=indeed
 www.fake.come  FALSE   /       FALSE   1022144953      cookiecliente   si
 www.loser.com  FALSE   /       FALSE   1139150993      UID     99
 %HOSTIP        FALSE   /       FALSE   1439150993      mooo    indeed
-#HttpOnly_%HOSTIP      FALSE   /w      FALSE   1439150993      mooo2   indeed2
-%HOSTIP        FALSE   /wa     FALSE   0       empty   
+#HttpOnly_%HOSTIP      FALSE   /want   FALSE   1439150993      mooo2   indeed2
+%HOSTIP        FALSE   /want   FALSE   0       empty   
 %HOSTIP        FALSE   /       FALSE   2054030187      ckyPersistent   permanent
 %HOSTIP        FALSE   /       FALSE   0       ckySession      temporary
 %HOSTIP        FALSE   /       FALSE   0       ASPSESSIONIDQGGQQSJJ    GKNBDIFAAOFDPDAIEAKDIBKE
index c36408a..4d54541 100644 (file)
@@ -59,7 +59,7 @@ perl -e 'if ("%HOSTIP" !~ /\.0\.0\.1$/) {print "Test only works for HOSTIPs endi
 GET /we/want/8 HTTP/1.1\r
 Host: %HOSTIP:%HTTPPORT\r
 Accept: */*\r
-Cookie: cookie=perhaps; cookie=yes; partmatch=present; foobar=name; blexp=yesyes\r
+Cookie: cookie=perhaps; cookie=yes; foobar=name; blexp=yesyes\r
 \r
 </protocol>
 </verify>