From 368adbf8e75c00712c7a30eb6b8d7a7e175e89d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lutz=20Sch=C3=B6nemann?= Date: Wed, 17 Dec 2014 16:27:35 +0100 Subject: Fix wrap registered object issue When wrapping a registered object the code generated a new ID for an already known object. That new ID wasn't stored but returned to the client including the objects information. That resulted in a new created object on client side but the remote object (on the server) was not accessible. This patch fixes the issue by just returning the known ID of a known object. Because the client already has a local representation of that object it does not have to unwrap the object description. Change-Id: I31964823c84c84fd7ebce4386865c18fb5518be7 Reviewed-by: Milian Wolff --- src/webchannel/qmetaobjectpublisher.cpp | 9 +++-- src/webchannel/qwebchannel.js | 2 +- tests/auto/webchannel/tst_webchannel.cpp | 56 ++++++++++++++++++++++++++++++++ tests/auto/webchannel/tst_webchannel.h | 20 ++++++++++++ 4 files changed, 83 insertions(+), 4 deletions(-) diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp index 0cad569..42c95d2 100644 --- a/src/webchannel/qmetaobjectpublisher.cpp +++ b/src/webchannel/qmetaobjectpublisher.cpp @@ -449,16 +449,18 @@ QJsonValue QMetaObjectPublisher::wrapResult(const QVariant &result, QWebChannelA { if (QObject *object = result.value()) { QString id = registeredObjectIds.value(object); + QJsonObject classInfo; if (id.isEmpty()) { // neither registered, nor wrapped, do so now id = QUuid::createUuid().toString(); - Q_ASSERT(!registeredObjects.contains(id)); + // store ID before the call to classInfoForObject() + // in case of self-contained objects it avoids + // infinite loops + registeredObjectIds[object] = id; classInfo = classInfoForObject(object, transport); - registeredObjectIds[object] = id; - ObjectInfo oi(object, classInfo); if (transport) { oi.transports.append(transport); @@ -485,6 +487,7 @@ QJsonValue QMetaObjectPublisher::wrapResult(const QVariant &result, QWebChannelA objectInfo[KEY_ID] = id; if (!classInfo.isEmpty()) objectInfo[KEY_DATA] = classInfo; + return objectInfo; } else if (result.canConvert()) { // Workaround for keeping QJSValues from QVariant. diff --git a/src/webchannel/qwebchannel.js b/src/webchannel/qwebchannel.js index c270a95..f114e77 100644 --- a/src/webchannel/qwebchannel.js +++ b/src/webchannel/qwebchannel.js @@ -193,7 +193,7 @@ function QObject(name, data, webChannel) } if (!response || !response["__QObject*__"] - || response["id"] === undefined) { + || response.id === undefined) { return response; } diff --git a/tests/auto/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp index 55fd2d9..e36a1b3 100644 --- a/tests/auto/webchannel/tst_webchannel.cpp +++ b/tests/auto/webchannel/tst_webchannel.cpp @@ -146,6 +146,12 @@ void TestWebChannel::testInfoForObject() method.append(obj.metaObject()->indexOfMethod("slot2(QString)")); expected.append(method); } + { + QJsonArray method; + method.append(QStringLiteral("setObjectProperty")); + method.append(obj.metaObject()->indexOfMethod("setObjectProperty(QObject*)")); + expected.append(method); + } { QJsonArray method; method.append(QStringLiteral("method1")); @@ -230,6 +236,19 @@ void TestWebChannel::testInfoForObject() property.append(obj.bar()); expected.append(property); } + { + QJsonArray property; + property.append(obj.metaObject()->indexOfProperty("objectProperty")); + property.append(QStringLiteral("objectProperty")); + { + QJsonArray signal; + signal.append(1); + signal.append(obj.metaObject()->indexOfMethod("objectPropertyChanged()")); + property.append(signal); + } + property.append(QJsonValue::fromVariant(QVariant::fromValue(obj.objectProperty()))); + expected.append(property); + } QCOMPARE(info["properties"].toArray(), expected); } } @@ -270,6 +289,43 @@ void TestWebChannel::testDisconnect() m_dummyTransport->emitMessageReceived(QJsonObject()); } +void TestWebChannel::testWrapRegisteredObject() +{ + QWebChannel channel; + TestObject obj; + obj.setObjectName("myTestObject"); + + channel.registerObject(obj.objectName(), &obj); + channel.connectTo(m_dummyTransport); + channel.d_func()->publisher->initializeClient(m_dummyTransport); + + QJsonObject objectInfo = channel.d_func()->publisher->wrapResult(QVariant::fromValue(&obj), m_dummyTransport).toObject(); + + QCOMPARE(2, objectInfo.length()); + QVERIFY(objectInfo.contains("id")); + QVERIFY(objectInfo.contains("__QObject*__")); + QVERIFY(objectInfo.value("__QObject*__").isBool() && objectInfo.value("__QObject*__").toBool()); + + QString returnedId = objectInfo.value("id").toString(); + + QCOMPARE(&obj, channel.d_func()->publisher->registeredObjects.value(obj.objectName())); + QCOMPARE(obj.objectName(), channel.d_func()->publisher->registeredObjectIds.value(&obj)); + QCOMPARE(obj.objectName(), returnedId); +} + +void TestWebChannel::testInfiniteRecursion() +{ + QWebChannel channel; + TestObject obj; + obj.setObjectProperty(&obj); + obj.setObjectName("myTestObject"); + + channel.connectTo(m_dummyTransport); + channel.d_func()->publisher->initializeClient(m_dummyTransport); + + QJsonObject objectInfo = channel.d_func()->publisher->wrapResult(QVariant::fromValue(&obj), m_dummyTransport).toObject(); +} + static QHash createObjects(QObject *parent) { const int num = 100; diff --git a/tests/auto/webchannel/tst_webchannel.h b/tests/auto/webchannel/tst_webchannel.h index 7b9a1e3..649e61f 100644 --- a/tests/auto/webchannel/tst_webchannel.h +++ b/tests/auto/webchannel/tst_webchannel.h @@ -69,9 +69,12 @@ class TestObject : public QObject Q_PROPERTY(Foo foo READ foo CONSTANT) Q_PROPERTY(int asdf READ asdf NOTIFY asdfChanged) Q_PROPERTY(QString bar READ bar NOTIFY theBarHasChanged) + Q_PROPERTY(QObject * objectProperty READ objectProperty WRITE setObjectProperty NOTIFY objectPropertyChanged) + public: explicit TestObject(QObject *parent = 0) : QObject(parent) + , mObjectProperty(0) { } enum Foo { @@ -83,6 +86,11 @@ public: int asdf() const {return 42;} QString bar() const {return QString();} + QObject *objectProperty() const + { + return mObjectProperty; + } + Q_INVOKABLE void method1() {} protected: @@ -96,16 +104,26 @@ signals: void sig2(const QString&); void asdfChanged(); void theBarHasChanged(); + void objectPropertyChanged(); public slots: void slot1() {} void slot2(const QString&) {} + void setObjectProperty(QObject *object) + { + mObjectProperty = object; + emit objectPropertyChanged(); + } + protected slots: void slot3() {} private slots: void slot4() {} + +public: + QObject *mObjectProperty; }; class BenchObject : public QObject @@ -218,6 +236,8 @@ private slots: void testInfoForObject(); void testInvokeMethodConversion(); void testDisconnect(); + void testWrapRegisteredObject(); + void testInfiniteRecursion(); void benchClassInfo(); void benchInitializeClients(); -- cgit v1.2.1