Fix QUrl parsing of IPv6 hosts with encoded colons

Registered names and IP addresses can only contain unreserved
characters (letters, digits, dots, hyphens, underscores) and the
colon, which is a gen-delim. For registered names and IPv4 addresses,
we can simply use the default config -- if anything that remains
percent-encoded, it means it's not a valid hostname anyway.

For IPv6, we just need to decode the colon.

Change-Id: If8083d47f6e5375f760e7a6c59631c89e4da8378
Reviewed-by: David Faure (KDE) <faure@kde.org>
This commit is contained in:
Thiago Macieira 2013-07-01 16:58:21 -07:00 committed by The Qt Project
parent afe66eb9b4
commit 393865be2a
2 changed files with 12 additions and 5 deletions

View File

@ -1132,21 +1132,24 @@ static const QChar *parseIpFuture(QString &host, const QChar *begin, const QChar
}
// ONLY the IPv6 address is parsed here, WITHOUT the brackets
static bool parseIp6(QString &host, const QChar *begin, const QChar *end)
static bool parseIp6(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode)
{
QIPAddressUtils::IPv6Address address;
if (!QIPAddressUtils::parseIp6(address, begin, end)) {
// this struct is kept in automatic storage because it's only 4 bytes
const ushort decodeColon[] = { decode(':'), 0 };
// IPv6 failed parsing, check if it was a percent-encoded character in
// the middle and try again
QString decoded;
if (!qt_urlRecode(decoded, begin, end, QUrl::FullyEncoded, 0)) {
if (mode != QUrl::TolerantMode || !qt_urlRecode(decoded, begin, end, 0, decodeColon)) {
// no transformation, nothing to re-parse
return false;
}
// recurse
// if the parsing fails again, the qt_urlRecode above will return 0
return parseIp6(host, decoded.constBegin(), decoded.constEnd());
return parseIp6(host, decoded.constBegin(), decoded.constEnd(), mode);
}
host.reserve(host.size() + (end - begin));
@ -1183,7 +1186,7 @@ inline bool QUrlPrivate::setHost(const QString &value, int from, int iend, QUrl:
return !c;
}
if (parseIp6(host, begin + 1, end - 1))
if (parseIp6(host, begin + 1, end - 1, mode))
return true;
setError(begin[1].unicode() == 'v' ? InvalidIPvFutureError : InvalidIPv6AddressError,
@ -1214,7 +1217,7 @@ inline bool QUrlPrivate::setHost(const QString &value, int from, int iend, QUrl:
// check for percent-encoding first
QString s;
if (mode == QUrl::TolerantMode && qt_urlRecode(s, begin, end, QUrl::DecodeReserved, 0)) {
if (mode == QUrl::TolerantMode && qt_urlRecode(s, begin, end, 0, 0)) {
// something was decoded
// anything encoded left?
int pos = s.indexOf(QChar(0x25)); // '%'

View File

@ -1656,6 +1656,9 @@ void tst_QUrl::ipv6_data()
QTest::newRow("case :,") << QString::fromLatin1("//[:,]") << false << "";
QTest::newRow("case ::bla") << QString::fromLatin1("//[::bla]") << false << "";
QTest::newRow("case v4-mapped") << "//[0:0:0:0:0:ffff:7f00:1]" << true << "//[::ffff:127.0.0.1]";
QTest::newRow("encoded-digit") << "//[::%31]" << true << "//[::1]";
QTest::newRow("encoded-colon") << "//[%3A%3A]" << true << "//[::]";
}
void tst_QUrl::ipv6()
@ -1950,6 +1953,7 @@ 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-encoded-ipv6") << "x://[%3a%3a%31]" << "Invalid IPv6 address";
QTest::newRow("unbalanced-brackets") << "http://[ff02::1" << "Expected ']' to match '[' in hostname";
// invalid hostnames happen in TolerantMode too