QUrl::resolved: avoid detaching from paths that don't have dot segments

This can happen in any number of cases where neither the base URI nor
the relative one had a "." or ".." segment. In particular, we want to
avoid detaching in the case where the new path is the same as either of
the base or relative URI's, which can happen when the other was empty
(and mergePaths() didn't have to prepend a slash).

Pick-to: 6.8.0 6.7 6.5
Change-Id: Iac1ff680887641888e00fffd17e14f3927e828ae
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
(cherry picked from commit 09055d7211b1f8ba9fdec141a1e919faee1c1676)
Reviewed-by: Ahmad Samir <a.samirh78@gmail.com>
This commit is contained in:
Thiago Macieira 2024-07-11 17:20:39 -07:00
parent 21eff6644d
commit 7b45dc49bb

View File

@ -1541,12 +1541,33 @@ static void removeDotsFromPath(QString *path)
// The input buffer is initialized with the now-appended path
// components and the output buffer is initialized to the empty
// string.
const QChar *in = path->constBegin();
// Scan the input for a "." or ".." segment. If there isn't any, then we
// don't need to modify this path at all.
qsizetype modidx = [&] {
bool lastWasSlash = true;
for (qsizetype i = 0, n = path->size(); i < n; ++i) {
if (lastWasSlash && in[i] == u'.') {
if (i + 1 == n || in[i + 1] == u'/')
return i;
if (in[i + 1] == u'.' && (i + 2 == n || in[i + 2] == u'/'))
return i;
}
lastWasSlash = in[i] == u'/';
}
return qsizetype(-1);
}();
if (modidx < 0)
return;
QChar *out = path->data();
const QChar *in = out;
const QChar *end = out + path->size();
out += modidx;
in = out;
// We implement a modified algorithm compared to RFC 3986, for efficiency.
while (in < end) {
do {
#if 0 // to see in the debugger
QStringView output(path->constBegin(), out);
QStringView input(in, end);
@ -1607,7 +1628,7 @@ static void removeDotsFromPath(QString *path)
// If it is neither, then we copy this segment.
while (in < end && in->unicode() != '/')
*out++ = *in++;
}
} while (in < end);
path->truncate(out - path->constBegin());
}