From: Shane Kearns Date: Fri, 8 Jun 2012 13:56:11 +0000 (+0100) Subject: Use RFC6265 rules for cookie path & path matching X-Git-Tag: 071012110112~221 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=058fddd1c01d49ee9fe8b70587a088d73f2c8e3c;p=profile%2Fivi%2Fqtbase.git Use RFC6265 rules for cookie path & path matching Url encoding of paths is no longer used. This matches the current release behaviour of Firefox, Chrome and MSIE browsers. RFC6265 does not allow this type of encoding. This fixes remaining path test cases in the IETF test suite. Currently the path0027 test is passed by Firefox but failed by Chrome and MSIE, so there is a potential compatibility issue. However it is a corner case with a malformed cookie. Task-number: QTBUG-15794 Change-Id: I9b02bb5adc32d614f512d314d06f2c60894aa2b0 Reviewed-by: Richard J. Moore --- diff --git a/src/network/access/qnetworkcookie.cpp b/src/network/access/qnetworkcookie.cpp index 306195a..5a75dd5 100644 --- a/src/network/access/qnetworkcookie.cpp +++ b/src/network/access/qnetworkcookie.cpp @@ -466,7 +466,7 @@ QByteArray QNetworkCookie::toRawForm(RawForm form) const } if (!d->path.isEmpty()) { result += "; path="; - result += QUrl::toPercentEncoding(d->path, "/"); + result += d->path.toUtf8(); } } return result; @@ -954,8 +954,15 @@ QList QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByt } //if unparsed, ignore the attribute but not the whole cookie (RFC6265 section 5.2.2) } else if (field.first == "path") { - QString path = QUrl::fromPercentEncoding(field.second); - cookie.setPath(path); + if (field.second.startsWith('/')) { + // ### we should treat cookie paths as an octet sequence internally + // However RFC6265 says we should assume UTF-8 for presentation as a string + cookie.setPath(QString::fromUtf8(field.second)); + } else { + // if the path doesn't start with '/' then set the default path (RFC6265 section 5.2.4) + // and also IETF test case path0030 which has valid and empty path in the same cookie + cookie.setPath(QString()); + } } else if (field.first == "secure") { cookie.setSecure(true); } else if (field.first == "httponly") { diff --git a/src/network/access/qnetworkcookiejar.cpp b/src/network/access/qnetworkcookiejar.cpp index 9e5dfe0..b4cf8ce 100644 --- a/src/network/access/qnetworkcookiejar.cpp +++ b/src/network/access/qnetworkcookiejar.cpp @@ -140,11 +140,21 @@ void QNetworkCookieJar::setAllCookies(const QList &cookieList) static inline bool isParentPath(QString path, QString reference) { - if (!path.endsWith(QLatin1Char('/'))) - path += QLatin1Char('/'); - if (!reference.endsWith(QLatin1Char('/'))) - reference += QLatin1Char('/'); - return path.startsWith(reference); + if (path.startsWith(reference)) { + //The cookie-path and the request-path are identical. + if (path.length() == reference.length()) + return true; + //The cookie-path is a prefix of the request-path, and the last + //character of the cookie-path is %x2F ("/"). + if (reference.endsWith('/')) + return true; + //The cookie-path is a prefix of the request-path, and the first + //character of the request-path that is not included in the cookie- + //path is a %x2F ("/") character. + if (path.at(reference.length()) == '/') + return true; + } + return false; } static inline bool isParentDomain(QString domain, QString reference) diff --git a/tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp b/tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp index 77afd23..7896003 100644 --- a/tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp +++ b/tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp @@ -235,20 +235,24 @@ void tst_QNetworkCookie::parseSingleCookie_data() QTest::newRow("path9") << "a=b;path=/foo" << cookie; // some weird paths: - cookie.setPath("/with spaces"); + cookie.setPath("/with%20spaces"); QTest::newRow("path-with-spaces") << "a=b;path=/with%20spaces" << cookie; QTest::newRow("path-with-spaces2") << "a=b; path=/with%20spaces " << cookie; - cookie.setPath("\"/with spaces\""); - QTest::newRow("path-with-spaces3") << "a=b; path=\"/with spaces\"" << cookie; - QTest::newRow("path-with-spaces4") << "a=b; path = \"/with spaces\" " << cookie; + cookie.setPath(QString()); + QTest::newRow("invalid-path-with-spaces3") << "a=b; path=\"/with spaces\"" << cookie; + QTest::newRow("invalid-path-with-spaces4") << "a=b; path = \"/with spaces\" " << cookie; + cookie.setPath("/with spaces"); + QTest::newRow("path-with-spaces5") << "a=b; path=/with spaces" << cookie; + QTest::newRow("path-with-spaces6") << "a=b; path = /with spaces " << cookie; cookie.setPath("/with\"Quotes"); - QTest::newRow("path-with-quotes") << "a=b; path = /with%22Quotes" << cookie; - cookie.setPath("\"/with\\\"Quotes\""); - QTest::newRow("path-with-quotes2") << "a=b; path = \"/with\\\"Quotes\"" << cookie; + QTest::newRow("path-with-quotes") << "a=b; path = /with\"Quotes" << cookie; + cookie.setPath(QString()); + QTest::newRow("invalid-path-with-quotes2") << "a=b; path = \"/with\\\"Quotes\"" << cookie; cookie.setPath(QString::fromUtf8("/R\303\251sum\303\251")); QTest::newRow("path-with-utf8") << QString::fromUtf8("a=b;path=/R\303\251sum\303\251") << cookie; + cookie.setPath("/R%C3%A9sum%C3%A9"); QTest::newRow("path-with-utf8-2") << "a=b;path=/R%C3%A9sum%C3%A9" << cookie; cookie.setPath(QString()); @@ -649,12 +653,21 @@ void tst_QNetworkCookie::parseMultipleCookies_data() QTest::newRow("invalid-06") << "=b" << list; QTest::newRow("invalid-07") << ";path=/" << list; + // these should be accepted by RFC6265 but ignoring the expires field // reason: malformed expiration date string - 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; + QNetworkCookie datelessCookie; + datelessCookie.setName("a"); + datelessCookie.setValue("b"); + list << datelessCookie; + QTest::newRow("expiration-empty") << "a=b;expires=" << list; + QTest::newRow("expiration-invalid-01") << "a=b;expires=foobar" << list; + QTest::newRow("expiration-invalid-02") << "a=b;expires=foobar, abc" << list; + QTest::newRow("expiration-invalid-03") << "a=b; expires=123" << list; // used to ASSERT + datelessCookie.setPath("/"); + list.clear(); + list << datelessCookie; + QTest::newRow("expiration-invalid-04") << "a=b;expires=foobar, dd-mmm-yyyy hh:mm:ss GMT; path=/" << list; + QTest::newRow("expiration-invalid-05") << "a=b;expires=foobar, 32-Caz-1999 24:01:60 GMT; path=/" << list; // cookies obtained from the network: QNetworkCookie cookie; @@ -697,7 +710,6 @@ void tst_QNetworkCookie::parseMultipleCookies_data() cookie.setDomain("!@#$%^&*();:."); // the ';' is actually problematic, because it is a separator list = QList(); QTest::newRow("domain-non-alpha-numeric") << "NonAlphNumDomName=NonAlphNumDomValue; domain=!@#$%^&*()" << list; - QTest::newRow("expiration-3digit1") << "a=b; expires=123" << list; // used to ASSERT } void tst_QNetworkCookie::parseMultipleCookies()