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:
parent
afe66eb9b4
commit
393865be2a
@ -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)); // '%'
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user