Commit 04f52e9b authored by Yamada Yasuharu's avatar Yamada Yasuharu Committed by Daniel Stenberg
Browse files

cookies: only consider full path matches

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
parent 100a33f7
Loading
Loading
Loading
Loading
+29 −4
Original line number Original line Diff line number Diff line
@@ -143,6 +143,34 @@ static bool tailmatch(const char *cooke_domain, const char *hostname)
  return FALSE;
  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).
 * 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
        /* now check the left part of the path with the cookies path
           requirement */
           requirement */
        if(!co->path ||
        if(!co->path || pathmatch(co->path, path) ) {
           /* not using checkprefix() because matching should be
              case-sensitive */
           !strncmp(co->path, path, strlen(co->path)) ) {


          /* and now, we know this is a match and we should create an
          /* and now, we know this is a match and we should create an
             entry for the return-linked-list */
             entry for the return-linked-list */
+1 −0
Original line number Original line Diff line number Diff line
@@ -93,6 +93,7 @@ test1200 test1201 test1202 test1203 test1204 test1205 test1206 test1207 \
test1208 test1209 test1210 test1211 test1212 test1213 test1214 test1215 \
test1208 test1209 test1210 test1211 test1212 test1213 test1214 test1215 \
test1216 test1217 test1218 test1219 \
test1216 test1217 test1218 test1219 \
test1220 test1221 test1222 test1223 test1224 test1225 test1226 test1227 \
test1220 test1221 test1222 test1223 test1224 test1225 test1226 test1227 \
test1228 \
\
\
test1300 test1301 test1302 test1303 test1304 test1305 test1306 test1307 \
test1300 test1301 test1302 test1303 test1304 test1305 test1306 test1307 \
test1308 test1309 test1310 test1311 test1312 test1313 test1314 test1315 \
test1308 test1309 test1310 test1311 test1312 test1313 test1314 test1315 \

tests/data/test1228

0 → 100644
+54 −0
Original line number Original line Diff line number Diff line
<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
Host: example.fake
Accept: */*
Proxy-Connection: Keep-Alive

GET http://example.fake/hogege/ HTTP/1.1
Host: example.fake
Accept: */*
Proxy-Connection: Keep-Alive
Cookie: path1=root

</protocol>
</verify>
</testcase>
+4 −4
Original line number Original line Diff line number Diff line
@@ -52,8 +52,8 @@ TZ=GMT
www.fake.come	FALSE	/	FALSE	1022144953	cookiecliente	si
www.fake.come	FALSE	/	FALSE	1022144953	cookiecliente	si
www.loser.com	FALSE	/	FALSE	1139150993	UID	99
www.loser.com	FALSE	/	FALSE	1139150993	UID	99
%HOSTIP	FALSE	/	FALSE	1439150993	mooo	indeed
%HOSTIP	FALSE	/	FALSE	1439150993	mooo	indeed
#HttpOnly_%HOSTIP	FALSE	/w	FALSE	1439150993	mooo2	indeed2
#HttpOnly_%HOSTIP	FALSE	/want	FALSE	1439150993	mooo2	indeed2
%HOSTIP	FALSE	/wa	FALSE	0	empty	
%HOSTIP	FALSE	/want	FALSE	0	empty	
</file>
</file>
</client>
</client>


@@ -77,8 +77,8 @@ Cookie: empty=; mooo2=indeed2; mooo=indeed
www.fake.come	FALSE	/	FALSE	1022144953	cookiecliente	si
www.fake.come	FALSE	/	FALSE	1022144953	cookiecliente	si
www.loser.com	FALSE	/	FALSE	1139150993	UID	99
www.loser.com	FALSE	/	FALSE	1139150993	UID	99
%HOSTIP	FALSE	/	FALSE	1439150993	mooo	indeed
%HOSTIP	FALSE	/	FALSE	1439150993	mooo	indeed
#HttpOnly_%HOSTIP	FALSE	/w	FALSE	1439150993	mooo2	indeed2
#HttpOnly_%HOSTIP	FALSE	/want	FALSE	1439150993	mooo2	indeed2
%HOSTIP	FALSE	/wa	FALSE	0	empty	
%HOSTIP	FALSE	/want	FALSE	0	empty	
%HOSTIP	FALSE	/	FALSE	2054030187	ckyPersistent	permanent
%HOSTIP	FALSE	/	FALSE	2054030187	ckyPersistent	permanent
%HOSTIP	FALSE	/	FALSE	0	ckySession	temporary
%HOSTIP	FALSE	/	FALSE	0	ckySession	temporary
%HOSTIP	FALSE	/	FALSE	0	ASPSESSIONIDQGGQQSJJ	GKNBDIFAAOFDPDAIEAKDIBKE
%HOSTIP	FALSE	/	FALSE	0	ASPSESSIONIDQGGQQSJJ	GKNBDIFAAOFDPDAIEAKDIBKE
+1 −1
Original line number Original line Diff line number Diff line
@@ -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
GET /we/want/8 HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Host: %HOSTIP:%HTTPPORT
Accept: */*
Accept: */*
Cookie: cookie=perhaps; cookie=yes; partmatch=present; foobar=name; blexp=yesyes
Cookie: cookie=perhaps; cookie=yes; foobar=name; blexp=yesyes


</protocol>
</protocol>
</verify>
</verify>