You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1408 lines
46 KiB
1408 lines
46 KiB
From 4ce37d79704623778fbe266397c85ed2b735e4dd Mon Sep 17 00:00:00 2001 |
|
From: Daniel Stenberg <daniel@haxx.se> |
|
Date: Fri, 15 Mar 2013 14:18:16 +0100 |
|
Subject: [PATCH 1/7] HTTP proxy: insert slash in URL if missing |
|
|
|
curl has been accepting URLs using slightly wrong syntax for a long |
|
time, such as when completely missing as slash "http://example.org" or |
|
missing a slash when a query part is given |
|
"http://example.org?q=foobar". |
|
|
|
curl would translate these into a legitimate HTTP request to servers, |
|
although as was shown in bug #1206 it was not adjusted properly in the |
|
cases where a HTTP proxy was used. |
|
|
|
Test 1213 and 1214 were added to the test suite to verify this fix. |
|
|
|
The test HTTP server was adjusted to allow us to specify test number in |
|
the host name only without using any slashes in a given URL. |
|
|
|
Bug: http://curl.haxx.se/bug/view.cgi?id=1206 |
|
Reported by: ScottJi |
|
|
|
Upstream-commit: e4b733e3f1a771bd1017cdcfb355fcb9caffe646 |
|
Signed-off-by: Kamil Dudka <kdudka@redhat.com> |
|
--- |
|
lib/url.c | 38 ++++++++++++++++++++++++++++++++++ |
|
tests/FILEFORMAT | 4 ++++ |
|
tests/data/Makefile.am | 2 +- |
|
tests/data/Makefile.in | 2 +- |
|
tests/data/test1213 | 53 +++++++++++++++++++++++++++++++++++++++++++++++ |
|
tests/data/test1214 | 53 +++++++++++++++++++++++++++++++++++++++++++++++ |
|
tests/server/sws.c | 56 ++++++++++++++++++++++++++++++++++++++++++-------- |
|
7 files changed, 198 insertions(+), 10 deletions(-) |
|
create mode 100644 tests/data/test1213 |
|
create mode 100644 tests/data/test1214 |
|
|
|
diff --git a/lib/url.c b/lib/url.c |
|
index 181f0a4..77549ba 100644 |
|
--- a/lib/url.c |
|
+++ b/lib/url.c |
|
@@ -3584,6 +3584,7 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, |
|
char protobuf[16]; |
|
const char *protop; |
|
CURLcode result; |
|
+ bool fix_slash = FALSE; |
|
|
|
*prot_missing = FALSE; |
|
|
|
@@ -3730,12 +3731,14 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, |
|
memcpy(path+1, query, hostlen); |
|
|
|
path[0]='/'; /* prepend the missing slash */ |
|
+ fix_slash = TRUE; |
|
|
|
*query=0; /* now cut off the hostname at the ? */ |
|
} |
|
else if(!path[0]) { |
|
/* if there's no path set, use a single slash */ |
|
strcpy(path, "/"); |
|
+ fix_slash = TRUE; |
|
} |
|
|
|
/* If the URL is malformatted (missing a '/' after hostname before path) we |
|
@@ -3748,6 +3751,41 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, |
|
is bigger than the path. Use +1 to move the zero byte too. */ |
|
memmove(&path[1], path, strlen(path)+1); |
|
path[0] = '/'; |
|
+ fix_slash = TRUE; |
|
+ } |
|
+ |
|
+ |
|
+ /* |
|
+ * "fix_slash" means that the URL was malformatted so we need to generate an |
|
+ * updated version with the new slash inserted at the right place! We need |
|
+ * the corrected URL when communicating over HTTP proxy and we don't know at |
|
+ * this point if we're using a proxy or not. |
|
+ */ |
|
+ if(fix_slash) { |
|
+ char *reurl; |
|
+ |
|
+ size_t plen = strlen(path); /* new path, should be 1 byte longer than |
|
+ the original */ |
|
+ size_t urllen = strlen(data->change.url); /* original URL length */ |
|
+ |
|
+ reurl = malloc(urllen + 2); /* 2 for zerobyte + slash */ |
|
+ if(!reurl) |
|
+ return CURLE_OUT_OF_MEMORY; |
|
+ |
|
+ /* copy the prefix */ |
|
+ memcpy(reurl, data->change.url, urllen - (plen-1)); |
|
+ |
|
+ /* append the trailing piece + zerobyte */ |
|
+ memcpy(&reurl[urllen - (plen-1)], path, plen + 1); |
|
+ |
|
+ /* possible free the old one */ |
|
+ if(data->change.url_alloc) { |
|
+ Curl_safefree(data->change.url); |
|
+ data->change.url_alloc = FALSE; |
|
+ } |
|
+ |
|
+ data->change.url = reurl; |
|
+ data->change.url_alloc = TRUE; /* free this later */ |
|
} |
|
|
|
/************************************************************* |
|
diff --git a/tests/FILEFORMAT b/tests/FILEFORMAT |
|
index d79cbf7..96cd5c8 100644 |
|
--- a/tests/FILEFORMAT |
|
+++ b/tests/FILEFORMAT |
|
@@ -250,6 +250,10 @@ If a CONNECT is used to the server (to emulate HTTPS etc over proxy), the port |
|
number given in the CONNECT request will be used to identify which test that |
|
is being run, if the proxy host name is said to start with 'test'. |
|
|
|
+If there's no non-zero test number found in the above to places, the HTTP test |
|
+server will use the number following the last dot in the given url so that |
|
+"foo.bar.123" gets treated as test case 123. |
|
+ |
|
Set type="perl" to write the test case as a perl script. It implies that |
|
there's no memory debugging and valgrind gets shut off for this test. |
|
|
|
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am |
|
index 4e37ed9..5e12f62 100644 |
|
--- a/tests/data/Makefile.am |
|
+++ b/tests/data/Makefile.am |
|
@@ -77,7 +77,7 @@ test1110 test1111 test1112 test1113 test1114 test1115 test1116 test1117 \ |
|
test1118 test1119 test1120 test1121 test1122 test1123 test1124 test1125 \ |
|
test1126 test1127 test1128 test1129 test1130 test1131 test1132 test1133 \ |
|
test1200 test1201 test1202 test1203 test1204 test1205 test1206 test1207 \ |
|
-test1208 test1209 test1210 test1211 test1216 test1218 \ |
|
+test1208 test1209 test1210 test1211 test1213 test1214 test1216 test1218 \ |
|
test1220 test1221 test1222 test1223 test1233 \ |
|
test1300 test1301 test1302 test1303 test1304 test1305 \ |
|
test1306 test1307 test1308 test1309 test1310 test1311 test1312 test1313 \ |
|
diff --git a/tests/data/Makefile.in b/tests/data/Makefile.in |
|
index d7f9ac2..597c1fb 100644 |
|
--- a/tests/data/Makefile.in |
|
+++ b/tests/data/Makefile.in |
|
@@ -341,7 +341,7 @@ test1110 test1111 test1112 test1113 test1114 test1115 test1116 test1117 \ |
|
test1118 test1119 test1120 test1121 test1122 test1123 test1124 test1125 \ |
|
test1126 test1127 test1128 test1129 test1130 test1131 test1132 test1133 \ |
|
test1200 test1201 test1202 test1203 test1204 test1205 test1206 test1207 \ |
|
-test1208 test1209 test1210 test1211 test1216 test1218 \ |
|
+test1208 test1209 test1210 test1211 test1213 test1214 test1216 test1218 \ |
|
test1220 test1221 test1222 test1223 \ |
|
test1300 test1301 test1302 test1303 test1304 test1305 \ |
|
test1306 test1307 test1308 test1309 test1310 test1311 test1312 test1313 \ |
|
diff --git a/tests/data/test1213 b/tests/data/test1213 |
|
new file mode 100644 |
|
index 0000000..d0d12b4 |
|
--- /dev/null |
|
+++ b/tests/data/test1213 |
|
@@ -0,0 +1,53 @@ |
|
+<testcase> |
|
+<info> |
|
+<keywords> |
|
+HTTP |
|
+HTTP GET |
|
+HTTP proxy |
|
+</keywords> |
|
+</info> |
|
+ |
|
+# Server-side |
|
+<reply> |
|
+<data> |
|
+HTTP/1.1 200 OK |
|
+Date: Thu, 09 Nov 2010 14:49:00 GMT |
|
+Server: test-server/fake |
|
+Content-Type: text/html |
|
+Funny-head: yesyes |
|
+Content-Length: 22 |
|
+ |
|
+the content goes here |
|
+</data> |
|
+</reply> |
|
+ |
|
+# Client-side |
|
+<client> |
|
+<server> |
|
+http |
|
+</server> |
|
+ <name> |
|
+HTTP with proxy and host-only URL |
|
+ </name> |
|
+# the thing here is that this sloppy form is accepted and we convert it |
|
+# for normal server use, and we need to make sure it gets converted to |
|
+# RFC style even for proxies |
|
+ <command> |
|
+-x %HOSTIP:%HTTPPORT we.want.that.site.com.1213 |
|
+</command> |
|
+</client> |
|
+ |
|
+# Verify data after the test has been "shot" |
|
+<verify> |
|
+<strip> |
|
+^User-Agent:.* |
|
+</strip> |
|
+<protocol> |
|
+GET HTTP://we.want.that.site.com.1213/ HTTP/1.1 |
|
+Host: we.want.that.site.com.1213 |
|
+Accept: */* |
|
+Proxy-Connection: Keep-Alive |
|
+ |
|
+</protocol> |
|
+</verify> |
|
+</testcase> |
|
diff --git a/tests/data/test1214 b/tests/data/test1214 |
|
new file mode 100644 |
|
index 0000000..8c36ade |
|
--- /dev/null |
|
+++ b/tests/data/test1214 |
|
@@ -0,0 +1,53 @@ |
|
+<testcase> |
|
+<info> |
|
+<keywords> |
|
+HTTP |
|
+HTTP GET |
|
+HTTP proxy |
|
+</keywords> |
|
+</info> |
|
+ |
|
+# Server-side |
|
+<reply> |
|
+<data> |
|
+HTTP/1.1 200 OK |
|
+Date: Thu, 09 Nov 2010 14:49:00 GMT |
|
+Server: test-server/fake |
|
+Content-Type: text/html |
|
+Funny-head: yesyes |
|
+Content-Length: 22 |
|
+ |
|
+the content goes here |
|
+</data> |
|
+</reply> |
|
+ |
|
+# Client-side |
|
+<client> |
|
+<server> |
|
+http |
|
+</server> |
|
+ <name> |
|
+HTTP with proxy and URL with ? and no slash separator |
|
+ </name> |
|
+# the thing here is that this sloppy form is accepted and we convert it |
|
+# for normal server use, and we need to make sure it gets converted to |
|
+# RFC style even for proxies |
|
+ <command> |
|
+-x %HOSTIP:%HTTPPORT http://we.want.that.site.com.1214?moo=foo |
|
+</command> |
|
+</client> |
|
+ |
|
+# Verify data after the test has been "shot" |
|
+<verify> |
|
+<strip> |
|
+^User-Agent:.* |
|
+</strip> |
|
+<protocol> |
|
+GET http://we.want.that.site.com.1214/?moo=foo HTTP/1.1 |
|
+Host: we.want.that.site.com.1214 |
|
+Accept: */* |
|
+Proxy-Connection: Keep-Alive |
|
+ |
|
+</protocol> |
|
+</verify> |
|
+</testcase> |
|
diff --git a/tests/server/sws.c b/tests/server/sws.c |
|
index a7de09f..aef55ea 100644 |
|
--- a/tests/server/sws.c |
|
+++ b/tests/server/sws.c |
|
@@ -507,15 +507,24 @@ static int ProcessRequest(struct httprequest *req) |
|
else |
|
req->partno = 0; |
|
|
|
- sprintf(logbuf, "Requested test number %ld part %ld", |
|
- req->testno, req->partno); |
|
- logmsg("%s", logbuf); |
|
+ if(req->testno) { |
|
+ |
|
+ sprintf(logbuf, "Requested test number %ld part %ld", |
|
+ req->testno, req->partno); |
|
+ logmsg("%s", logbuf); |
|
|
|
- /* find and parse <servercmd> for this test */ |
|
- parse_servercmd(req); |
|
+ /* find and parse <servercmd> for this test */ |
|
+ parse_servercmd(req); |
|
+ } |
|
+ else |
|
+ req->testno = DOCNUMBER_NOTHING; |
|
|
|
} |
|
- else { |
|
+ |
|
+ if(req->testno == DOCNUMBER_NOTHING) { |
|
+ /* didn't find any in the first scan, try alternative test case |
|
+ number placements */ |
|
+ |
|
if(sscanf(req->reqbuf, "CONNECT %" MAXDOCNAMELEN_TXT "s HTTP/%d.%d", |
|
doc, &prot_major, &prot_minor) == 3) { |
|
char *portp = NULL; |
|
@@ -563,8 +572,39 @@ static int ProcessRequest(struct httprequest *req) |
|
parse_servercmd(req); |
|
} |
|
else { |
|
- logmsg("Did not find test number in PATH"); |
|
- req->testno = DOCNUMBER_404; |
|
+ /* there was no trailing slash and it wasn't CONNECT, then we get the |
|
+ the number off the last dot instead, IE we consider the TLD to be |
|
+ the test number. Test 123 can then be written as |
|
+ "example.com.123". */ |
|
+ |
|
+ /* find the last dot */ |
|
+ ptr = strrchr(doc, '.'); |
|
+ |
|
+ /* get the number after it */ |
|
+ if(ptr) { |
|
+ ptr++; /* skip the dot */ |
|
+ |
|
+ req->testno = strtol(ptr, &ptr, 10); |
|
+ |
|
+ if(req->testno > 10000) { |
|
+ req->partno = req->testno % 10000; |
|
+ req->testno /= 10000; |
|
+ } |
|
+ else |
|
+ req->partno = 0; |
|
+ |
|
+ sprintf(logbuf, "Requested test number %ld part %ld (from host name)", |
|
+ req->testno, req->partno); |
|
+ logmsg("%s", logbuf); |
|
+ |
|
+ } |
|
+ |
|
+ if(!req->testno) { |
|
+ logmsg("Did not find test number in PATH"); |
|
+ req->testno = DOCNUMBER_404; |
|
+ } |
|
+ else |
|
+ parse_servercmd(req); |
|
} |
|
} |
|
} |
|
-- |
|
2.1.0 |
|
|
|
|
|
From 052143a4aaac9ce91ffdb6ae88eb5888c54d66aa Mon Sep 17 00:00:00 2001 |
|
From: YAMADA Yasuharu <yasuharu.yamada@access-company.com> |
|
Date: Sat, 18 May 2013 22:51:31 +0200 |
|
Subject: [PATCH 2/7] 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 |
|
Upstream-commit: 04f52e9b4db01bcbf672c9c69303a4e4ad0d0fb9 |
|
Signed-off-by: Kamil Dudka <kdudka@redhat.com> |
|
--- |
|
lib/cookie.c | 33 ++++++++++++++++++++++++++---- |
|
tests/data/Makefile.am | 2 +- |
|
tests/data/Makefile.in | 2 +- |
|
tests/data/test1228 | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
tests/data/test46 | 8 ++++---- |
|
tests/data/test8 | 2 +- |
|
6 files changed, 90 insertions(+), 11 deletions(-) |
|
create mode 100644 tests/data/test1228 |
|
|
|
diff --git a/lib/cookie.c b/lib/cookie.c |
|
index ac4d89c..a4480c0 100644 |
|
--- a/lib/cookie.c |
|
+++ b/lib/cookie.c |
|
@@ -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). |
|
*/ |
|
@@ -841,10 +869,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 */ |
|
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am |
|
index 4e37ed9..64662c6 100644 |
|
--- a/tests/data/Makefile.am |
|
+++ b/tests/data/Makefile.am |
|
@@ -78,7 +78,7 @@ test1118 test1119 test1120 test1121 test1122 test1123 test1124 test1125 \ |
|
test1126 test1127 test1128 test1129 test1130 test1131 test1132 test1133 \ |
|
test1200 test1201 test1202 test1203 test1204 test1205 test1206 test1207 \ |
|
test1208 test1209 test1210 test1211 test1213 test1214 test1216 test1218 \ |
|
-test1220 test1221 test1222 test1223 test1233 \ |
|
+test1220 test1221 test1222 test1223 test1233 test1236 \ |
|
test1300 test1301 test1302 test1303 test1304 test1305 \ |
|
test1306 test1307 test1308 test1309 test1310 test1311 test1312 test1313 \ |
|
test1314 test1315 test1316 test1317 test1318 test1319 test1320 test1321 \ |
|
diff --git a/tests/data/Makefile.in b/tests/data/Makefile.in |
|
index 1e6d679..5296c09 100644 |
|
--- a/tests/data/Makefile.in |
|
+++ b/tests/data/Makefile.in |
|
@@ -342,7 +342,7 @@ test1118 test1119 test1120 test1121 test1122 test1123 test1124 test1125 \ |
|
test1126 test1127 test1128 test1129 test1130 test1131 test1132 test1133 \ |
|
test1200 test1201 test1202 test1203 test1204 test1205 test1206 test1207 \ |
|
test1208 test1209 test1210 test1211 test1213 test1214 test1216 test1218 \ |
|
-test1220 test1221 test1222 test1223 \ |
|
+test1220 test1221 test1222 test1223 test1233 test1236 \ |
|
test1300 test1301 test1302 test1303 test1304 test1305 \ |
|
test1306 test1307 test1308 test1309 test1310 test1311 test1312 test1313 \ |
|
test1314 test1315 test1316 test1317 test1318 test1319 test1320 test1321 \ |
|
diff --git a/tests/data/test1228 b/tests/data/test1228 |
|
new file mode 100644 |
|
index 0000000..0a76b87 |
|
--- /dev/null |
|
+++ b/tests/data/test1228 |
|
@@ -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 |
|
+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> |
|
diff --git a/tests/data/test46 b/tests/data/test46 |
|
index f73acde..b6f8f83 100644 |
|
--- a/tests/data/test46 |
|
+++ b/tests/data/test46 |
|
@@ -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 |
|
diff --git a/tests/data/test8 b/tests/data/test8 |
|
index c36408a..4d54541 100644 |
|
--- a/tests/data/test8 |
|
+++ b/tests/data/test8 |
|
@@ -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 |
|
Host: %HOSTIP:%HTTPPORT |
|
Accept: */* |
|
-Cookie: cookie=perhaps; cookie=yes; partmatch=present; foobar=name; blexp=yesyes |
|
+Cookie: cookie=perhaps; cookie=yes; foobar=name; blexp=yesyes |
|
|
|
</protocol> |
|
</verify> |
|
-- |
|
2.1.0 |
|
|
|
|
|
From 847085920706380e75f8cb23f2a161cdcdfcb384 Mon Sep 17 00:00:00 2001 |
|
From: YAMADA Yasuharu <yasuharu.yamada@access-company.com> |
|
Date: Wed, 12 Jun 2013 11:19:56 +0200 |
|
Subject: [PATCH 3/7] 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). |
|
Upstream-commit: f24dc09d209a2f91ca38d854f0c15ad93f3d7e2d |
|
Signed-off-by: Kamil Dudka <kdudka@redhat.com> |
|
--- |
|
lib/cookie.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++-------- |
|
lib/cookie.h | 3 +- |
|
tests/data/test31 | 3 ++ |
|
3 files changed, 128 insertions(+), 21 deletions(-) |
|
|
|
diff --git a/lib/cookie.c b/lib/cookie.c |
|
index a4480c0..1d226cf 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; |
|
} |
|
|
|
/* |
|
@@ -316,6 +400,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)) { |
|
/* note that this name may or may not have a preceding dot, but |
|
@@ -489,6 +578,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; |
|
@@ -580,12 +672,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: |
|
@@ -656,14 +757,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; |
|
@@ -692,6 +793,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); |
|
|
|
@@ -869,7 +972,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 d3b63f7..bd89082 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 */ |
|
diff --git a/tests/data/test31 b/tests/data/test31 |
|
index b1171d8..38af83b 100644 |
|
--- a/tests/data/test31 |
|
+++ b/tests/data/test31 |
|
@@ -18,6 +18,8 @@ Content-Type: text/html |
|
Funny-head: yesyes |
|
Set-Cookie: foobar=name; domain=anything.com; path=/ ; secure |
|
Set-Cookie:ismatch=this ; domain=127.0.0.1; path=/silly/ |
|
+Set-Cookie: overwrite=this ; domain=127.0.0.1; path=/overwrite/ |
|
+Set-Cookie: overwrite=this2 ; domain=127.0.0.1; path=/overwrite |
|
Set-Cookie: sec1value=secure1 ; domain=127.0.0.1; path=/secure1/ ; secure |
|
Set-Cookie: sec2value=secure2 ; domain=127.0.0.1; path=/secure2/ ; secure= |
|
Set-Cookie: sec3value=secure3 ; domain=127.0.0.1; path=/secure3/ ; secure= |
|
@@ -94,6 +96,7 @@ Accept: */* |
|
# This file was generated by libcurl! Edit at your own risk. |
|
|
|
.127.0.0.1 TRUE /silly/ FALSE 0 ismatch this |
|
+.127.0.0.1 TRUE /overwrite FALSE 0 overwrite this2 |
|
.127.0.0.1 TRUE /secure1/ TRUE 0 sec1value secure1 |
|
.127.0.0.1 TRUE /secure2/ TRUE 0 sec2value secure2 |
|
.127.0.0.1 TRUE /secure3/ TRUE 0 sec3value secure3 |
|
-- |
|
2.1.0 |
|
|
|
|
|
From ffe02d8f3950b5fcf0470890a112125327606f35 Mon Sep 17 00:00:00 2001 |
|
From: YAMADA Yasuharu <yasuharu.yamada@access-company.com> |
|
Date: Tue, 17 Sep 2013 15:51:22 +0900 |
|
Subject: [PATCH 4/7] cookies: add expiration |
|
|
|
Implement: Expired Cookies These following situation, curl removes |
|
cookie(s) from struct CookieInfo if the cookie expired. |
|
- Curl_cookie_add() |
|
- Curl_cookie_getlist() |
|
- cookie_output() |
|
|
|
Upstream-commit: 4cfbb201c4f823ba31ba4b895044088fba6ae535 |
|
Signed-off-by: Kamil Dudka <kdudka@redhat.com> |
|
--- |
|
lib/cookie.c | 37 ++++++++++++++++++++++++++ |
|
tests/data/Makefile.am | 2 +- |
|
tests/data/Makefile.in | 2 +- |
|
tests/data/test1415 | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
4 files changed, 111 insertions(+), 2 deletions(-) |
|
create mode 100644 tests/data/test1415 |
|
|
|
diff --git a/lib/cookie.c b/lib/cookie.c |
|
index 1d226cf..0ca0829 100644 |
|
--- a/lib/cookie.c |
|
+++ b/lib/cookie.c |
|
@@ -289,6 +289,34 @@ static void strstore(char **str, const char *newstr) |
|
*str = strdup(newstr); |
|
} |
|
|
|
+/* |
|
+ * remove_expired() removes expired cookies. |
|
+ */ |
|
+static void remove_expired(struct CookieInfo *cookies) |
|
+{ |
|
+ struct Cookie *co, *nx, *pv; |
|
+ curl_off_t now = (curl_off_t)time(NULL); |
|
+ |
|
+ co = cookies->cookies; |
|
+ pv = NULL; |
|
+ while(co) { |
|
+ nx = co->next; |
|
+ if((co->expirestr || co->maxage) && co->expires < now) { |
|
+ if(co == cookies->cookies) { |
|
+ cookies->cookies = co->next; |
|
+ } |
|
+ else { |
|
+ pv->next = co->next; |
|
+ } |
|
+ cookies->numcookies--; |
|
+ freecookie(co); |
|
+ } |
|
+ else { |
|
+ pv = co; |
|
+ } |
|
+ co = nx; |
|
+ } |
|
+} |
|
|
|
/**************************************************************************** |
|
* |
|
@@ -740,6 +768,9 @@ Curl_cookie_add(struct SessionHandle *data, |
|
superceeds an already existing cookie, which it may if the previous have |
|
the same domain and path as this */ |
|
|
|
+ /* at first, remove expired cookies */ |
|
+ remove_expired(c); |
|
+ |
|
clist = c->cookies; |
|
replace_old = FALSE; |
|
while(clist) { |
|
@@ -954,6 +985,9 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, |
|
if(!c || !c->cookies) |
|
return NULL; /* no cookie struct or no cookies in the struct */ |
|
|
|
+ /* at first, remove expired cookies */ |
|
+ remove_expired(c); |
|
+ |
|
co = c->cookies; |
|
|
|
while(co) { |
|
@@ -1196,6 +1230,9 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) |
|
destination file */ |
|
return 0; |
|
|
|
+ /* at first, remove expired cookies */ |
|
+ remove_expired(c); |
|
+ |
|
if(strequal("-", dumphere)) { |
|
/* use stdout */ |
|
out = stdout; |
|
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am |
|
index 64662c6..f34268c 100644 |
|
--- a/tests/data/Makefile.am |
|
+++ b/tests/data/Makefile.am |
|
@@ -92,7 +92,7 @@ test1371 test1372 test1373 test1374 test1375 test1376 test1377 test1378 \ |
|
test1379 test1380 test1381 test1382 test1383 test1384 test1385 test1386 \ |
|
test1387 test1388 test1389 test1390 test1391 test1392 test1393 \ |
|
test1400 test1401 test1402 test1403 test1404 test1405 test1406 test1407 \ |
|
-test1408 test1409 test1410 test1411 test1412 test1413 \ |
|
+test1408 test1409 test1410 test1411 test1412 test1413 test1415 \ |
|
test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \ |
|
test1508 \ |
|
test2000 test2001 test2002 test2003 test2004 test2005 test2006 test2007 \ |
|
diff --git a/tests/data/Makefile.in b/tests/data/Makefile.in |
|
index 791fa1e..cd2c322 100644 |
|
--- a/tests/data/Makefile.in |
|
+++ b/tests/data/Makefile.in |
|
@@ -356,7 +356,7 @@ test1371 test1372 test1373 test1374 test1375 test1376 test1377 test1378 \ |
|
test1379 test1380 test1381 test1382 test1383 test1384 test1385 test1386 \ |
|
test1387 test1388 test1389 test1390 test1391 test1392 test1393 \ |
|
test1400 test1401 test1402 test1403 test1404 test1405 test1406 test1407 \ |
|
-test1408 test1409 test1410 test1411 test1412 test1413 \ |
|
+test1408 test1409 test1410 test1411 test1412 test1413 test1415 \ |
|
test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \ |
|
test1508 \ |
|
test2000 test2001 test2002 test2003 test2004 test2005 test2006 test2007 \ |
|
diff --git a/tests/data/test1415 b/tests/data/test1415 |
|
new file mode 100644 |
|
index 0000000..cc6bd70 |
|
--- /dev/null |
|
+++ b/tests/data/test1415 |
|
@@ -0,0 +1,72 @@ |
|
+<testcase> |
|
+<info> |
|
+<keywords> |
|
+HTTP |
|
+HTTP GET |
|
+cookies |
|
+cookiejar |
|
+delete expired cookie |
|
+</keywords> |
|
+</info> |
|
+# Server-side |
|
+<reply> |
|
+<data> |
|
+HTTP/1.1 200 OK |
|
+Date: Thu, 09 Nov 2010 14:49:00 GMT |
|
+Server: test-server/fake |
|
+Content-Length: 4 |
|
+Content-Type: text/html |
|
+Funny-head: yesyes |
|
+Set-Cookie: test1value=test1; domain=example.com; path=/; |
|
+Set-Cookie: test2value=test2; expires=Friday, 01-Jan-2038 00:00:00 GMT; domain=example.com; path=/; |
|
+Set-Cookie: test3value=test3; expires=Monday, 13-Jun-1988 03:04:55 GMT; domain=example.com; path=/; |
|
+Set-Cookie: test4value=test4; expires=Friday, 01-Jan-2038 00:00:00 GMT; domain=example.com; path=/; |
|
+Set-Cookie: test5value=test5; expires=Monday, 13-Jun-1988 03:04:55 GMT; domain=example.com; path=/; |
|
+Set-Cookie: test6value=test6; expires=Monday, 13-Jun-1988 03:04:55 GMT; domain=example.com; path=/; |
|
+Set-Cookie: test7value=test7; expires=Friday, 01-Jan-2038 00:00:00 GMT; domain=example.com; path=/; |
|
+Set-Cookie: test8value=test8; expires=Monday, 13-Jun-1988 03:04:55 GMT; domain=example.com; path=/; |
|
+ |
|
+boo |
|
+</data> |
|
+</reply> |
|
+ |
|
+# Client-side |
|
+<client> |
|
+<server> |
|
+http |
|
+</server> |
|
+<name> |
|
+Delete expired cookies |
|
+</name> |
|
+<setenv> |
|
+TZ=GMT |
|
+</setenv> |
|
+<command> |
|
+http://example.com/we/want/1415 -b none -c log/jar1415.txt -x %HOSTIP:%HTTPPORT |
|
+</command> |
|
+ |
|
+# Verify data after the test has been "shot" |
|
+<verify> |
|
+<strip> |
|
+^User-Agent:.* |
|
+</strip> |
|
+<protocol> |
|
+GET http://example.com/we/want/1415 HTTP/1.1 |
|
+Host: example.com |
|
+Accept: */* |
|
+Proxy-Connection: Keep-Alive |
|
+ |
|
+</protocol> |
|
+ |
|
+<file name="log/jar1415.txt" mode="text"> |
|
+# Netscape HTTP Cookie File |
|
+# http://curl.haxx.se/docs/http-cookies.html |
|
+# This file was generated by libcurl! Edit at your own risk. |
|
+ |
|
+.example.com TRUE / FALSE 0 test1value test1 |
|
+.example.com TRUE / FALSE 2145916800 test2value test2 |
|
+.example.com TRUE / FALSE 2145916800 test4value test4 |
|
+.example.com TRUE / FALSE 2145916800 test7value test7 |
|
+</file> |
|
+</verify> |
|
+</testcase> |
|
-- |
|
2.1.0 |
|
|
|
|
|
From f866a6369316df97b777289a34db03444f7dedbe Mon Sep 17 00:00:00 2001 |
|
From: Daniel Stenberg <daniel@haxx.se> |
|
Date: Sat, 21 Sep 2013 13:43:39 -0500 |
|
Subject: [PATCH 5/7] test1415: adjusted to work for 32bit time_t |
|
|
|
The libcurl date parser returns INT_MAX for all dates > 2037 so this |
|
test is now made to use 2037 instead of 2038 to work the same for both |
|
32bit and 64bit time_t systems. |
|
|
|
Upstream-commit: 34df869f99477edda61d639151b1edf75998abd9 |
|
Signed-off-by: Kamil Dudka <kdudka@redhat.com> |
|
--- |
|
tests/data/test1415 | 12 ++++++------ |
|
1 file changed, 6 insertions(+), 6 deletions(-) |
|
|
|
diff --git a/tests/data/test1415 b/tests/data/test1415 |
|
index cc6bd70..51eed3e 100644 |
|
--- a/tests/data/test1415 |
|
+++ b/tests/data/test1415 |
|
@@ -18,12 +18,12 @@ Content-Length: 4 |
|
Content-Type: text/html |
|
Funny-head: yesyes |
|
Set-Cookie: test1value=test1; domain=example.com; path=/; |
|
-Set-Cookie: test2value=test2; expires=Friday, 01-Jan-2038 00:00:00 GMT; domain=example.com; path=/; |
|
+Set-Cookie: test2value=test2; expires=Friday, 01-Jan-2037 00:00:00 GMT; domain=example.com; path=/; |
|
Set-Cookie: test3value=test3; expires=Monday, 13-Jun-1988 03:04:55 GMT; domain=example.com; path=/; |
|
-Set-Cookie: test4value=test4; expires=Friday, 01-Jan-2038 00:00:00 GMT; domain=example.com; path=/; |
|
+Set-Cookie: test4value=test4; expires=Friday, 01-Jan-2037 00:00:00 GMT; domain=example.com; path=/; |
|
Set-Cookie: test5value=test5; expires=Monday, 13-Jun-1988 03:04:55 GMT; domain=example.com; path=/; |
|
Set-Cookie: test6value=test6; expires=Monday, 13-Jun-1988 03:04:55 GMT; domain=example.com; path=/; |
|
-Set-Cookie: test7value=test7; expires=Friday, 01-Jan-2038 00:00:00 GMT; domain=example.com; path=/; |
|
+Set-Cookie: test7value=test7; expires=Friday, 01-Jan-2037 00:00:00 GMT; domain=example.com; path=/; |
|
Set-Cookie: test8value=test8; expires=Monday, 13-Jun-1988 03:04:55 GMT; domain=example.com; path=/; |
|
|
|
boo |
|
@@ -64,9 +64,9 @@ Proxy-Connection: Keep-Alive |
|
# This file was generated by libcurl! Edit at your own risk. |
|
|
|
.example.com TRUE / FALSE 0 test1value test1 |
|
-.example.com TRUE / FALSE 2145916800 test2value test2 |
|
-.example.com TRUE / FALSE 2145916800 test4value test4 |
|
-.example.com TRUE / FALSE 2145916800 test7value test7 |
|
+.example.com TRUE / FALSE 2114380800 test2value test2 |
|
+.example.com TRUE / FALSE 2114380800 test4value test4 |
|
+.example.com TRUE / FALSE 2114380800 test7value test7 |
|
</file> |
|
</verify> |
|
</testcase> |
|
-- |
|
2.1.0 |
|
|
|
|
|
From 8471ac93e881f7f17fe598086b6b548289716279 Mon Sep 17 00:00:00 2001 |
|
From: Daniel Stenberg <daniel@haxx.se> |
|
Date: Thu, 16 Jan 2014 08:51:30 +0100 |
|
Subject: [PATCH 6/7] cookie: max-age fixes |
|
|
|
1 - allow >31 bit max-age values |
|
|
|
2 - don't overflow on extremely large max-age values when we add the |
|
value to the current time |
|
|
|
3 - make sure max-age takes precedence over expires as dictated by |
|
RFC6265 |
|
|
|
Bug: http://curl.haxx.se/mail/lib-2014-01/0130.html |
|
Reported-by: Chen Prog |
|
Upstream-commit: ecaf2f02f1df70f0bbcbbbf48914bfc83c8f2a56 |
|
Signed-off-by: Kamil Dudka <kdudka@redhat.com> |
|
--- |
|
lib/cookie.c | 38 ++++++++++++++++++++++++-------------- |
|
1 file changed, 24 insertions(+), 14 deletions(-) |
|
|
|
diff --git a/lib/cookie.c b/lib/cookie.c |
|
index 0ca0829..d4fe9a3 100644 |
|
--- a/lib/cookie.c |
|
+++ b/lib/cookie.c |
|
@@ -523,9 +523,6 @@ Curl_cookie_add(struct SessionHandle *data, |
|
badcookie = TRUE; |
|
break; |
|
} |
|
- co->expires = |
|
- strtol((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0],NULL,10) |
|
- + (long)now; |
|
} |
|
else if(Curl_raw_equal("expires", name)) { |
|
strstore(&co->expirestr, whatptr); |
|
@@ -533,17 +530,6 @@ Curl_cookie_add(struct SessionHandle *data, |
|
badcookie = TRUE; |
|
break; |
|
} |
|
- /* Note that if the date couldn't get parsed for whatever reason, |
|
- the cookie will be treated as a session cookie */ |
|
- co->expires = curl_getdate(what, &now); |
|
- |
|
- /* Session cookies have expires set to 0 so if we get that back |
|
- from the date parser let's add a second to make it a |
|
- non-session cookie */ |
|
- if(co->expires == 0) |
|
- co->expires = 1; |
|
- else if(co->expires < 0) |
|
- co->expires = 0; |
|
} |
|
else if(!co->name) { |
|
co->name = strdup(name); |
|
@@ -578,6 +564,30 @@ Curl_cookie_add(struct SessionHandle *data, |
|
semiptr=strchr(ptr, '\0'); |
|
} while(semiptr); |
|
|
|
+ if(co->maxage) { |
|
+ co->expires = |
|
+ curlx_strtoofft((*co->maxage=='\"')? |
|
+ &co->maxage[1]:&co->maxage[0], NULL, 10); |
|
+ if(CURL_OFF_T_MAX - now < co->expires) |
|
+ /* avoid overflow */ |
|
+ co->expires = CURL_OFF_T_MAX; |
|
+ else |
|
+ co->expires += now; |
|
+ } |
|
+ else if(co->expirestr) { |
|
+ /* Note that if the date couldn't get parsed for whatever reason, |
|
+ the cookie will be treated as a session cookie */ |
|
+ co->expires = curl_getdate(co->expirestr, NULL); |
|
+ |
|
+ /* Session cookies have expires set to 0 so if we get that back |
|
+ from the date parser let's add a second to make it a |
|
+ non-session cookie */ |
|
+ if(co->expires == 0) |
|
+ co->expires = 1; |
|
+ else if(co->expires < 0) |
|
+ co->expires = 0; |
|
+ } |
|
+ |
|
if(!badcookie && !co->domain) { |
|
if(domain) { |
|
/* no domain was given in the header line, set the default */ |
|
-- |
|
2.1.0 |
|
|
|
|
|
From ee52a81c23b918895b363b904ebb5fc9908b55cc Mon Sep 17 00:00:00 2001 |
|
From: Tim Ruehsen <tim.ruehsen@gmx.de> |
|
Date: Tue, 19 Aug 2014 21:01:28 +0200 |
|
Subject: [PATCH 7/7] cookies: only use full host matches for hosts used as IP |
|
address |
|
|
|
By not detecting and rejecting domain names for partial literal IP |
|
addresses properly when parsing received HTTP cookies, libcurl can be |
|
fooled to both send cookies to wrong sites and to allow arbitrary sites |
|
to set cookies for others. |
|
|
|
CVE-2014-3613 |
|
|
|
Bug: http://curl.haxx.se/docs/adv_20140910A.html |
|
Upstream-commit: 8a75dbeb2305297640453029b7905ef51b87e8dd |
|
Signed-off-by: Kamil Dudka <kdudka@redhat.com> |
|
--- |
|
lib/cookie.c | 50 ++++++++++++++++++++++++++++++++++++++---------- |
|
tests/data/test1105 | 3 +-- |
|
tests/data/test31 | 55 +++++++++++++++++++++++++++-------------------------- |
|
tests/data/test8 | 3 ++- |
|
4 files changed, 71 insertions(+), 40 deletions(-) |
|
|
|
diff --git a/lib/cookie.c b/lib/cookie.c |
|
index d4fe9a3..956efd4 100644 |
|
--- a/lib/cookie.c |
|
+++ b/lib/cookie.c |
|
@@ -94,6 +94,7 @@ Example set of cookies: |
|
#include "strtoofft.h" |
|
#include "rawstr.h" |
|
#include "curl_memrchr.h" |
|
+#include "inet_pton.h" |
|
|
|
/* The last #include file should be: */ |
|
#include "memdebug.h" |
|
@@ -318,6 +319,28 @@ static void remove_expired(struct CookieInfo *cookies) |
|
} |
|
} |
|
|
|
+/* |
|
+ * Return true if the given string is an IP(v4|v6) address. |
|
+ */ |
|
+static bool isip(const char *domain) |
|
+{ |
|
+ struct in_addr addr; |
|
+#ifdef ENABLE_IPV6 |
|
+ struct in6_addr addr6; |
|
+#endif |
|
+ |
|
+ if(Curl_inet_pton(AF_INET, domain, &addr) |
|
+#ifdef ENABLE_IPV6 |
|
+ || Curl_inet_pton(AF_INET6, domain, &addr6) |
|
+#endif |
|
+ ) { |
|
+ /* domain name given as IP address */ |
|
+ return TRUE; |
|
+ } |
|
+ |
|
+ return FALSE; |
|
+} |
|
+ |
|
/**************************************************************************** |
|
* |
|
* Curl_cookie_add() |
|
@@ -472,24 +495,27 @@ Curl_cookie_add(struct SessionHandle *data, |
|
whatptr); |
|
} |
|
else { |
|
+ bool is_ip; |
|
+ |
|
/* Now, we make sure that our host is within the given domain, |
|
or the given domain is not valid and thus cannot be set. */ |
|
|
|
if('.' == whatptr[0]) |
|
whatptr++; /* ignore preceding dot */ |
|
|
|
- if(!domain || tailmatch(whatptr, domain)) { |
|
- const char *tailptr=whatptr; |
|
- if(tailptr[0] == '.') |
|
- tailptr++; |
|
- strstore(&co->domain, tailptr); /* don't prefix w/dots |
|
- internally */ |
|
+ is_ip = isip(domain ? domain : whatptr); |
|
+ |
|
+ if(!domain |
|
+ || (is_ip && !strcmp(whatptr, domain)) |
|
+ || (!is_ip && tailmatch(whatptr, domain))) { |
|
+ strstore(&co->domain, whatptr); |
|
if(!co->domain) { |
|
badcookie = TRUE; |
|
break; |
|
} |
|
- co->tailmatch=TRUE; /* we always do that if the domain name was |
|
- given */ |
|
+ if(!is_ip) |
|
+ co->tailmatch=TRUE; /* we always do that if the domain name was |
|
+ given */ |
|
} |
|
else { |
|
/* we did not get a tailmatch and then the attempted set domain |
|
@@ -991,6 +1017,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, |
|
time_t now = time(NULL); |
|
struct Cookie *mainco=NULL; |
|
size_t matches = 0; |
|
+ bool is_ip; |
|
|
|
if(!c || !c->cookies) |
|
return NULL; /* no cookie struct or no cookies in the struct */ |
|
@@ -998,6 +1025,9 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, |
|
/* at first, remove expired cookies */ |
|
remove_expired(c); |
|
|
|
+ /* check if host is an IP(v4|v6) address */ |
|
+ is_ip = isip(host); |
|
+ |
|
co = c->cookies; |
|
|
|
while(co) { |
|
@@ -1009,8 +1039,8 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, |
|
|
|
/* now check if the domain is correct */ |
|
if(!co->domain || |
|
- (co->tailmatch && tailmatch(co->domain, host)) || |
|
- (!co->tailmatch && Curl_raw_equal(host, co->domain)) ) { |
|
+ (co->tailmatch && !is_ip && tailmatch(co->domain, host)) || |
|
+ ((!co->tailmatch || is_ip) && Curl_raw_equal(host, co->domain)) ) { |
|
/* the right part of the host matches the domain stuff in the |
|
cookie data */ |
|
|
|
diff --git a/tests/data/test1105 b/tests/data/test1105 |
|
index 922346f..ea7b198 100644 |
|
--- a/tests/data/test1105 |
|
+++ b/tests/data/test1105 |
|
@@ -59,8 +59,7 @@ userid=myname&password=mypassword |
|
# This file was generated by libcurl! Edit at your own risk. |
|
|
|
127.0.0.1 FALSE /we/want/ FALSE 0 foobar name |
|
-.127.0.0.1 TRUE "/silly/" FALSE 0 mismatch this |
|
-.0.0.1 TRUE / FALSE 0 partmatch present |
|
+127.0.0.1 FALSE "/silly/" FALSE 0 mismatch this |
|
</file> |
|
</verify> |
|
</testcase> |
|
diff --git a/tests/data/test31 b/tests/data/test31 |
|
index 38af83b..dfcac04 100644 |
|
--- a/tests/data/test31 |
|
+++ b/tests/data/test31 |
|
@@ -51,7 +51,8 @@ Set-Cookie: novalue; domain=reallysilly |
|
Set-Cookie: test=yes; domain=foo.com; expires=Sat Feb 2 11:56:27 GMT 2030 |
|
Set-Cookie: test2=yes; domain=se; expires=Sat Feb 2 11:56:27 GMT 2030 |
|
Set-Cookie: magic=yessir; path=/silly/; HttpOnly |
|
-Set-Cookie: blexp=yesyes; domain=.0.0.1; domain=.0.0.1; expiry=totally bad; |
|
+Set-Cookie: blexp=yesyes; domain=127.0.0.1; domain=127.0.0.1; expiry=totally bad; |
|
+Set-Cookie: partialip=nono; domain=.0.0.1; |
|
|
|
boo |
|
</data> |
|
@@ -95,34 +96,34 @@ Accept: */* |
|
# http://curl.haxx.se/docs/http-cookies.html |
|
# This file was generated by libcurl! Edit at your own risk. |
|
|
|
-.127.0.0.1 TRUE /silly/ FALSE 0 ismatch this |
|
-.127.0.0.1 TRUE /overwrite FALSE 0 overwrite this2 |
|
-.127.0.0.1 TRUE /secure1/ TRUE 0 sec1value secure1 |
|
-.127.0.0.1 TRUE /secure2/ TRUE 0 sec2value secure2 |
|
-.127.0.0.1 TRUE /secure3/ TRUE 0 sec3value secure3 |
|
-.127.0.0.1 TRUE /secure4/ TRUE 0 sec4value secure4 |
|
-.127.0.0.1 TRUE /secure5/ TRUE 0 sec5value secure5 |
|
-.127.0.0.1 TRUE /secure6/ TRUE 0 sec6value secure6 |
|
-.127.0.0.1 TRUE /secure7/ TRUE 0 sec7value secure7 |
|
-.127.0.0.1 TRUE /secure8/ TRUE 0 sec8value secure8 |
|
-.127.0.0.1 TRUE /secure9/ TRUE 0 secure very1 |
|
-#HttpOnly_.127.0.0.1 TRUE /p1/ FALSE 0 httpo1 value1 |
|
-#HttpOnly_.127.0.0.1 TRUE /p2/ FALSE 0 httpo2 value2 |
|
-#HttpOnly_.127.0.0.1 TRUE /p3/ FALSE 0 httpo3 value3 |
|
-#HttpOnly_.127.0.0.1 TRUE /p4/ FALSE 0 httpo4 value4 |
|
-#HttpOnly_.127.0.0.1 TRUE /p4/ FALSE 0 httponly myvalue1 |
|
-#HttpOnly_.127.0.0.1 TRUE /p4/ TRUE 0 httpandsec myvalue2 |
|
-#HttpOnly_.127.0.0.1 TRUE /p4/ TRUE 0 httpandsec2 myvalue3 |
|
-#HttpOnly_.127.0.0.1 TRUE /p4/ TRUE 0 httpandsec3 myvalue4 |
|
-#HttpOnly_.127.0.0.1 TRUE /p4/ TRUE 0 httpandsec4 myvalue5 |
|
-#HttpOnly_.127.0.0.1 TRUE /p4/ TRUE 0 httpandsec5 myvalue6 |
|
-#HttpOnly_.127.0.0.1 TRUE /p4/ TRUE 0 httpandsec6 myvalue7 |
|
-#HttpOnly_.127.0.0.1 TRUE /p4/ TRUE 0 httpandsec7 myvalue8 |
|
-#HttpOnly_.127.0.0.1 TRUE /p4/ TRUE 0 httpandsec8 myvalue9 |
|
-.127.0.0.1 TRUE / FALSE 0 partmatch present |
|
+127.0.0.1 FALSE /silly/ FALSE 0 ismatch this |
|
+127.0.0.1 FALSE /overwrite FALSE 0 overwrite this2 |
|
+127.0.0.1 FALSE /secure1/ TRUE 0 sec1value secure1 |
|
+127.0.0.1 FALSE /secure2/ TRUE 0 sec2value secure2 |
|
+127.0.0.1 FALSE /secure3/ TRUE 0 sec3value secure3 |
|
+127.0.0.1 FALSE /secure4/ TRUE 0 sec4value secure4 |
|
+127.0.0.1 FALSE /secure5/ TRUE 0 sec5value secure5 |
|
+127.0.0.1 FALSE /secure6/ TRUE 0 sec6value secure6 |
|
+127.0.0.1 FALSE /secure7/ TRUE 0 sec7value secure7 |
|
+127.0.0.1 FALSE /secure8/ TRUE 0 sec8value secure8 |
|
+127.0.0.1 FALSE /secure9/ TRUE 0 secure very1 |
|
+#HttpOnly_127.0.0.1 FALSE /p1/ FALSE 0 httpo1 value1 |
|
+#HttpOnly_127.0.0.1 FALSE /p2/ FALSE 0 httpo2 value2 |
|
+#HttpOnly_127.0.0.1 FALSE /p3/ FALSE 0 httpo3 value3 |
|
+#HttpOnly_127.0.0.1 FALSE /p4/ FALSE 0 httpo4 value4 |
|
+#HttpOnly_127.0.0.1 FALSE /p4/ FALSE 0 httponly myvalue1 |
|
+#HttpOnly_127.0.0.1 FALSE /p4/ TRUE 0 httpandsec myvalue2 |
|
+#HttpOnly_127.0.0.1 FALSE /p4/ TRUE 0 httpandsec2 myvalue3 |
|
+#HttpOnly_127.0.0.1 FALSE /p4/ TRUE 0 httpandsec3 myvalue4 |
|
+#HttpOnly_127.0.0.1 FALSE /p4/ TRUE 0 httpandsec4 myvalue5 |
|
+#HttpOnly_127.0.0.1 FALSE /p4/ TRUE 0 httpandsec5 myvalue6 |
|
+#HttpOnly_127.0.0.1 FALSE /p4/ TRUE 0 httpandsec6 myvalue7 |
|
+#HttpOnly_127.0.0.1 FALSE /p4/ TRUE 0 httpandsec7 myvalue8 |
|
+#HttpOnly_127.0.0.1 FALSE /p4/ TRUE 0 httpandsec8 myvalue9 |
|
+127.0.0.1 FALSE / FALSE 0 partmatch present |
|
127.0.0.1 FALSE /we/want/ FALSE 2054030187 nodomain value |
|
#HttpOnly_127.0.0.1 FALSE /silly/ FALSE 0 magic yessir |
|
-.0.0.1 TRUE /we/want/ FALSE 0 blexp yesyes |
|
+127.0.0.1 FALSE /we/want/ FALSE 0 blexp yesyes |
|
</file> |
|
</verify> |
|
</testcase> |
|
diff --git a/tests/data/test8 b/tests/data/test8 |
|
index 4d54541..030fd55 100644 |
|
--- a/tests/data/test8 |
|
+++ b/tests/data/test8 |
|
@@ -42,7 +42,8 @@ Set-Cookie: duplicate=test; domain=.0.0.1; domain=.0.0.1; path=/donkey; |
|
Set-Cookie: cookie=yes; path=/we; |
|
Set-Cookie: cookie=perhaps; path=/we/want; |
|
Set-Cookie: nocookie=yes; path=/WE; |
|
-Set-Cookie: blexp=yesyes; domain=.0.0.1; domain=.0.0.1; expiry=totally bad; |
|
+Set-Cookie: blexp=yesyes; domain=%HOSTIP; domain=%HOSTIP; expiry=totally bad; |
|
+Set-Cookie: partialip=nono; domain=.0.0.1; |
|
|
|
</file> |
|
<precheck> |
|
-- |
|
2.1.0 |
|
|
|
|