QUrl::resolved: rewrite to fix some corner cases for relative URLs
Both issues reported in QTBUG-120396 came from the same dubious piece of code, which predates the public Qt history if (path->size() >= 2 && in[0].unicode() == '.' && in[1].unicode() == '/') in += 2; else if (path->size() >= 3 && in[0].unicode() == '.' && in[1].unicode() == '.' && in[2].unicode() == '/') in += 3; It makes no sense to check path->size() inside the loop, as the in pointer will have advanced past the beginning and the remaining size of the input will not be path->size(). It additionally had theoretical UB in expressions like in <= end - 4 for paths that were less than 4 characters long (it cannot happen with current QString because of the QArrayData header before the payload). So this commit rewrites the function to fix those issues and some others found during the unit-testing. It gives the function a major simplification. Fixes: QTBUG-120396 Pick-to: 6.7 6.5 Change-Id: I46feca3a447244a8ba19fffd17e012c27e410056 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Ahmad Samir <a.samirh78@gmail.com> (cherry picked from commit 4b1547adc9b195e6acc90471fc48dec7ee0c429d) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
65144dba05
commit
a1610c6c68
@ -1529,6 +1529,12 @@ inline QString QUrlPrivate::mergePaths(const QString &relativePath) const
|
||||
|
||||
Removes unnecessary ../ and ./ from the path. Used for normalizing
|
||||
the URL.
|
||||
|
||||
This code has a Qt-specific extension to handle empty path segments (a.k.a.
|
||||
multiple slashes like "a//b"). We try to keep them wherever possible
|
||||
because with some protocols they are meaningful, but we still consider them
|
||||
to be a single directory transition for "." or ".." (e.g., "a/b//c" +
|
||||
"../" is "a/"). See tst_QUrl::resolved() for the expected behavior.
|
||||
*/
|
||||
static void removeDotsFromPath(QString *path)
|
||||
{
|
||||
@ -1539,71 +1545,87 @@ static void removeDotsFromPath(QString *path)
|
||||
const QChar *in = out;
|
||||
const QChar *end = out + path->size();
|
||||
|
||||
// If the input buffer consists only of
|
||||
// "." or "..", then remove that from the input
|
||||
// buffer;
|
||||
if (path->size() == 1 && in[0].unicode() == '.')
|
||||
++in;
|
||||
else if (path->size() == 2 && in[0].unicode() == '.' && in[1].unicode() == '.')
|
||||
in += 2;
|
||||
// While the input buffer is not empty, loop:
|
||||
// We implement a modified algorithm compared to RFC 3986, for efficiency.
|
||||
while (in < end) {
|
||||
|
||||
// otherwise, if the input buffer begins with a prefix of "../" or "./",
|
||||
// then remove that prefix from the input buffer;
|
||||
if (path->size() >= 2 && in[0].unicode() == '.' && in[1].unicode() == '/')
|
||||
in += 2;
|
||||
else if (path->size() >= 3 && in[0].unicode() == '.'
|
||||
&& in[1].unicode() == '.' && in[2].unicode() == '/')
|
||||
in += 3;
|
||||
|
||||
// otherwise, if the input buffer begins with a prefix of
|
||||
// "/./" or "/.", where "." is a complete path segment,
|
||||
// then replace that prefix with "/" in the input buffer;
|
||||
if (in <= end - 3 && in[0].unicode() == '/' && in[1].unicode() == '.'
|
||||
&& in[2].unicode() == '/') {
|
||||
in += 2;
|
||||
continue;
|
||||
} else if (in == end - 2 && in[0].unicode() == '/' && in[1].unicode() == '.') {
|
||||
*out++ = u'/';
|
||||
in += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
// otherwise, if the input buffer begins with a prefix
|
||||
// of "/../" or "/..", where ".." is a complete path
|
||||
// segment, then replace that prefix with "/" in the
|
||||
// input buffer and remove the last //segment and its
|
||||
// preceding "/" (if any) from the output buffer;
|
||||
if (in <= end - 4 && in[0].unicode() == '/' && in[1].unicode() == '.'
|
||||
&& in[2].unicode() == '.' && in[3].unicode() == '/') {
|
||||
while (out > path->constData() && (--out)->unicode() != '/')
|
||||
;
|
||||
if (out == path->constData() && out->unicode() != '/')
|
||||
++in;
|
||||
in += 3;
|
||||
continue;
|
||||
} else if (in == end - 3 && in[0].unicode() == '/' && in[1].unicode() == '.'
|
||||
&& in[2].unicode() == '.') {
|
||||
while (out > path->constData() && (--out)->unicode() != '/')
|
||||
;
|
||||
if (out->unicode() == '/')
|
||||
++out;
|
||||
in += 3;
|
||||
break;
|
||||
}
|
||||
|
||||
// otherwise move the first path segment in
|
||||
// the input buffer to the end of the output
|
||||
// buffer, including the initial "/" character
|
||||
// (if any) and any subsequent characters up
|
||||
// to, but not including, the next "/"
|
||||
// character or the end of the input buffer.
|
||||
#if 0 // to see in the debugger
|
||||
QStringView output(path->constBegin(), out);
|
||||
QStringView input(in, end);
|
||||
#endif
|
||||
// First, copy any preceding slashes, so we can look at the segment's
|
||||
// content.
|
||||
while (in < end && in[0] == u'/') {
|
||||
*out++ = *in++;
|
||||
|
||||
// Note: we may exit this loop with in == end, in which case we
|
||||
// *shouldn't* dereference *in. But since we are pointing to a
|
||||
// detached, non-empty QString, we know there's a u'\0' at the end.
|
||||
}
|
||||
|
||||
// Is this path segment either "." or ".."?
|
||||
enum { Nothing, Dot, DotDot } type = Nothing;
|
||||
if (in[0] == u'.') {
|
||||
if (in + 1 == end || in[1] == u'/')
|
||||
type = Dot;
|
||||
else if (in[1] == u'.' && (in + 2 == end || in[2] == u'/'))
|
||||
type = DotDot;
|
||||
}
|
||||
if (type != Nothing) {
|
||||
// If it is either, we skip it and remove any preceding slashes (if
|
||||
// any) from the output. If it is "..", we remove the segment
|
||||
// before that and its preceding slashes (if any) too.
|
||||
const QChar *start = path->constBegin();
|
||||
if (type == DotDot) {
|
||||
while (out > start && *--out != u'/')
|
||||
;
|
||||
while (out > start && *--out == u'/')
|
||||
;
|
||||
++in; // the first dot
|
||||
}
|
||||
|
||||
in += 2; // one dot and either one slash or the terminating null
|
||||
while (out > start && *--out != u'/')
|
||||
;
|
||||
|
||||
// And then replace the segment with "/", unless it would make a
|
||||
// relative path become absolute.
|
||||
if (out != start) {
|
||||
// Replacing with a slash won't make the path absolute.
|
||||
*out++ = u'/';
|
||||
} else if (*start == u'/') {
|
||||
// The path is already absolute.
|
||||
++out;
|
||||
} else {
|
||||
// The path is relative, so we must skip any follow-on slashes
|
||||
// to make sure the next iteration of the loop won't copy them,
|
||||
// which would make the path become absolute.
|
||||
while (in < end && *in == u'/')
|
||||
++in;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// If it is neither, then we copy this segment.
|
||||
while (in < end && in->unicode() != '/')
|
||||
*out++ = *in++;
|
||||
}
|
||||
path->truncate(out - path->constData());
|
||||
path->truncate(out - path->constBegin());
|
||||
}
|
||||
|
||||
// Authority-less URLs cannot have paths starting with double slashes (see
|
||||
// QUrlPrivate::validityError). We refuse to turn a valid URL into invalid by
|
||||
// way of QUrl::resolved().
|
||||
static void fixupNonAuthorityPath(QString *path)
|
||||
{
|
||||
if (path->isEmpty() || path->at(0) != u'/')
|
||||
return;
|
||||
|
||||
// Find the first non-slash character, because its position is equal to the
|
||||
// number of slashes. We'll remove all but one of them.
|
||||
qsizetype i = 0;
|
||||
while (i + 1 < path->size() && path->at(i + 1) == u'/')
|
||||
++i;
|
||||
if (i)
|
||||
path->remove(0, i);
|
||||
}
|
||||
|
||||
inline QUrlPrivate::ErrorCode QUrlPrivate::validityError(QString *source, qsizetype *position) const
|
||||
@ -2778,6 +2800,8 @@ QUrl QUrl::resolved(const QUrl &relative) const
|
||||
t.d->sectionIsPresent &= ~QUrlPrivate::Fragment;
|
||||
|
||||
removeDotsFromPath(&t.d->path);
|
||||
if (!t.d->hasAuthority())
|
||||
fixupNonAuthorityPath(&t.d->path);
|
||||
|
||||
#if defined(QURL_DEBUG)
|
||||
qDebug("QUrl(\"%ls\").resolved(\"%ls\") = \"%ls\"",
|
||||
|
@ -839,7 +839,33 @@ void tst_QUrl::resolving_data()
|
||||
QTest::addColumn<QString>("relativeUrl");
|
||||
QTest::addColumn<QString>("resolvedUrl");
|
||||
|
||||
// boundary cases
|
||||
QTest::newRow("empty-on-empty") << "http://a" << "" << "http://a";
|
||||
QTest::newRow("empty-on-/") << "http://a/" << "" << "http://a/";
|
||||
QTest::newRow("empty-on-//") << "http://a//" << "" << "http://a//";
|
||||
QTest::newRow("empty-on-/.") << "http://a/." << "" << "http://a/";
|
||||
QTest::newRow("empty-on-/./") << "http://a/./" << "" << "http://a/";
|
||||
QTest::newRow("empty-on-/..") << "http://a/.." << "" << "http://a/";
|
||||
QTest::newRow("empty-on-/../") << "http://a/../" << "" << "http://a/";
|
||||
|
||||
QTest::newRow("/-on-empty-with-authority") << "http://a" << "/" << "http://a/";
|
||||
QTest::newRow(".-on-empty-with-authority") << "http://a" << "." << "http://a/";
|
||||
QTest::newRow("./-on-empty-with-authority") << "http://a" << "./" << "http://a/";
|
||||
QTest::newRow(".//-on-empty-with-authority") << "http://a" << ".//" << "http://a//";
|
||||
QTest::newRow("..-on-empty-with-authority") << "http://a" << ".." << "http://a/";
|
||||
QTest::newRow("../-on-empty-with-authority") << "http://a" << "../" << "http://a/";
|
||||
QTest::newRow("/-on-empty-no-authority") << "scheme:" << "/" << "scheme:/";
|
||||
QTest::newRow(".-on-empty-no-authority") << "scheme:" << "." << "scheme:";
|
||||
QTest::newRow("./-on-empty-no-authority") << "scheme:" << "./" << "scheme:";
|
||||
QTest::newRow(".//-on-empty-no-authority") << "scheme:" << "./" << "scheme:";
|
||||
QTest::newRow("..-on-empty-no-authority") << "scheme:" << ".." << "scheme:";
|
||||
QTest::newRow("../-on-empty-no-authority") << "scheme:" << "../" << "scheme:";
|
||||
|
||||
QTest::newRow("scheme-change") << "http://a" << "https://b" << "https://b";
|
||||
QTest::newRow("scheme-change-path") << "http://a/" << "scheme:" << "scheme:";
|
||||
|
||||
// 5.4.1 Normal Examples (http://www.ietf.org/rfc/rfc3986.txt)
|
||||
// URL paths not ending in /
|
||||
QTest::newRow("g:h") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("g:h") << QString::fromLatin1("g:h");
|
||||
QTest::newRow("g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("g") << QString::fromLatin1("http://a/b/c/g");
|
||||
QTest::newRow("./g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("./g") << QString::fromLatin1("http://a/b/c/g");
|
||||
@ -857,12 +883,62 @@ void tst_QUrl::resolving_data()
|
||||
QTest::newRow("[empty]") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("") << QString::fromLatin1("http://a/b/c/d;p?q");
|
||||
QTest::newRow(".") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1(".") << QString::fromLatin1("http://a/b/c/");
|
||||
QTest::newRow("./") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("./") << QString::fromLatin1("http://a/b/c/");
|
||||
QTest::newRow(".//") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1(".//") << QString::fromLatin1("http://a/b/c//");
|
||||
QTest::newRow("..") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("..") << QString::fromLatin1("http://a/b/");
|
||||
QTest::newRow("../") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../") << QString::fromLatin1("http://a/b/");
|
||||
QTest::newRow("..//") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("..//") << QString::fromLatin1("http://a/b//");
|
||||
QTest::newRow("../g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../g") << QString::fromLatin1("http://a/b/g");
|
||||
QTest::newRow("..//g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("..//g") << QString::fromLatin1("http://a/b//g");
|
||||
QTest::newRow("../..") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../..") << QString::fromLatin1("http://a/");
|
||||
QTest::newRow("../../") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../../") << QString::fromLatin1("http://a/");
|
||||
QTest::newRow("../..//") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../..//") << QString::fromLatin1("http://a//");
|
||||
QTest::newRow("../../g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../../g") << QString::fromLatin1("http://a/g");
|
||||
QTest::newRow("../..//g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../..//g") << QString::fromLatin1("http://a//g");
|
||||
|
||||
// URL paths ending in /
|
||||
QTest::newRow("g:h-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("g:h") << QString::fromLatin1("g:h");
|
||||
QTest::newRow("g-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("g") << QString::fromLatin1("http://a/b/c/g");
|
||||
QTest::newRow("./g-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("./g") << QString::fromLatin1("http://a/b/c/g");
|
||||
QTest::newRow("g/-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("g/") << QString::fromLatin1("http://a/b/c/g/");
|
||||
QTest::newRow("/g-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("/g") << QString::fromLatin1("http://a/g");
|
||||
QTest::newRow("//g-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("//g") << QString::fromLatin1("http://g");
|
||||
QTest::newRow("?y-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("?y") << QString::fromLatin1("http://a/b/c/;p?y");
|
||||
QTest::newRow("g?y-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("g?y") << QString::fromLatin1("http://a/b/c/g?y");
|
||||
QTest::newRow("#s-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("#s") << QString::fromLatin1("http://a/b/c/;p?q#s");
|
||||
QTest::newRow("g#s-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("g#s") << QString::fromLatin1("http://a/b/c/g#s");
|
||||
QTest::newRow("g?y#s-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("g?y#s") << QString::fromLatin1("http://a/b/c/g?y#s");
|
||||
QTest::newRow(";x-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1(";x") << QString::fromLatin1("http://a/b/c/;x");
|
||||
QTest::newRow("g;x-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("g;x") << QString::fromLatin1("http://a/b/c/g;x");
|
||||
QTest::newRow("g;x?y#s-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("g;x?y#s") << QString::fromLatin1("http://a/b/c/g;x?y#s");
|
||||
QTest::newRow("[empty]-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("") << QString::fromLatin1("http://a/b/c/;p?q");
|
||||
QTest::newRow(".-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1(".") << QString::fromLatin1("http://a/b/c/");
|
||||
QTest::newRow("./-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("./") << QString::fromLatin1("http://a/b/c/");
|
||||
QTest::newRow(".//-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1(".//") << QString::fromLatin1("http://a/b/c//");
|
||||
QTest::newRow("..-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("..") << QString::fromLatin1("http://a/b/");
|
||||
QTest::newRow("../-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("../") << QString::fromLatin1("http://a/b/");
|
||||
QTest::newRow("..//-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("..//") << QString::fromLatin1("http://a/b//");
|
||||
QTest::newRow("../g-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("../g") << QString::fromLatin1("http://a/b/g");
|
||||
QTest::newRow("..//g-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("..//g") << QString::fromLatin1("http://a/b//g");
|
||||
QTest::newRow("../..-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("../..") << QString::fromLatin1("http://a/");
|
||||
QTest::newRow("../../-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("../../") << QString::fromLatin1("http://a/");
|
||||
QTest::newRow("../..//-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("../..//") << QString::fromLatin1("http://a//");
|
||||
QTest::newRow("../../g-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("../../g") << QString::fromLatin1("http://a/g");
|
||||
QTest::newRow("../..//g-on-/") << QString::fromLatin1("http://a/b/c/;p?q") << QString::fromLatin1("../..//g") << QString::fromLatin1("http://a//g");
|
||||
|
||||
// URL paths ending in //
|
||||
QTest::newRow(".-on-//") << "http://a/b/c//" << "." << "http://a/b/c//";
|
||||
QTest::newRow("./-on-//") << "http://a/b/c//" << "./" << "http://a/b/c//";
|
||||
QTest::newRow(".//-on-//") << "http://a/b/c//" << ".//" << "http://a/b/c///"; // weird but correct
|
||||
QTest::newRow("..-on-//") << "http://a/b/c//" << ".." << "http://a/b/";
|
||||
QTest::newRow("../-on-//") << "http://a/b/c//" << "../" << "http://a/b/";
|
||||
QTest::newRow("..//-on-//") << "http://a/b/c//" << "..//" << "http://a/b//";
|
||||
QTest::newRow("../g-on-//") << "http://a/b/c//" << "../g" << "http://a/b/g";
|
||||
QTest::newRow("..//g-on-//") << "http://a/b/c//" << "..//g" << "http://a/b//g";
|
||||
QTest::newRow("../..-on-//") << "http://a/b/c//" << "../.." << "http://a/";
|
||||
QTest::newRow("../../-on-//") << "http://a/b/c//" << "../../" << "http://a/";
|
||||
QTest::newRow("../..//-on-//") << "http://a/b/c//" << "../..//" << "http://a//";
|
||||
QTest::newRow("../../g-on-//") << "http://a/b/c//" << "../../g" << "http://a/g";
|
||||
QTest::newRow("../..//g-on-//") << "http://a/b/c//" << "../..//g" << "http://a//g";
|
||||
|
||||
// 5.4.2 Abnormal Examples (http://www.ietf.org/rfc/rfc3986.txt)
|
||||
|
||||
@ -870,8 +946,15 @@ void tst_QUrl::resolving_data()
|
||||
// relative path ".." segments than there are hierarchical levels in the
|
||||
// base URI's path. Note that the ".." syntax cannot be used to change
|
||||
// the authority component of a URI.
|
||||
QTest::newRow("../../../") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../../../") << QString::fromLatin1("http://a/");
|
||||
QTest::newRow("../../../..") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../../../..") << QString::fromLatin1("http://a/");
|
||||
QTest::newRow("../../../..//") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../../../..//") << QString::fromLatin1("http://a//");
|
||||
QTest::newRow("../../../../..") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../../../../..") << QString::fromLatin1("http://a/");
|
||||
QTest::newRow("../../../../../") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../../../../../") << QString::fromLatin1("http://a/");
|
||||
QTest::newRow("../../../g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../../../g") << QString::fromLatin1("http://a/g");
|
||||
QTest::newRow("../../..//g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../../..//g") << QString::fromLatin1("http://a//g");
|
||||
QTest::newRow("../../../../g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../../../../g") << QString::fromLatin1("http://a/g");
|
||||
QTest::newRow("../../../..//g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../../../..//g") << QString::fromLatin1("http://a//g");
|
||||
|
||||
// Similarly, parsers must remove the dot-segments "." and ".." when
|
||||
// they are complete components of a path, but not when they are only
|
||||
@ -917,11 +1000,49 @@ void tst_QUrl::resolving_data()
|
||||
QTest::newRow("../a (2)") << QString::fromLatin1("b/a") << QString::fromLatin1("../a") << QString::fromLatin1("a");
|
||||
QTest::newRow("../a (3)") << QString::fromLatin1("b/c/a") << QString::fromLatin1("../a") << QString::fromLatin1("b/a");
|
||||
QTest::newRow("../a (4)") << QString::fromLatin1("b") << QString::fromLatin1("/a") << QString::fromLatin1("/a");
|
||||
QTest::newRow("relative+.") << "scheme:" << "." << "scheme:";
|
||||
QTest::newRow("relative+./") << "scheme:" << "./" << "scheme:";
|
||||
QTest::newRow("relative+.//") << "scheme:" << ".//" << "scheme:";
|
||||
QTest::newRow("relative+.///") << "scheme:" << ".///" << "scheme:";
|
||||
QTest::newRow("relative+./.") << "scheme:" << "./." << "scheme:";
|
||||
QTest::newRow("relative+././") << "scheme:" << "././" << "scheme:";
|
||||
QTest::newRow("relative+..") << "scheme:" << ".." << "scheme:";
|
||||
QTest::newRow("relative+../") << "scheme:" << "../" << "scheme:";
|
||||
QTest::newRow("relative+..//") << "scheme:" << "..//" << "scheme:";
|
||||
QTest::newRow("relative+..///") << "scheme:" << "..///" << "scheme:";
|
||||
QTest::newRow("relative+../.") << "scheme:" << "../." << "scheme:";
|
||||
QTest::newRow("relative+.././") << "scheme:" << ".././" << "scheme:";
|
||||
QTest::newRow("relative+.././/") << "scheme:" << ".././/" << "scheme:";
|
||||
QTest::newRow("relative+.././//") << "scheme:" << ".././//" << "scheme:";
|
||||
QTest::newRow("relative+../../../..") << "scheme:b/c/d" << "../../../.." << "scheme:";
|
||||
QTest::newRow("relative+../../../../") << "scheme:b/c/d" << "../../../../" << "scheme:";
|
||||
QTest::newRow("relative+../../../..//") << "scheme:b/c/d" << "../../../..//" << "scheme:";
|
||||
QTest::newRow("relative+../../d/../..") << "scheme:b/c/d" << "../../d/../.." << "scheme:";
|
||||
QTest::newRow("relative+../../d/../../") << "scheme:b/c/d" << "../../d/../../" << "scheme:";
|
||||
QTest::newRow("relative+endslash+../../../..") << "scheme:b/c/d/" << "../../../.." << "scheme:";
|
||||
QTest::newRow("relative+endslash+../../../../") << "scheme:b/c/d/" << "../../../../" << "scheme:";
|
||||
QTest::newRow("relative+endslash+../../../..//") << "scheme:b/c/d/" << "../../../..//" << "scheme:";
|
||||
|
||||
// Resolve absolute without authority with relative
|
||||
QTest::newRow("../a (5)") << QString::fromLatin1("/b") << QString::fromLatin1("../a") << QString::fromLatin1("/a");
|
||||
QTest::newRow("../a (6)") << QString::fromLatin1("/b/a") << QString::fromLatin1("../a") << QString::fromLatin1("/a");
|
||||
QTest::newRow("../a (7)") << QString::fromLatin1("/b/c/a") << QString::fromLatin1("../a") << QString::fromLatin1("/b/a");
|
||||
QTest::newRow("../a (8)") << QString::fromLatin1("/b") << QString::fromLatin1("/a") << QString::fromLatin1("/a");
|
||||
QTest::newRow("noauthority+.") << "scheme:/a/b" << "." << "scheme:/a/";
|
||||
QTest::newRow("noauthority+./") << "scheme:/a/b" << "./" << "scheme:/a/";
|
||||
QTest::newRow("noauthority+.//") << "scheme:/a/b" << ".//" << "scheme:/a//";
|
||||
QTest::newRow("noauthority+./d") << "scheme:/a/b" << "./d" << "scheme:/a/d";
|
||||
QTest::newRow("noauthority+.//d") << "scheme:/a/b" << ".//d" << "scheme:/a//d";
|
||||
QTest::newRow("noauthority+..") << "scheme:/a/b" << ".." << "scheme:/";
|
||||
QTest::newRow("noauthority+../") << "scheme:/a/b" << "../" << "scheme:/";
|
||||
QTest::newRow("noauthority+..//") << "scheme:/a/b" << "..//" << "scheme:/";
|
||||
QTest::newRow("noauthority+../d") << "scheme:/a/b" << "../d" << "scheme:/d";
|
||||
QTest::newRow("noauthority+..//d") << "scheme:/a/b" << "..//d" << "scheme:/d"; // no double slash!
|
||||
QTest::newRow("noauthority+../..") << "scheme:/a/b" << "../.." << "scheme:/";
|
||||
QTest::newRow("noauthority+../../") << "scheme:/a/b" << "../../" << "scheme:/";
|
||||
QTest::newRow("noauthority+../..//") << "scheme:/a/b" << "../..//" << "scheme:/";
|
||||
QTest::newRow("noauthority+../../d") << "scheme:/a/b" << "../../d" << "scheme:/d";
|
||||
QTest::newRow("noauthority+../..//d") << "scheme:/a/b" << "../..//d" << "scheme:/d"; // no double slash!
|
||||
|
||||
// More tests from KDE
|
||||
QTest::newRow("brackets") << QString::fromLatin1("http://www.calorieking.com/personal/diary/") << QString::fromLatin1("/personal/diary/rpc.php?C=jsrs1&F=getDiaryDay&P0=[2006-3-8]&U=1141858921458") << QString::fromLatin1("http://www.calorieking.com/personal/diary/rpc.php?C=jsrs1&F=getDiaryDay&P0=[2006-3-8]&U=1141858921458");
|
||||
|
Loading…
x
Reference in New Issue
Block a user