diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2013-07-02 13:30:28 -0700 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-07-20 05:06:16 +0200 |
commit | b60cac3602b54dbd3a4b717d143f620da10c1f32 (patch) | |
tree | 2b4221a9a72ba47170d3658655cc9c726afe9bb7 | |
parent | 393865be2a68d61200808c0a6d8e7957139ab9d5 (diff) |
Fix IPvFuture use in QUrl
We have no idea what it might contain, but test it anyway to make sure
it works. Turns out there were a few bugs the unit tests have now
caught.
Change-Id: I0a6c868365feec31c2360b3c341c8ca6944f4352
Reviewed-by: David Faure (KDE) <faure@kde.org>
-rw-r--r-- | src/corelib/io/qurl.cpp | 11 | ||||
-rw-r--r-- | tests/auto/corelib/io/qurl/tst_qurl.cpp | 64 |
2 files changed, 70 insertions, 5 deletions
diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index 17447d9490..be4f177515 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -1087,7 +1087,7 @@ inline void QUrlPrivate::appendHost(QString &appendTo, QUrl::FormattingOptions o // the whole IPvFuture is passed and parsed here, including brackets; // returns null if the parsing was successful, or the QChar of the first failure -static const QChar *parseIpFuture(QString &host, const QChar *begin, const QChar *end) +static const QChar *parseIpFuture(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode) { // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) static const char acceptable[] = @@ -1098,17 +1098,18 @@ static const QChar *parseIpFuture(QString &host, const QChar *begin, const QChar // the brackets and the "v" have been checked if (begin[3].unicode() != '.') return &begin[3]; - if ((begin[2].unicode() >= 'A' && begin[2].unicode() >= 'F') || + if ((begin[2].unicode() >= 'A' && begin[2].unicode() <= 'F') || (begin[2].unicode() >= 'a' && begin[2].unicode() <= 'f') || (begin[2].unicode() >= '0' && begin[2].unicode() <= '9')) { // this is so unlikely that we'll just go down the slow path // decode the whole string, skipping the "[vH." and "]" which we already know to be there host += QString::fromRawData(begin, 4); + begin += 4; --end; QString decoded; - if (qt_urlRecode(decoded, begin, end, QUrl::FullyEncoded, 0)) { + if (mode == QUrl::TolerantMode && qt_urlRecode(decoded, begin, end, QUrl::FullyDecoded, 0)) { begin = decoded.constBegin(); end = decoded.constEnd(); } @@ -1180,7 +1181,7 @@ inline bool QUrlPrivate::setHost(const QString &value, int from, int iend, QUrl: } if (len > 5 && begin[1].unicode() == 'v') { - const QChar *c = parseIpFuture(host, begin, end); + const QChar *c = parseIpFuture(host, begin, end, mode); if (c) setError(InvalidIPvFutureError, value, c - value.constData()); return !c; @@ -3653,7 +3654,7 @@ static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &err case QUrlPrivate::InvalidIPv6AddressError: return QStringLiteral("Invalid IPv6 address"); case QUrlPrivate::InvalidIPvFutureError: - return QStringLiteral("Invalid IPvFuture address"); + return QStringLiteral("Invalid IPvFuture address (character '%1' not permitted)").arg(c); case QUrlPrivate::HostMissingEndBracket: return QStringLiteral("Expected ']' to match '[' in hostname"); diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp index cda187b037..ad4c0c1224 100644 --- a/tests/auto/corelib/io/qurl/tst_qurl.cpp +++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp @@ -111,6 +111,8 @@ private slots: void percentEncoding(); void swap(); void symmetry(); + void ipvfuture_data(); + void ipvfuture(); void ipv6_data(); void ipv6(); void ipv6_2_data(); @@ -1616,6 +1618,66 @@ void tst_QUrl::symmetry() } } +void tst_QUrl::ipvfuture_data() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<bool>("isValid"); + QTest::addColumn<QString>("output"); + + // No one uses IPvFuture yet, so we have no clue what it might contain + // We're just testing that it can hold what the RFC says it should hold: + // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) + QTest::newRow("missing-version-dot") << "x://[v]" << false; + QTest::newRow("missing-version") << "x://[v.]" << false; + QTest::newRow("missing-version-2") << "x://[v.1234]" << false; + QTest::newRow("missing-dot") << "x://[v7]" << false; + QTest::newRow("missing-dot-2") << "x://[v71234]" << false; + QTest::newRow("missing-data") << "x://[v7.]" << false; + QTest::newRow("non-hex-version") << "x://[vz.1234]" << false; + + QTest::newRow("digit-ver") << "x://[v7.1]" << true << "x://[v7.1]"; + QTest::newRow("lowercase-hex-ver") << "x://[va.1]" << true << "x://[va.1]"; + QTest::newRow("lowercase-hex-ver") << "x://[vA.1]" << true << "x://[vA.1]"; + + QTest::newRow("data-digits") << "x://[v7.1234]" << true << "x://[v7.1234]"; + QTest::newRow("data-unreserved") << "x://[v7.hello~-WORLD_.com]" << true << "x://[v7.hello~-WORLD_.com]"; + QTest::newRow("data-sub-delims-colon") << "x://[v7.!$&'()*+,;=:]" << true << "x://[v7.!$&'()*+,;=:]"; + + // we're using the tolerant parser + QTest::newRow("data-encoded-digits") << "x://[v7.%31%32%33%34]" << true << "x://[v7.1234]"; + QTest::newRow("data-encoded-unreserved") << "x://[v7.%7E%2D%54%5f%2E]" << true << "x://[v7.~-T_.]"; + QTest::newRow("data-encoded-sub-delims-colon") << "x://[v7.%21%24%26%27%28%29%2A%2B%2C%3B%3D%3A]" << true << "x://[v7.!$&'()*+,;=:]"; + + // should we test "[%76%37%2ex]" -> "[v7.x]" ? + + QTest::newRow("data-invalid-space") << "x://[v7.%20]" << false; + QTest::newRow("data-invalid-control") << "x://[v7.\x7f]" << false; + QTest::newRow("data-invalid-other-1") << "x://[v7.{1234}]" << false; + QTest::newRow("data-invalid-other-2") << "x://[v7.<hello>]" << false; + QTest::newRow("data-invalid-unicode") << "x://[v7.æøå]" << false; + QTest::newRow("data-invalid-percent") << "x://[v7.%]" << false; + QTest::newRow("data-invalid-percent-percent") << "x://[v7.%25]" << false; +} + +void tst_QUrl::ipvfuture() +{ + QFETCH(QString, input); + QFETCH(bool, isValid); + + QUrl url(input); + if (isValid) { + QVERIFY2(url.isValid(), qPrintable(url.errorString())); + + QFETCH(QString, output); + QCOMPARE(url.toString(), output); + + QUrl url2(output); + QCOMPARE(url2, url); + } else { + QVERIFY(!url.isValid()); + } +} + void tst_QUrl::ipv6_data() { @@ -1953,7 +2015,9 @@ void tst_QUrl::strictParser_data() QTest::newRow("invalid-ipvfuture-1") << "http://[v7]" << "Invalid IPvFuture address"; QTest::newRow("invalid-ipvfuture-2") << "http://[v7.]" << "Invalid IPvFuture address"; QTest::newRow("invalid-ipvfuture-3") << "http://[v789]" << "Invalid IPvFuture address"; + QTest::newRow("invalid-ipvfuture-char1") << "http://[v7.^]" << "Invalid IPvFuture address"; QTest::newRow("invalid-encoded-ipv6") << "x://[%3a%3a%31]" << "Invalid IPv6 address"; + QTest::newRow("invalid-encoded-ipvfuture") << "x://[v7.%7E%2D%54%5f%2E]" << "Invalid IPvFuture address"; QTest::newRow("unbalanced-brackets") << "http://[ff02::1" << "Expected ']' to match '[' in hostname"; // invalid hostnames happen in TolerantMode too |