QUrl: decode square brackets in fromLocalFile()
QUrl has an intentional deviation from RFC 3986 when it comes to those characters, matching the behavior of major browsers: we distinguish the forms '[' and ']' from their encoded forms. However, for local files, they are definitely identical, because there's no such thing as a percent-encoded file names. [ChangeLog][QtCore][QUrl] QUrl::fromLocalFile() will now decode the square bracket characters '[' and ']' to their percent-encoded forms. This will be visible in calls to toString(), toEncoded(), or the encoded form of path(). QUrl's comparison operator will consider the old (created from an encoded URL string) and new forms to be different. Pick-to: 6.8 6.9 Fixes: QTBUG-134073 Change-Id: I9eae083007103e34f73cfffd59a618069eba0e19 Reviewed-by: David Faure <david.faure@kdab.com>
This commit is contained in:
parent
31753e722c
commit
5e936b60fc
@ -748,6 +748,32 @@ static const ushort * const pathInIsolation = userNameInIsolation + 5;
|
||||
static const ushort * const queryInIsolation = userNameInIsolation + 6;
|
||||
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[] = {
|
||||
encode(':'), // 0
|
||||
decode('@'), // 1
|
||||
@ -3360,7 +3386,11 @@ QUrl QUrl::fromLocalFile(const QString &localFile)
|
||||
}
|
||||
|
||||
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 = deslashified;
|
||||
|
||||
return url;
|
||||
}
|
||||
|
@ -1367,6 +1367,8 @@ void tst_QUrl::toLocalFile_data()
|
||||
QTest::newRow("FILE:/") << QString::fromLatin1("FILE:/a.txt") << QString::fromLatin1("/a.txt");
|
||||
|
||||
QTest::newRow("path-delimiter") << QString::fromLatin1("file:///Mambo <%235>.mp3") << QString::fromLatin1("/Mambo <#5>.mp3");
|
||||
QTest::newRow("path-brackets-encoded") << u"file:///tmp/%5Btest%5D.txt"_s << u"/tmp/[test].txt"_s;
|
||||
QTest::newRow("path-brackets-decoded") << u"file:///tmp/[test].txt"_s << u"/tmp/[test].txt"_s;
|
||||
QTest::newRow("path-percent") << QString::fromLatin1("file:///a%25.txt") << QString::fromLatin1("/a%.txt");
|
||||
QTest::newRow("path-percent-percent") << QString::fromLatin1("file:///a%25%25.txt") << QString::fromLatin1("/a%%.txt");
|
||||
QTest::newRow("path-percent-a-percent") << QString::fromLatin1("file:///a%25a%25.txt") << QString::fromLatin1("/a%a%.txt");
|
||||
@ -1408,6 +1410,16 @@ void tst_QUrl::toLocalFile()
|
||||
QUrl url(theUrl);
|
||||
QCOMPARE(url.toLocalFile(), theFile);
|
||||
QCOMPARE(url.isLocalFile(), !theFile.isEmpty());
|
||||
|
||||
// set the path to the same (encoded) thing - nothing should change
|
||||
url.setPath(url.path(QUrl::FullyEncoded), QUrl::TolerantMode);
|
||||
QCOMPARE(url.toLocalFile(), theFile);
|
||||
QCOMPARE(url.isLocalFile(), !theFile.isEmpty());
|
||||
|
||||
// QUrl::PrettyDecoded is still URL-encoded and lossless
|
||||
url.setPath(url.path(QUrl::PrettyDecoded), QUrl::TolerantMode);
|
||||
QCOMPARE(url.toLocalFile(), theFile);
|
||||
QCOMPARE(url.isLocalFile(), !theFile.isEmpty());
|
||||
}
|
||||
|
||||
void tst_QUrl::fromLocalFile_data()
|
||||
@ -1421,6 +1433,7 @@ void tst_QUrl::fromLocalFile_data()
|
||||
QTest::newRow("absolute-two-path") << QString::fromLatin1("/a/b.txt") << QString::fromLatin1("file:///a/b.txt") << QString::fromLatin1("/a/b.txt");
|
||||
QTest::newRow("path-delimiters") << QString::fromLatin1("/Mambo <#5>.mp3") << QString::fromLatin1("file:///Mambo <%235>.mp3")
|
||||
<< QString::fromLatin1("/Mambo <#5>.mp3");
|
||||
QTest::newRow("path-brackets") << u"/tmp/[test].txt"_s << u"file:///tmp/%5Btest%5D.txt"_s << u"/tmp/[test].txt"_s;
|
||||
|
||||
// Windows absolute details
|
||||
QTest::newRow("windows-drive") << QString::fromLatin1("c:/a.txt") << QString::fromLatin1("file:///c:/a.txt") << QString::fromLatin1("/c:/a.txt");
|
||||
@ -1483,6 +1496,16 @@ void tst_QUrl::fromLocalFile()
|
||||
|
||||
QCOMPARE(url.toString(QUrl::DecodeReserved), theUrl);
|
||||
QCOMPARE(url.path(), thePath);
|
||||
|
||||
// set the path to the same (encoded) thing - nothing should change
|
||||
url.setPath(url.path(QUrl::FullyEncoded), QUrl::TolerantMode);
|
||||
QCOMPARE(url.toString(QUrl::DecodeReserved), theUrl);
|
||||
QCOMPARE(url.path(), thePath);
|
||||
|
||||
// QUrl::PrettyDecoded is still URL-encoded and lossless
|
||||
url.setPath(url.path(QUrl::PrettyDecoded), QUrl::TolerantMode);
|
||||
QCOMPARE(url.toString(QUrl::DecodeReserved), theUrl);
|
||||
QCOMPARE(url.path(), thePath);
|
||||
}
|
||||
|
||||
void tst_QUrl::fromLocalFileNormalize_data()
|
||||
|
Loading…
x
Reference in New Issue
Block a user