Remove support for multiple cookies in one Set-Cookie header to follow RFC6265.
authorJocelyn Turcotte <jocelyn.turcotte@nokia.com>
Wed, 14 Sep 2011 14:12:10 +0000 (16:12 +0200)
committerQt by Nokia <qt-info@nokia.com>
Tue, 26 Jun 2012 22:46:35 +0000 (00:46 +0200)
This also allows cookie values to contain commas to increase compatibility like
most popular browsers do even though the RFC still reserves them for future uses.

Reviewed-by: Peter Hartmann <peter.hartmann@nokia.com>
Task-number: QTBUG-21456
(cherry-picked from 8ba781b01e900148fec2e9d26485369b3295487f)

Change-Id: Ib09ab2411dddf7f99de1c0c31680428b7412fc7e
Reviewed-by: Shane Kearns <shane.kearns@accenture.com>
src/network/access/qnetworkcookie.cpp
tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp

index b3324a1..6a2a70f 100644 (file)
@@ -386,7 +386,7 @@ static QPair<QByteArray, QByteArray> nextField(const QByteArray &text, int &posi
     // parse the first part, before the equal sign
     for (i = position; i < length; ++i) {
         register char c = text.at(i);
-        if (c == ';' || c == ',' || c == '=')
+        if (c == ';' || c == '=')
             break;
     }
 
@@ -437,7 +437,7 @@ static QPair<QByteArray, QByteArray> nextField(const QByteArray &text, int &posi
 
         for ( ; i < length; ++i) {
             register char c = text.at(i);
-            if (c == ',' || c == ';')
+            if (c == ';')
                 break;
         }
         position = i;
@@ -448,7 +448,7 @@ static QPair<QByteArray, QByteArray> nextField(const QByteArray &text, int &posi
             register char c = text.at(i);
             // for name value pairs, we want to parse until reaching the next ';'
             // and not break when reaching a space char
-            if (c == ',' || c == ';' || ((isNameValue && (c == '\n' || c == '\r')) || (!isNameValue && isLWS(c))))
+            if (c == ';' || ((isNameValue && (c == '\n' || c == '\r')) || (!isNameValue && isLWS(c))))
                 break;
         }
 
@@ -475,8 +475,7 @@ static QPair<QByteArray, QByteArray> nextField(const QByteArray &text, int &posi
 
     \value Full                 makes toRawForm() return the full
         cookie contents, as suitable for sending to a client in a
-        server's "Set-Cookie:" header. Multiple cookies are separated
-        by commas in a "Set-Cookie:" header.
+        server's "Set-Cookie:" header.
 
     Note that only the Full form of the cookie can be parsed back into
     its original contents.
@@ -502,7 +501,6 @@ QByteArray QNetworkCookie::toRawForm(RawForm form) const
     result = d->name;
     result += '=';
     if ((d->value.contains(';') ||
-        d->value.contains(',') ||
         d->value.contains('"')) &&
         (!d->value.startsWith('"') &&
         !d->value.endsWith('"'))) {
@@ -981,14 +979,8 @@ QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByt
         cookie.setValue(field.second);
 
         position = nextNonWhitespace(cookieString, position);
-        bool endOfCookie = false;
-        while (!endOfCookie && position < length) {
+        while (position < length) {
             switch (cookieString.at(position++)) {
-            case ',':
-                // end of the cookie
-                endOfCookie = true;
-                break;
-
             case ';':
                 // new field in the cookie
                 field = nextField(cookieString, position, false);
index 4df1084..77dfa18 100644 (file)
@@ -181,6 +181,14 @@ void tst_QNetworkCookie::parseSingleCookie_data()
     QTest::newRow("with-value-with-special4") << "a = \"\\\"\" " << cookie;
     cookie.setValue("\"\\\"a, b; c\\\"\"");
     QTest::newRow("with-value-with-special5") << "a = \"\\\"a, b; c\\\"\"" << cookie;
+    // RFC6265 states that cookie values shouldn't contain commas, but we still allow them
+    // since they are only reserved for future compatibility and other browsers do the same.
+    cookie.setValue(",");
+    QTest::newRow("with-value-with-special6") << "a = ," << cookie;
+    cookie.setValue(",b");
+    QTest::newRow("with-value-with-special7") << "a = ,b" << cookie;
+    cookie.setValue("b,");
+    QTest::newRow("with-value-with-special8") << "a = b," << cookie;
 
     cookie.setValue("b c");
     QTest::newRow("with-value-with-whitespace") << "a = b c" << cookie;
@@ -599,7 +607,6 @@ void tst_QNetworkCookie::parseSingleCookie()
 
     //QEXPECT_FAIL("network2", "QDateTime parsing problem: the date is beyond year 8000", Abort);
     QCOMPARE(result.count(), 1);
-    QEXPECT_FAIL("network3", "Cookie value contains commas, violating the HTTP spec", Abort);
     QCOMPARE(result.at(0), expectedCookie);
 
     result = QNetworkCookie::parseCookies(result.at(0).toRawForm());
@@ -634,48 +641,17 @@ void tst_QNetworkCookie::parseMultipleCookies_data()
     // reason: malformed NAME=VALUE pair
     QTest::newRow("invalid-05") << "foo" << list;
     QTest::newRow("invalid-06") << "=b" << list;
-    QTest::newRow("invalid-09") << "foo,a=b" << list;
-    QTest::newRow("invalid-11") << ";path=/" << list;
+    QTest::newRow("invalid-07") << ";path=/" << list;
 
     // reason: malformed expiration date string
-    QTest::newRow("invalid-12") << "a=b;expires=" << list;
-    QTest::newRow("invalid-13") << "a=b;expires=foobar" << list;
-    QTest::newRow("invalid-14") << "a=b;expires=foobar, abc" << list;
-    QTest::newRow("invalid-15") << "a=b;expires=foobar, dd-mmm-yyyy hh:mm:ss GMT; path=/" << list;
-    QTest::newRow("invalid-16") << "a=b;expires=foobar, 32-Caz-1999 24:01:60 GMT; path=/" << list;
-
-    QNetworkCookie cookie;
-    cookie.setName("a");
-    list += cookie;
-    cookie.setName("c");
-    cookie.setValue("d");
-    list += cookie;
-    QTest::newRow("two-1") << "a=,c=d" << list;
-    QTest::newRow("two-2") << "a=, c=d" << list;
-    QTest::newRow("two-3") << "a= ,c=d" << list;
-    QTest::newRow("two-4") << "a= , c=d" << list;
-
-    list.clear();
-    list += cookie;
-    cookie.setName("a");
-    cookie.setValue(QByteArray());
-    list += cookie;
-    QTest::newRow("two-5") << "c=d,a=" << list;
-    QTest::newRow("two-6") << "c=d, a=" << list;
-    QTest::newRow("two-7") << "c=d , a=" << list;
-
-    cookie.setName("foo");
-    cookie.setValue("bar");
-    cookie.setPath("/");
-    list += cookie;
-    QTest::newRow("complex-1") << "c=d, a=, foo=bar; path=/" << list;
-
-    cookie.setName("baz");
-    cookie.setDomain(".qt.nokia.com");
-    list.prepend(cookie);
-    QTest::newRow("complex-2") << "baz=bar; path=/; domain=.qt.nokia.com, c=d,a=,foo=bar; path=/" << list;
+    QTest::newRow("invalid-08") << "a=b;expires=" << list;
+    QTest::newRow("invalid-09") << "a=b;expires=foobar" << list;
+    QTest::newRow("invalid-10") << "a=b;expires=foobar, abc" << list;
+    QTest::newRow("invalid-11") << "a=b;expires=foobar, dd-mmm-yyyy hh:mm:ss GMT; path=/" << list;
+    QTest::newRow("invalid-12") << "a=b;expires=foobar, 32-Caz-1999 24:01:60 GMT; path=/" << list;
 
     // cookies obtained from the network:
+    QNetworkCookie cookie;
     cookie = QNetworkCookie("id", "51706646077999719");
     cookie.setDomain(".bluestreak.com");
     cookie.setPath("/");