From 2e492dc6a6cf9e73a04f65e133ea4e97324a68da Mon Sep 17 00:00:00 2001 From: Robbert Proost Date: Thu, 18 Jan 2018 09:52:49 +0100 Subject: [PATCH] QUrl: Support IPv6 addresses with zone id Task-number: QTBUG-25550 Change-Id: I37ec02b655abe2779aa11945e20550ce00e43723 --- src/corelib/io/qurl.cpp | 63 ++++++++++++++++--------- tests/auto/corelib/io/qurl/tst_qurl.cpp | 52 ++++++++++++++++++++ 2 files changed, 92 insertions(+), 23 deletions(-) diff --git x/qtbase/src/corelib/io/qurl.cpp y/qtbase/src/corelib/io/qurl.cpp index 4587b9fcd6..e2a66c8459 100644 --- x/qtbase/src/corelib/io/qurl.cpp +++ y/qtbase/src/corelib/io/qurl.cpp @@ -1203,16 +1203,18 @@ inline void QUrlPrivate::setQuery(const QString &value, int from, int iend) inline void QUrlPrivate::appendHost(QString &appendTo, QUrl::FormattingOptions options) const { - // EncodeUnicode is the only flag that matters - if ((options & QUrl::FullyDecoded) == QUrl::FullyDecoded) - options = 0; - else - options &= QUrl::EncodeUnicode; if (host.isEmpty()) return; if (host.at(0).unicode() == '[') { - // IPv6Address and IPvFuture address never require any transformation - appendTo += host; + // IPv6 addresses might contain a zone-id which needs to be recoded + QString hostInCorrectFormat; + if (options != 0) + qt_urlRecode(hostInCorrectFormat, host.constBegin(), host.constEnd(), options, 0); + + if (hostInCorrectFormat.isEmpty()) + hostInCorrectFormat = host; + + appendTo += hostInCorrectFormat; } else { // this is either an IPv4Address or a reg-name // if it is a reg-name, it is already stored in Unicode form @@ -1278,31 +1280,46 @@ static const QChar *parseIpFuture(QString &host, const QChar *begin, const QChar // ONLY the IPv6 address is parsed here, WITHOUT the brackets static const QChar *parseIp6(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode) { - QIPAddressUtils::IPv6Address address; - const QChar *ret = QIPAddressUtils::parseIp6(address, begin, end); - if (ret) { - // this struct is kept in automatic storage because it's only 4 bytes + QString decoded; + if (mode == QUrl::TolerantMode) { const ushort decodeColon[] = { decode(':'), 0 }; + if (qt_urlRecode(decoded, begin, end, QUrl::ComponentFormattingOption::PrettyDecoded, decodeColon) == 0) { + decoded = QString(begin, end-begin); + } + } + else { + decoded = QString(begin, end-begin); + } - // IPv6 failed parsing, check if it was a percent-encoded character in - // the middle and try again - QString decoded; - if (mode == QUrl::TolerantMode && qt_urlRecode(decoded, begin, end, 0, decodeColon)) { - // recurse - // if the parsing fails again, the qt_urlRecode above will return 0 - ret = parseIp6(host, decoded.constBegin(), decoded.constEnd(), mode); + const QLatin1String zoneIdIdentifier("%25"); + QIPAddressUtils::IPv6Address address; + QString zoneId; + + const QChar *endBeforeZoneId = decoded.constEnd(); + + int zoneIdPosition = decoded.indexOf(zoneIdIdentifier); + if ((zoneIdPosition != -1) && (decoded.lastIndexOf(zoneIdIdentifier) == zoneIdPosition)) { + zoneId = decoded.mid(zoneIdPosition + zoneIdIdentifier.size()); + endBeforeZoneId = decoded.constBegin() + zoneIdPosition; - // we can't return ret, otherwise it would be dangling - return ret ? end : 0; + if (zoneId.isEmpty() == true) { + return end; } + } - // no transformation, nothing to re-parse - return ret; + const QChar *ret = QIPAddressUtils::parseIp6(address, decoded.constBegin(), endBeforeZoneId); + if (ret) { + return begin + (ret - decoded.constBegin()); } - host.reserve(host.size() + (end - begin)); + host.reserve(host.size() + (decoded.constEnd() - decoded.constBegin())); host += QLatin1Char('['); QIPAddressUtils::toString(host, address); + + if (zoneId.isEmpty() == false) { + host += zoneIdIdentifier; + host += zoneId; + } host += QLatin1Char(']'); return 0; } -- 2.18.0