Make sure that the parsing mode reaches QUrlPrivate::setHost
authorThiago Macieira <thiago.macieira@intel.com>
Tue, 31 Jul 2012 13:19:30 +0000 (15:19 +0200)
committerQt by Nokia <qt-info@nokia.com>
Wed, 1 Aug 2012 11:04:21 +0000 (13:04 +0200)
Ensure that the parsing mode is cascaded down from setAuthority and
setUrl so that the hostname parsing does not attempt to decode
percent-encoded hostnames when it shouldn't.

Take the opportunity to also remove the "Boolean Trap" from
QUrlPrivate::setHost.

Change-Id: Ia64754c4a4900182700b7af1382aea8410abc7e9
Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
src/corelib/io/qurl.cpp
src/corelib/io/qurl_p.h
tests/auto/corelib/io/qurl/tst_qurl.cpp

index bc92e94..8cabc06 100644 (file)
@@ -708,7 +708,7 @@ bool QUrlPrivate::setScheme(const QString &value, int len)
     return true;
 }
 
-bool QUrlPrivate::setAuthority(const QString &auth, int from, int end)
+bool QUrlPrivate::setAuthority(const QString &auth, int from, int end, QUrl::ParsingMode mode)
 {
     sectionHasError &= ~Authority;
     sectionIsPresent &= ~Authority;
@@ -768,7 +768,7 @@ bool QUrlPrivate::setAuthority(const QString &auth, int from, int end)
         port = -1;
     }
 
-    return setHost(auth, from, qMin<uint>(end, colonIndex)) && !(sectionHasError & Port);
+    return setHost(auth, from, qMin<uint>(end, colonIndex), mode) && !(sectionHasError & Port);
 }
 
 void QUrlPrivate::setUserInfo(const QString &userInfo, int from, int end)
@@ -955,7 +955,7 @@ static bool parseIp6(QString &host, const QChar *begin, const QChar *end)
     return true;
 }
 
-bool QUrlPrivate::setHost(const QString &value, int from, int iend, bool maybePercentEncoded)
+bool QUrlPrivate::setHost(const QString &value, int from, int iend, QUrl::ParsingMode mode)
 {
     const QChar *begin = value.constData() + from;
     const QChar *end = value.constData() + iend;
@@ -1020,7 +1020,7 @@ bool QUrlPrivate::setHost(const QString &value, int from, int iend, bool maybePe
 
     // check for percent-encoding first
     QString s;
-    if (maybePercentEncoded && qt_urlRecode(s, begin, end, QUrl::DecodeReserved, 0)) {
+    if (mode == QUrl::TolerantMode && qt_urlRecode(s, begin, end, QUrl::DecodeReserved, 0)) {
         // something was decoded
         // anything encoded left?
         if (s.contains(QChar(0x25))) { // '%'
@@ -1030,7 +1030,7 @@ bool QUrlPrivate::setHost(const QString &value, int from, int iend, bool maybePe
         }
 
         // recurse
-        return setHost(s, 0, s.length(), false);
+        return setHost(s, 0, s.length(), QUrl::StrictMode);
     }
 
     s = qt_ACE_do(QString::fromRawData(begin, len), NormalizeAce);
@@ -1111,7 +1111,7 @@ void QUrlPrivate::parse(const QString &url, QUrl::ParsingMode parsingMode)
             }
         }
 
-        setAuthority(url, hierStart + 2, authorityEnd);
+        setAuthority(url, hierStart + 2, authorityEnd, parsingMode);
 
         // even if we failed to set the authority properly, let's try to recover
         pathStart = authorityEnd;
@@ -1649,7 +1649,7 @@ void QUrl::setAuthority(const QString &authority, ParsingMode mode)
         mode = TolerantMode;
     }
 
-    d->setAuthority(data, 0, data.length());
+    d->setAuthority(data, 0, data.length(), mode);
     if (authority.isNull()) {
         // QUrlPrivate::setAuthority cleared almost everything
         // but it leaves the Host bit set
@@ -1893,7 +1893,7 @@ void QUrl::setHost(const QString &host, ParsingMode mode)
         mode = TolerantMode;
     }
 
-    if (d->setHost(data, 0, data.length())) {
+    if (d->setHost(data, 0, data.length(), mode)) {
         if (host.isNull())
             d->sectionIsPresent &= ~QUrlPrivate::Host;
     } else if (!data.startsWith(QLatin1Char('['))) {
@@ -1902,7 +1902,7 @@ void QUrl::setHost(const QString &host, ParsingMode mode)
         ushort oldSupplement = d->errorSupplement;
         data.prepend(QLatin1Char('['));
         data.append(QLatin1Char(']'));
-        if (!d->setHost(data, 0, data.length())) {
+        if (!d->setHost(data, 0, data.length(), mode)) {
             // failed again: choose if this was an IPv6 error or not
             if (!data.contains(QLatin1Char(':'))) {
                 d->errorCode = oldCode;
index 95ccd22..a1efb29 100644 (file)
@@ -123,11 +123,11 @@ public:
 
     // the "end" parameters are like STL iterators: they point to one past the last valid element
     bool setScheme(const QString &value, int len);
-    bool setAuthority(const QString &auth, int from, int end);
+    bool setAuthority(const QString &auth, int from, int end, QUrl::ParsingMode mode);
     void setUserInfo(const QString &userInfo, int from, int end);
     void setUserName(const QString &value, int from, int end);
     void setPassword(const QString &value, int from, int end);
-    bool setHost(const QString &value, int from, int end, bool maybePercentEncoded = true);
+    bool setHost(const QString &value, int from, int end, QUrl::ParsingMode mode);
     void setPath(const QString &value, int from, int end);
     void setQuery(const QString &value, int from, int end);
     void setFragment(const QString &value, int from, int end);
index acde1f8..6b7a802 100644 (file)
@@ -1842,6 +1842,7 @@ void tst_QUrl::strictParser_data()
     QTest::newRow("invalid-password") << "http://user:pass\x7F@ok-hostname" << "Invalid password";
 
     QTest::newRow("invalid-regname") << "http://bad<hostname>" << "Hostname contains invalid characters";
+    QTest::newRow("invalid-regname-2") << "http://b%61d" << "Hostname contains invalid characters";
     QTest::newRow("invalid-ipv6") << "http://[:::]" << "Invalid IPv6 address";
     QTest::newRow("invalid-ipvfuture-1") << "http://[v7]" << "Invalid IPvFuture address";
     QTest::newRow("invalid-ipvfuture-2") << "http://[v7.]" << "Invalid IPvFuture address";
@@ -2007,6 +2008,13 @@ void tst_QUrl::tolerantParser()
         QVERIFY(url.isValid());
         QCOMPARE(QString(url.toEncoded()), QString("http://strange%3Cusername%3E@hostname/"));
     }
+
+    {
+        QUrl url;
+        url.setUrl("http://en%63o%64%65%64.hostname/", QUrl::TolerantMode);
+        QVERIFY(url.isValid());
+        QCOMPARE(url.toString(), QString("http://encoded.hostname/"));
+    }
 }
 
 void tst_QUrl::correctEncodedMistakes_data()
@@ -3045,6 +3053,15 @@ void tst_QUrl::setComponents_data()
     QTest::newRow("invalid-host-1") << QUrl("http://example.com")
                                     << int(Host) << "-not-valid-" << Tolerant << false
                                     << PrettyDecoded << "" << "";
+    QTest::newRow("invalid-host-2") << QUrl("http://example.com")
+                                    << int(Host) << "%31%30.%30.%30.%31" << Strict << false
+                                    << PrettyDecoded << "" << "";
+    QTest::newRow("invalid-authority-1") << QUrl("http://example.com")
+                                         << int(Authority) << "-not-valid-" << Tolerant << false
+                                         << PrettyDecoded << "" << "";
+    QTest::newRow("invalid-authority-2") << QUrl("http://example.com")
+                                         << int(Authority) << "%31%30.%30.%30.%31" << Strict << false
+                                         << PrettyDecoded << "" << "";
     QTest::newRow("invalid-path-1") << QUrl("/relative")
                                     << int(Path) << "c:/" << Strict << false
                                     << PrettyDecoded << "" << "";
@@ -3063,10 +3080,13 @@ void tst_QUrl::setComponents_data()
     QTest::newRow("password-encode") << QUrl("http://example.com")
                                      << int(Password) << "h%61llo:world@" << Decoded << true
                                      << PrettyDecoded << "h%2561llo:world@" << "http://:h%2561llo:world%40@example.com";
-    // '%' characters are not permitted in the hostname, this tests that it fails to set anything
+    // '%' characters are not permitted in the hostname, these test that it fails to set anything
     QTest::newRow("invalid-host-encode") << QUrl("http://example.com")
                                          << int(Host) << "ex%61mple.com" << Decoded << false
                                          << PrettyDecoded << "" << "";
+    QTest::newRow("invalid-authority-encode") << QUrl("http://example.com")
+                                              << int(Authority) << "ex%61mple.com" << Decoded << false
+                                              << PrettyDecoded << "" << "";
     QTest::newRow("path-encode") << QUrl("http://example.com/foo")
                                  << int(Path) << "bar%23" << Decoded << true
                                  << PrettyDecoded << "bar%2523" << "http://example.com/bar%2523";
@@ -3142,6 +3162,11 @@ void tst_QUrl::setComponents()
         QCOMPARE(copy.host(QUrl::ComponentFormattingOptions(encoding)), output);
         break;
 
+    case Authority:
+        copy.setAuthority(newValue, QUrl::ParsingMode(parsingMode));
+        QCOMPARE(copy.authority(QUrl::ComponentFormattingOptions(encoding)), output);
+        break;
+
     case Query:
         copy.setQuery(newValue, QUrl::ParsingMode(parsingMode));
         QCOMPARE(copy.hasQuery(), !newValue.isNull());