diff options
author | Fabian Kosmale <fabian.kosmale@qt.io> | 2020-01-03 10:32:01 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2020-01-03 12:02:18 +0000 |
commit | 01bbd7e41ac8444d2282ac6ca1862c3748f685a1 (patch) | |
tree | ad46297d0f39957fd2597f19f2e5eacbeb0240d5 | |
parent | a4150b040e8492e070d6bfefb190ae0852644f11 (diff) |
QV4::ExecutionEngine: provide QNAM accessor
In XMLHttpRequest, we need to get the QNetworkAccessManager from the
engine. However, if the request originates from a WorkerScript, there
exists no qmlEngine. We therefore add a new indirection to access the
QNAM, and set it up accordinly in registerWorkerScript.
Fixes: QTBUG-81055
Change-Id: I8915202b6d6b7139c8386304b3d1d7a22a82045e
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 11 | ||||
-rw-r--r-- | src/qml/qml/qqmlxmlhttprequest.cpp | 2 | ||||
-rw-r--r-- | src/qmlworkerscript/qquickworkerscript.cpp | 11 | ||||
-rw-r--r-- | tests/auto/qml/qquickworkerscript/data/doRequest.mjs | 6 | ||||
-rw-r--r-- | tests/auto/qml/qquickworkerscript/data/xmlHttpRequest.qml | 16 | ||||
-rw-r--r-- | tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp | 8 |
7 files changed, 57 insertions, 2 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 885f06a3e3..23582e0ccb 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -2323,4 +2323,9 @@ int ExecutionEngine::registerExtension() return registrationData()->extensionCount++; } +QNetworkAccessManager *QV4::detail::getNetworkAccessManager(ExecutionEngine *engine) +{ + return engine->qmlEngine()->networkAccessManager(); +} + QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index d233347060..081859f4cc 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -91,7 +91,14 @@ class PageAllocation; QT_BEGIN_NAMESPACE -namespace QV4 { struct QObjectMethod; } +class QNetworkAccessManager; + +namespace QV4 { +struct QObjectMethod; +namespace detail { +QNetworkAccessManager *getNetworkAccessManager(ExecutionEngine *engine); +} +} // Used to allow a QObject method take and return raw V4 handles without having to expose // 48 in the public API. @@ -348,6 +355,8 @@ public: FunctionObject *getStackFunction() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetStack_Function); } FunctionObject *thrower() const { return reinterpret_cast<FunctionObject *>(jsObjects + ThrowerObject); } + std::function<QNetworkAccessManager*(ExecutionEngine*)> networkAccessManager = detail::getNetworkAccessManager; + enum JSStrings { String_Empty, String_undefined, diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index 4db0562c0e..021aa369fa 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -1647,7 +1647,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject Scope scope(f->engine()); const QQmlXMLHttpRequestCtor *ctor = static_cast<const QQmlXMLHttpRequestCtor *>(f); - QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->qmlEngine()->networkAccessManager(), scope.engine); + QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->networkAccessManager(scope.engine), scope.engine); Scoped<QQmlXMLHttpRequestWrapper> w(scope, scope.engine->memoryManager->allocate<QQmlXMLHttpRequestWrapper>(r)); ScopedObject proto(scope, ctor->d()->proto); w->setPrototypeUnchecked(proto); diff --git a/src/qmlworkerscript/qquickworkerscript.cpp b/src/qmlworkerscript/qquickworkerscript.cpp index 8b236697b9..c39433c74d 100644 --- a/src/qmlworkerscript/qquickworkerscript.cpp +++ b/src/qmlworkerscript/qquickworkerscript.cpp @@ -130,6 +130,7 @@ struct WorkerScript : public QV4::ExecutionEngine { QQuickWorkerScriptEnginePrivate *p = nullptr; QUrl source; QQuickWorkerScript *owner = nullptr; + QScopedPointer<QNetworkAccessManager> scriptLocalNAM; int id = -1; }; @@ -389,6 +390,16 @@ WorkerScript::WorkerScript(int id, QQuickWorkerScriptEnginePrivate *parent) QV4::ScopedValue sendMessage(scope, QV4::FunctionObject::createBuiltinFunction(this, name, QQuickWorkerScriptEnginePrivate::method_sendMessage, 1)); api->put(QV4::ScopedString(scope, scope.engine->newString(QStringLiteral("sendMessage"))), sendMessage); globalObject->put(QV4::ScopedString(scope, scope.engine->newString(QStringLiteral("WorkerScript"))), api); + networkAccessManager = [this](QV4::ExecutionEngine *engine){ + auto *workerScript = static_cast<WorkerScript *>(engine); + if (workerScript->scriptLocalNAM) + return workerScript->scriptLocalNAM.get(); + if (auto *namFactory = p->qmlengine->networkAccessManagerFactory()) + workerScript->scriptLocalNAM.reset(namFactory->create(p)); + else + workerScript->scriptLocalNAM.reset(new QNetworkAccessManager(p)); + return workerScript->scriptLocalNAM.get(); + }; } int QQuickWorkerScriptEngine::registerWorkerScript(QQuickWorkerScript *owner) diff --git a/tests/auto/qml/qquickworkerscript/data/doRequest.mjs b/tests/auto/qml/qquickworkerscript/data/doRequest.mjs new file mode 100644 index 0000000000..d607c3400d --- /dev/null +++ b/tests/auto/qml/qquickworkerscript/data/doRequest.mjs @@ -0,0 +1,6 @@ +WorkerScript.onMessage = function(message) +{ + var req = new XMLHttpRequest(); + req.open("GET", message.url, true); + req.send(); +}; diff --git a/tests/auto/qml/qquickworkerscript/data/xmlHttpRequest.qml b/tests/auto/qml/qquickworkerscript/data/xmlHttpRequest.qml new file mode 100644 index 0000000000..42136d78f0 --- /dev/null +++ b/tests/auto/qml/qquickworkerscript/data/xmlHttpRequest.qml @@ -0,0 +1,16 @@ +import QtQuick 2.14 + +Rectangle +{ + width: 100 + height: 100 + + WorkerScript + { + source: "doRequest.mjs" + Component.onCompleted: + { + sendMessage({"url": "https://example.com"}); + } + } +} diff --git a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp index bea9978f0b..d11e7bde4b 100644 --- a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp +++ b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp @@ -59,6 +59,7 @@ private slots: void script_function(); void script_var(); void stressDispose(); + void xmlHttpRequest(); private: void waitForEchoMessage(QQuickWorkerScript *worker) { @@ -341,6 +342,13 @@ void tst_QQuickWorkerScript::stressDispose() } } +void tst_QQuickWorkerScript::xmlHttpRequest() +{ + QQmlComponent component(&m_engine, testFileUrl("xmlHttpRequest.qml")); + QScopedPointer<QObject> root{component.create()}; // should not crash + QVERIFY(root); +} + QTEST_MAIN(tst_QQuickWorkerScript) #include "tst_qquickworkerscript.moc" |