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