QUrl: expand the square brackets encoding to decoded setPath() calls
Amends (reverts) commit 5e936b60fc921e21b8153a83113886a1de333b57, which forced the encoding of the square brackets ("[]") into their percent- encoded forms only in QUrl::fromLocalFile(). This commit expands the functionality to all uses of decoded paths by applying the change directly to recodeFromUser(). [ChangeLog][QtCore][QUrl] Square brackets ("[]") are now transformed to their percent-encoded forms ("%5B" and "%5D") when present as inputs to setPath(), setQuery(), and setFragment() if the parsing mode is QUrl::DecodedMode (the default). Pick-to: 6.8 Fixes: QTBUG-135433 Task-number: QTBUG-134073 See: https://bugs.kde.org/show_bug.cgi?id=502280 Change-Id: Id2b41559af08b5f228e4fffdb9c6f23120f856b5 Reviewed-by: David Faure <david.faure@kdab.com> (cherry picked from commit f3da9d3c858e8dc28a5dc91047b592ed5becbd62) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
bbe0b18b38
commit
01ff6e19f7
@ -748,32 +748,6 @@ static const ushort * const pathInIsolation = userNameInIsolation + 5;
|
|||||||
static const ushort * const queryInIsolation = userNameInIsolation + 6;
|
static const ushort * const queryInIsolation = userNameInIsolation + 6;
|
||||||
static const ushort * const fragmentInIsolation = userNameInIsolation + 7;
|
static const ushort * const fragmentInIsolation = userNameInIsolation + 7;
|
||||||
|
|
||||||
static const ushort localPathFromUser[] = {
|
|
||||||
// we force-decode some of the gen-delims, because
|
|
||||||
// pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
|
||||||
// the gen-delim lines are leave() in qt_urlRecode, so we don't need to
|
|
||||||
// repeat them if we want to keep them decoded
|
|
||||||
// decode(':'), // allowed
|
|
||||||
// decode('@'), // allowed
|
|
||||||
encode(']'),
|
|
||||||
encode('['),
|
|
||||||
// decode('/'), // special and allowed
|
|
||||||
// decode('?'), // handled by path() and others
|
|
||||||
// decode('#'), // ditto
|
|
||||||
|
|
||||||
// the rest is like pathInIsolation above
|
|
||||||
decode('"'),
|
|
||||||
decode('<'),
|
|
||||||
decode('>'),
|
|
||||||
decode('^'),
|
|
||||||
decode('\\'),
|
|
||||||
decode('|'),
|
|
||||||
decode('{'),
|
|
||||||
decode('}'),
|
|
||||||
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
static const ushort userNameInUserInfo[] = {
|
static const ushort userNameInUserInfo[] = {
|
||||||
encode(':'), // 0
|
encode(':'), // 0
|
||||||
decode('@'), // 1
|
decode('@'), // 1
|
||||||
@ -833,9 +807,11 @@ static const ushort * const pathInUrl = userNameInUrl + 5;
|
|||||||
static const ushort * const queryInUrl = userNameInUrl + 6;
|
static const ushort * const queryInUrl = userNameInUrl + 6;
|
||||||
static const ushort * const fragmentInUrl = userNameInUrl + 6;
|
static const ushort * const fragmentInUrl = userNameInUrl + 6;
|
||||||
|
|
||||||
static inline void parseDecodedComponent(QString &data)
|
static inline void parseDecodedComponent(QString &data, QUrlPrivate::Section section)
|
||||||
{
|
{
|
||||||
data.replace(u'%', "%25"_L1);
|
data.replace(u'%', "%25"_L1);
|
||||||
|
if (section != QUrlPrivate::Host)
|
||||||
|
data.replace(u'[', "%5B"_L1).replace(u']', "%5D"_L1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline QString
|
static inline QString
|
||||||
@ -2135,7 +2111,7 @@ void QUrl::setUserName(const QString &userName, ParsingMode mode)
|
|||||||
|
|
||||||
QString data = userName;
|
QString data = userName;
|
||||||
if (mode == DecodedMode) {
|
if (mode == DecodedMode) {
|
||||||
parseDecodedComponent(data);
|
parseDecodedComponent(data, QUrlPrivate::UserName);
|
||||||
mode = TolerantMode;
|
mode = TolerantMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2198,7 +2174,7 @@ void QUrl::setPassword(const QString &password, ParsingMode mode)
|
|||||||
|
|
||||||
QString data = password;
|
QString data = password;
|
||||||
if (mode == DecodedMode) {
|
if (mode == DecodedMode) {
|
||||||
parseDecodedComponent(data);
|
parseDecodedComponent(data, QUrlPrivate::Password);
|
||||||
mode = TolerantMode;
|
mode = TolerantMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2260,7 +2236,7 @@ void QUrl::setHost(const QString &host, ParsingMode mode)
|
|||||||
|
|
||||||
QString data = host;
|
QString data = host;
|
||||||
if (mode == DecodedMode) {
|
if (mode == DecodedMode) {
|
||||||
parseDecodedComponent(data);
|
parseDecodedComponent(data, QUrlPrivate::Host);
|
||||||
mode = TolerantMode;
|
mode = TolerantMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2385,7 +2361,7 @@ void QUrl::setPath(const QString &path, ParsingMode mode)
|
|||||||
|
|
||||||
QString data = path;
|
QString data = path;
|
||||||
if (mode == DecodedMode) {
|
if (mode == DecodedMode) {
|
||||||
parseDecodedComponent(data);
|
parseDecodedComponent(data, QUrlPrivate::Path);
|
||||||
mode = TolerantMode;
|
mode = TolerantMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2521,7 +2497,7 @@ void QUrl::setQuery(const QString &query, ParsingMode mode)
|
|||||||
|
|
||||||
QString data = query;
|
QString data = query;
|
||||||
if (mode == DecodedMode) {
|
if (mode == DecodedMode) {
|
||||||
parseDecodedComponent(data);
|
parseDecodedComponent(data, QUrlPrivate::Query);
|
||||||
mode = TolerantMode;
|
mode = TolerantMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2619,7 +2595,7 @@ void QUrl::setFragment(const QString &fragment, ParsingMode mode)
|
|||||||
|
|
||||||
QString data = fragment;
|
QString data = fragment;
|
||||||
if (mode == DecodedMode) {
|
if (mode == DecodedMode) {
|
||||||
parseDecodedComponent(data);
|
parseDecodedComponent(data, QUrlPrivate::Fragment);
|
||||||
mode = TolerantMode;
|
mode = TolerantMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3386,11 +3362,7 @@ QUrl QUrl::fromLocalFile(const QString &localFile)
|
|||||||
}
|
}
|
||||||
|
|
||||||
url.setScheme(scheme);
|
url.setScheme(scheme);
|
||||||
|
url.setPath(deslashified, DecodedMode);
|
||||||
// not directly using setPath here, as we do a few more transforms
|
|
||||||
parseDecodedComponent(deslashified);
|
|
||||||
if (!qt_urlRecode(url.d->path, deslashified, {}, localPathFromUser))
|
|
||||||
url.d->path = std::move(deslashified);
|
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
@ -1422,6 +1422,11 @@ void tst_QUrl::toLocalFile()
|
|||||||
url.setPath(url.path(QUrl::PrettyDecoded), QUrl::TolerantMode);
|
url.setPath(url.path(QUrl::PrettyDecoded), QUrl::TolerantMode);
|
||||||
QCOMPARE(url.toLocalFile(), theFile);
|
QCOMPARE(url.toLocalFile(), theFile);
|
||||||
QCOMPARE(url.isLocalFile(), !theFile.isEmpty());
|
QCOMPARE(url.isLocalFile(), !theFile.isEmpty());
|
||||||
|
|
||||||
|
// local file paths can be fully decoded without loss
|
||||||
|
url.setPath(url.path());
|
||||||
|
QCOMPARE(url.toLocalFile(), theFile);
|
||||||
|
QCOMPARE(url.isLocalFile(), !theFile.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QUrl::fromLocalFile_data()
|
void tst_QUrl::fromLocalFile_data()
|
||||||
@ -1508,6 +1513,11 @@ void tst_QUrl::fromLocalFile()
|
|||||||
url.setPath(url.path(QUrl::PrettyDecoded), QUrl::TolerantMode);
|
url.setPath(url.path(QUrl::PrettyDecoded), QUrl::TolerantMode);
|
||||||
QCOMPARE(url.toString(QUrl::DecodeReserved), theUrl);
|
QCOMPARE(url.toString(QUrl::DecodeReserved), theUrl);
|
||||||
QCOMPARE(url.path(), thePath);
|
QCOMPARE(url.path(), thePath);
|
||||||
|
|
||||||
|
// local file paths can be fully decoded without loss
|
||||||
|
url.setPath(url.path());
|
||||||
|
QCOMPARE(url.toString(QUrl::DecodeReserved), theUrl);
|
||||||
|
QCOMPARE(url.path(), thePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QUrl::fromLocalFileNormalize_data()
|
void tst_QUrl::fromLocalFileNormalize_data()
|
||||||
@ -4150,24 +4160,25 @@ void tst_QUrl::setComponents_data()
|
|||||||
<< int(Scheme) << "http%61" << Decoded << false
|
<< int(Scheme) << "http%61" << Decoded << false
|
||||||
<< PrettyDecoded << "" << "";
|
<< PrettyDecoded << "" << "";
|
||||||
QTest::newRow("username-encode") << QUrl("http://example.com")
|
QTest::newRow("username-encode") << QUrl("http://example.com")
|
||||||
<< int(UserName) << "h%61llo:world" << Decoded << true
|
<< int(UserName) << "h%61llo[:]world" << Decoded << true
|
||||||
<< PrettyDecoded << "h%2561llo:world" << "http://h%2561llo%3Aworld@example.com";
|
<< PrettyDecoded << "h%2561llo[:]world" << "http://h%2561llo%5B%3A%5Dworld@example.com";
|
||||||
QTest::newRow("password-encode") << QUrl("http://example.com")
|
QTest::newRow("password-encode") << QUrl("http://example.com")
|
||||||
<< int(Password) << "h%61llo:world@" << Decoded << true
|
<< int(Password) << "h%61llo[:]world@" << Decoded << true
|
||||||
<< PrettyDecoded << "h%2561llo:world@" << "http://:h%2561llo:world%40@example.com";
|
<< PrettyDecoded << "h%2561llo[:]world@" << "http://:h%2561llo%5B:%5Dworld%40@example.com";
|
||||||
// '%' characters are not permitted in the hostname, these test 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")
|
QTest::newRow("invalid-host-encode") << QUrl("http://example.com")
|
||||||
<< int(Host) << "ex%61mple.com" << Decoded << false
|
<< int(Host) << "ex%61mple.com" << Decoded << false
|
||||||
<< PrettyDecoded << QString() << QString();
|
<< PrettyDecoded << QString() << QString();
|
||||||
|
// square brackets are force-encoded from decoded forms in the path, query, and fragment
|
||||||
QTest::newRow("path-encode") << QUrl("http://example.com/foo")
|
QTest::newRow("path-encode") << QUrl("http://example.com/foo")
|
||||||
<< int(Path) << "/bar%23" << Decoded << true
|
<< int(Path) << "/ba[r]%23" << Decoded << true
|
||||||
<< PrettyDecoded << "/bar%2523" << "http://example.com/bar%2523";
|
<< PrettyDecoded << "/ba%5Br%5D%2523" << "http://example.com/ba%5Br%5D%2523";
|
||||||
QTest::newRow("query-encode") << QUrl("http://example.com/foo?q")
|
QTest::newRow("query-encode") << QUrl("http://example.com/foo?q")
|
||||||
<< int(Query) << "bar%23" << Decoded << true
|
<< int(Query) << "ba[r]%23" << Decoded << true
|
||||||
<< PrettyDecoded << "bar%2523" << "http://example.com/foo?bar%2523";
|
<< PrettyDecoded << "ba%5Br%5D%2523" << "http://example.com/foo?ba%5Br%5D%2523";
|
||||||
QTest::newRow("fragment-encode") << QUrl("http://example.com/foo#z")
|
QTest::newRow("fragment-encode") << QUrl("http://example.com/foo#z")
|
||||||
<< int(Fragment) << "bar%23" << Decoded << true
|
<< int(Fragment) << "ba[r]%23" << Decoded << true
|
||||||
<< PrettyDecoded << "bar%2523" << "http://example.com/foo#bar%2523";
|
<< PrettyDecoded << "ba%5Br%5D%2523" << "http://example.com/foo#ba%5Br%5D%2523";
|
||||||
// force decoding
|
// force decoding
|
||||||
QTest::newRow("username-decode") << QUrl("http://example.com")
|
QTest::newRow("username-decode") << QUrl("http://example.com")
|
||||||
<< int(UserName) << "hello%3Aworld%25" << Tolerant << true
|
<< int(UserName) << "hello%3Aworld%25" << Tolerant << true
|
||||||
@ -4176,8 +4187,8 @@ void tst_QUrl::setComponents_data()
|
|||||||
<< int(Password) << "}}>b9o%25kR(" << Tolerant << true
|
<< int(Password) << "}}>b9o%25kR(" << Tolerant << true
|
||||||
<< FullyDecoded << "}}>b9o%kR(" << "http://:%7D%7D%3Eb9o%25kR(@example.com";
|
<< FullyDecoded << "}}>b9o%kR(" << "http://:%7D%7D%3Eb9o%25kR(@example.com";
|
||||||
QTest::newRow("path-decode") << QUrl("http://example.com/")
|
QTest::newRow("path-decode") << QUrl("http://example.com/")
|
||||||
<< int(Path) << "/bar%25foo" << Tolerant << true
|
<< int(Path) << "/bar%25[foo]" << Tolerant << true
|
||||||
<< FullyDecoded << "/bar%foo" << "http://example.com/bar%25foo";
|
<< FullyDecoded << "/bar%[foo]" << "http://example.com/bar%25[foo]";
|
||||||
QTest::newRow("query-decode") << QUrl("http://example.com/foo?qq")
|
QTest::newRow("query-decode") << QUrl("http://example.com/foo?qq")
|
||||||
<< int(Query) << "bar%25foo" << Tolerant << true
|
<< int(Query) << "bar%25foo" << Tolerant << true
|
||||||
<< FullyDecoded << "bar%foo" << "http://example.com/foo?bar%25foo";
|
<< FullyDecoded << "bar%foo" << "http://example.com/foo?bar%25foo";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user