On network redirects, update finalUrl, not url

We want all further imports to be relative to the redirected URL, not
the base one.

Note that this will incorporate any prior URL interceptions into the
final URL if a redirect happens. We don't really want this to happen
because the result of interception is not meant to be the base for
further URL lookup. However, as interception occurs before redirection,
this is unavoidable. Don't use URL interceptors on remote URLs.

Task-number: QTBUG-67882
Change-Id: I6693d14c8af8212dda9954d0bd0293c3c85441ef
(cherry picked from commit cda2680d80)
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
This commit is contained in:
Ulf Hermann 2018-05-23 12:28:46 +02:00 committed by Jani Heikkinen
parent 047e3f480e
commit 8556133d62
8 changed files with 60 additions and 9 deletions

View File

@ -357,9 +357,8 @@ qreal QQmlDataBlob::progress() const
/*!
Returns the physical url of the data. Initially this is the same as
finalUrl(), but if a network redirect happens while fetching the data, this url
is updated to reflect the new location. Also, if a URL interceptor is set, it
will work on this URL and leave finalUrl() alone.
finalUrl(), but if a URL interceptor is set, it will work on this URL
and leave finalUrl() alone.
\sa finalUrl()
*/
@ -380,8 +379,12 @@ QString QQmlDataBlob::urlString() const
Returns the logical URL to be used for resolving further URLs referred to in
the code.
This is the blob url passed to the constructor. If a network redirect
happens while fetching the data, this url remains the same.
This is the blob url passed to the constructor. If a URL interceptor rewrites
the URL, this one stays the same. If a network redirect happens while fetching
the data, this url is updated to reflect the new location. Therefore, if both
an interception and a redirection happen, the final url will indirectly
incorporate the result of the interception, potentially breaking further
lookups.
\sa url()
*/
@ -1195,15 +1198,15 @@ void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply)
QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (redirect.isValid()) {
QUrl url = reply->url().resolved(redirect.toUrl());
blob->m_url = url;
blob->m_urlString.clear();
blob->m_finalUrl = url;
blob->m_finalUrlString.clear();
QNetworkReply *reply = m_thread->networkAccessManager()->get(QNetworkRequest(url));
QObject *nrp = m_thread->networkReplyProxy();
QObject::connect(reply, SIGNAL(finished()), nrp, SLOT(finished()));
m_networkReplies.insert(reply, blob);
#ifdef DATABLOB_DEBUG
qWarning("QQmlDataBlob: redirected to %s", qPrintable(blob->urlString()));
qWarning("QQmlDataBlob: redirected to %s", qPrintable(blob->finalUrlString()));
#endif
return;
}

View File

@ -0,0 +1,3 @@
import QtQml 2.0
QtObject {}

View File

@ -0,0 +1,11 @@
import QtQuick 2.0
Item {
property int xy: loader.xy
Loader {
id: loader
asynchronous: true
source: 'Base.qml'
property int xy: item.xy
}
}

View File

@ -0,0 +1,5 @@
import QtQml 2.0
QtObject {
property int xy: 323232
}

View File

@ -0,0 +1,5 @@
import QtQml 2.0
Imported {
}

View File

@ -0,0 +1 @@
Imported 1.0 Imported.qml

View File

@ -33,6 +33,7 @@
#include <QtQuick/qquickitem.h>
#include <QtQml/private/qqmlengine_p.h>
#include <QtQml/private/qqmltypeloader_p.h>
#include "../../shared/testhttpserver.h"
#include "../../shared/util.h"
class tst_QQMLTypeLoader : public QQmlDataTest
@ -48,6 +49,7 @@ private slots:
void keepSingleton();
void keepRegistrations();
void intercept();
void redirect();
};
void tst_QQMLTypeLoader::testLoadComplete()
@ -410,6 +412,22 @@ void tst_QQMLTypeLoader::intercept()
QVERIFY(factory.loadedFiles.contains(QLatin1String(QT_TESTCASE_BUILDDIR) + "/Slow/qmldir"));
}
void tst_QQMLTypeLoader::redirect()
{
TestHTTPServer server;
QVERIFY2(server.listen(), qPrintable(server.errorString()));
QVERIFY(server.serveDirectory(dataDirectory()));
server.addRedirect("Base.qml", server.urlString("/redirected/Redirected.qml"));
QQmlEngine engine;
QQmlComponent component(&engine);
component.loadUrl(server.urlString("/Load.qml"), QQmlComponent::Asynchronous);
QTRY_VERIFY2(component.isReady(), qPrintable(component.errorString()));
QObject *object = component.create();
QTRY_COMPARE(object->property("xy").toInt(), 323232);
}
QTEST_MAIN(tst_QQMLTypeLoader)
#include "tst_qqmltypeloader.moc"

View File

@ -3,7 +3,12 @@ TARGET = tst_qqmltypeloader
QT += qml testlib qml-private quick
macx:CONFIG -= app_bundle
SOURCES += tst_qqmltypeloader.cpp
SOURCES += \
tst_qqmltypeloader.cpp \
../../shared/testhttpserver.cpp
HEADERS += \
../../shared/testhttpserver.h
include (../../shared/util.pri)