QUrl: do not decode "#" in fragments

For some time, we've assumed that the URL specification had a mistake in
that it didn't allow the "#" character to appear decoded in the
fragment. We've gotten away with it so far.

However, turns out that the CoreFoundation NSURL class doesn't like it.
So we have to be stricter.

[ChangeLog][Important Behavior Changes][QUrl and QUrlQuery] QUrl no
longer decodes %23 found in the fragment to "#" in the output of
toString(QUrl::FullyEncoded) or toEncoded()

Task-number: QTBUG-31945
Change-Id: If5e0fb37bae84710986c9ca89bd69ec98437cd63
Reviewed-by: David Faure (KDE) <faure@kde.org>
bb10
Thiago Macieira 2013-07-19 12:03:25 -07:00 committed by The Qt Project
parent 7b964c77fa
commit c615dcc441
3 changed files with 13 additions and 8 deletions

View File

@ -632,7 +632,6 @@ inline void QUrlPrivate::setError(ErrorCode errorCode, const QString &source, in
// here are the gen-delims we can unambiguously transform when the field is
// taken in isolation:
// - fragment: none, since it's the last
// Deviation: the spec says "#" <-> %23 is unambiguous, but we treat it as if were
// - query: "#" is unambiguous
// - path: "#" and "?" are unambiguous
// - host: completely special but never ambiguous, see setHost() below.
@ -747,7 +746,7 @@ static const ushort userNameInUrl[] = {
static const ushort * const passwordInUrl = userNameInUrl + 1;
static const ushort * const pathInUrl = userNameInUrl + 5;
static const ushort * const queryInUrl = userNameInUrl + 6;
static const ushort * const fragmentInUrl = 0;
static const ushort * const fragmentInUrl = userNameInUrl + 6;
static inline void parseDecodedComponent(QString &data)
{
@ -879,7 +878,8 @@ inline void QUrlPrivate::appendPath(QString &appendTo, QUrl::FormattingOptions o
inline void QUrlPrivate::appendFragment(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
{
appendToUser(appendTo, fragment, options,
appendingTo == FullUrl || options & QUrl::EncodeDelimiters ? fragmentInUrl : fragmentInIsolation);
options & QUrl::EncodeDelimiters ? fragmentInUrl :
appendingTo == FullUrl ? 0 : fragmentInIsolation);
}
inline void QUrlPrivate::appendQuery(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const

View File

@ -2506,7 +2506,7 @@ void tst_QUrl::setEncodedFragment_data()
QTest::newRow("basic test") << BA("http://www.kde.org") << BA("abc") << BA("http://www.kde.org#abc");
QTest::newRow("initial url has fragment") << BA("http://www.kde.org#old") << BA("new") << BA("http://www.kde.org#new");
QTest::newRow("encoded fragment") << BA("http://www.kde.org") << BA("a%20c") << BA("http://www.kde.org#a%20c");
QTest::newRow("with #") << BA("http://www.kde.org") << BA("a#b") << BA("http://www.kde.org#a#b");
QTest::newRow("with #") << BA("http://www.kde.org") << BA("a#b") << BA("http://www.kde.org#a%23b"); // toString uses "a#b"
QTest::newRow("unicode") << BA("http://www.kde.org") << BA("\xc3\xa9") << BA("http://www.kde.org#%C3%A9");
QTest::newRow("binary") << BA("http://www.kde.org") << BA("\x00\xc0\x80", 3) << BA("http://www.kde.org#%00%C0%80");
}
@ -3151,12 +3151,12 @@ void tst_QUrl::componentEncodings_data()
<< "x://%5B%3A%2F%3F%23%40%5D:%5B%2F%3F%23%40%5D@host/%2F%3F%23?%23";
// 2) test that the other delimiters remain decoded
QTest::newRow("decoded-gendelims-unchanging") << QUrl("x://::@host/:@/[]?:/?@[]?##:/?@[]")
QTest::newRow("decoded-gendelims-unchanging") << QUrl("x://::@host/:@/[]?:/?@[]?#:/?@[]")
<< int(QUrl::FullyEncoded)
<< "" << ":" << "::"
<< "host" << "::@host"
<< "/:@/[]" << ":/?@[]?" << "#:/?@[]"
<< "x://::@host/:@/[]?:/?@[]?##:/?@[]";
<< "/:@/[]" << ":/?@[]?" << ":/?@[]"
<< "x://::@host/:@/[]?:/?@[]?#:/?@[]";
// 3) and test that the same encoded sequences remain encoded
QTest::newRow("encoded-gendelims-unchanging") << QUrl("x://:%3A@host/%3A%40%5B%5D?%3A%2F%3F%40%5B%5D#%23%3A%2F%3F%40%5B%5D")

View File

@ -104,6 +104,11 @@ void tst_QDesktopServices::openUrl_data()
<< QUrl("http://google.com/search?q=/profile/5")
<< "This should search \"/profile/5\" on Google.";
// see QTBUG-31945
QTest::newRow("two-fragments")
<< QUrl("http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006926-CH3-SW81")
<< "This should open \"Implementing a Container View Controller\" in the UIViewController docs";
QTest::newRow("mail")
<< QUrl("mailto:development@qt-project.org")
<< "This should open an email composer with the destination set to development@qt-project.org";
@ -118,7 +123,7 @@ void tst_QDesktopServices::openUrl()
QFETCH(QUrl, data);
QFETCH(QString, message);
qWarning("\n\nOpening \"%s\": %s", qPrintable(data.toString()), qPrintable(message));
QDesktopServices::openUrl(data);
QVERIFY(QDesktopServices::openUrl(data));
}
QTEST_MAIN(tst_QDesktopServices)