From dc60a6e2b1a65fb51fa593840cef906aa017c6a0 Mon Sep 17 00:00:00 2001 From: Catalin Badea Date: Sun, 24 Aug 2014 21:17:21 -0700 Subject: [PATCH] Bug 982726 - Patch 3 - Implement client.postMessage and add tests for getServiced(). r=baku --HG-- extra : rebase_source : 39ac96d409c4ea2ccf1794a7b2a0f681fc7c5786 extra : amend_source : 9357dd9eec14a5af6bd234189473d0bfdf5d6ba7 --- dom/webidl/ServiceWorkerClient.webidl | 2 + dom/workers/ServiceWorkerClient.cpp | 130 ++++++++++++++++++ dom/workers/ServiceWorkerClient.h | 9 ++ .../get_serviced_worker_advanced.js | 12 ++ .../get_serviced_worker_enumerate.js | 7 + .../serviceworkers/message_posting_worker.js | 9 ++ dom/workers/test/serviceworkers/mochitest.ini | 7 + .../sw_clients/service_worker_controlled.html | 39 ++++++ .../test_get_serviced_advanced.html | 80 +++++++++++ .../test_get_serviced_enumerate.html | 82 +++++++++++ .../serviceworkers/test_post_message.html | 62 +++++++++ 11 files changed, 439 insertions(+) create mode 100644 dom/workers/test/serviceworkers/get_serviced_worker_advanced.js create mode 100644 dom/workers/test/serviceworkers/get_serviced_worker_enumerate.js create mode 100644 dom/workers/test/serviceworkers/message_posting_worker.js create mode 100644 dom/workers/test/serviceworkers/sw_clients/service_worker_controlled.html create mode 100644 dom/workers/test/serviceworkers/test_get_serviced_advanced.html create mode 100644 dom/workers/test/serviceworkers/test_get_serviced_enumerate.html create mode 100644 dom/workers/test/serviceworkers/test_post_message.html diff --git a/dom/webidl/ServiceWorkerClient.webidl b/dom/webidl/ServiceWorkerClient.webidl index 2473fb572fe..3543b4b49f8 100644 --- a/dom/webidl/ServiceWorkerClient.webidl +++ b/dom/webidl/ServiceWorkerClient.webidl @@ -11,4 +11,6 @@ [Exposed=ServiceWorker] interface ServiceWorkerClient { readonly attribute unsigned long id; + [Throws] + void postMessage(any message, optional sequence transfer); }; diff --git a/dom/workers/ServiceWorkerClient.cpp b/dom/workers/ServiceWorkerClient.cpp index 2a2e1c28b3e..f183b593611 100644 --- a/dom/workers/ServiceWorkerClient.cpp +++ b/dom/workers/ServiceWorkerClient.cpp @@ -6,8 +6,13 @@ #include "ServiceWorkerClient.h" +#include "mozilla/dom/MessageEvent.h" +#include "nsGlobalWindow.h" +#include "WorkerPrivate.h" + #include "mozilla/dom/ServiceWorkerClientBinding.h" +using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::dom::workers; @@ -27,3 +32,128 @@ ServiceWorkerClient::WrapObject(JSContext* aCx) return ServiceWorkerClientBinding::Wrap(aCx, this); } +namespace { + +class ServiceWorkerClientPostMessageRunnable MOZ_FINAL : public nsRunnable +{ + uint64_t mId; + JSAutoStructuredCloneBuffer mBuffer; + nsTArray> mClonedObjects; + +public: + ServiceWorkerClientPostMessageRunnable(uint64_t aId, + JSAutoStructuredCloneBuffer&& aData, + nsTArray>& aClonedObjects) + : mId(aId), + mBuffer(Move(aData)) + { + mClonedObjects.SwapElements(aClonedObjects); + } + + NS_IMETHOD + Run() + { + AssertIsOnMainThread(); + nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mId); + if (!window) { + return NS_ERROR_FAILURE; + } + + AutoJSAPI jsapi; + jsapi.Init(window); + JSContext* cx = jsapi.cx(); + + return DispatchDOMEvent(cx, window); + } + +private: + NS_IMETHOD + DispatchDOMEvent(JSContext* aCx, nsGlobalWindow* aTargetWindow) + { + AssertIsOnMainThread(); + + // Release reference to objects that were AddRef'd for + // cloning into worker when array goes out of scope. + nsTArray> clonedObjects; + clonedObjects.SwapElements(mClonedObjects); + + JS::Rooted messageData(aCx); + if (!mBuffer.read(aCx, &messageData, + WorkerStructuredCloneCallbacks(true))) { + xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR); + return NS_ERROR_FAILURE; + } + + nsCOMPtr event = new MessageEvent(aTargetWindow, + nullptr, nullptr); + nsresult rv = + event->InitMessageEvent(NS_LITERAL_STRING("message"), + false /* non-bubbling */, + false /* not cancelable */, + messageData, + EmptyString(), + EmptyString(), + nullptr); + if (NS_FAILED(rv)) { + xpc::Throw(aCx, rv); + return NS_ERROR_FAILURE; + } + + event->SetTrusted(true); + bool status = false; + aTargetWindow->DispatchEvent(event, &status); + + if (!status) { + return NS_ERROR_FAILURE; + } + + return NS_OK; + } +}; + +} // anonymous namespace + +void +ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle aMessage, + const Optional>& aTransferable, + ErrorResult& aRv) +{ + WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + + JS::Rooted transferable(aCx, JS::UndefinedValue()); + if (aTransferable.WasPassed()) { + const Sequence& realTransferable = aTransferable.Value(); + + JS::HandleValueArray elements = + JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(), + realTransferable.Elements()); + + JSObject* array = JS_NewArrayObject(aCx, elements); + if (!array) { + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); + return; + } + + transferable.setObject(*array); + } + + JSStructuredCloneCallbacks* callbacks = WorkerStructuredCloneCallbacks(false); + + nsTArray> clonedObjects; + + JSAutoStructuredCloneBuffer buffer; + if (!buffer.write(aCx, aMessage, transferable, callbacks, &clonedObjects)) { + aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); + return; + } + + nsRefPtr runnable = + new ServiceWorkerClientPostMessageRunnable(mId, Move(buffer), clonedObjects); + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + aRv.Throw(NS_ERROR_FAILURE); + } +} + diff --git a/dom/workers/ServiceWorkerClient.h b/dom/workers/ServiceWorkerClient.h index 7ad4c4aff80..438f0ce7a11 100644 --- a/dom/workers/ServiceWorkerClient.h +++ b/dom/workers/ServiceWorkerClient.h @@ -11,9 +11,14 @@ #include "nsWrapperCache.h" namespace mozilla { + +class ErrorResult; + namespace dom { class Promise; +template class Optional; +template class Sequence; namespace workers { @@ -36,6 +41,10 @@ public: return mId; } + void PostMessage(JSContext* aCx, JS::Handle aMessage, + const Optional>& aTransferable, + ErrorResult& aRv); + nsISupports* GetParentObject() const { return mOwner; diff --git a/dom/workers/test/serviceworkers/get_serviced_worker_advanced.js b/dom/workers/test/serviceworkers/get_serviced_worker_advanced.js new file mode 100644 index 00000000000..28e4e4e3112 --- /dev/null +++ b/dom/workers/test/serviceworkers/get_serviced_worker_advanced.js @@ -0,0 +1,12 @@ +onmessage = function(e) { + if (!e.data) { + dump("ERROR: message has no data.\n"); + } + + self.clients.getServiced().then(function(res) { + if (res.length === 0) { + dump("ERROR: no client is currently being controlled.\n"); + } + res[res.length - 1].postMessage(res.length); + }); +}; diff --git a/dom/workers/test/serviceworkers/get_serviced_worker_enumerate.js b/dom/workers/test/serviceworkers/get_serviced_worker_enumerate.js new file mode 100644 index 00000000000..42be6681abe --- /dev/null +++ b/dom/workers/test/serviceworkers/get_serviced_worker_enumerate.js @@ -0,0 +1,7 @@ +onmessage = function() { + self.clients.getServiced().then(function(result) { + for (i = 0; i < result.length; i++) { + result[i].postMessage(i); + } + }); +}; diff --git a/dom/workers/test/serviceworkers/message_posting_worker.js b/dom/workers/test/serviceworkers/message_posting_worker.js new file mode 100644 index 00000000000..f4b0b09979f --- /dev/null +++ b/dom/workers/test/serviceworkers/message_posting_worker.js @@ -0,0 +1,9 @@ +onmessage = function(e) { + self.clients.getServiced().then(function(res) { + if (!res.length) { + dump("ERROR: no clients are currently controlled.\n"); + } + res[0].postMessage(e.data); + }); +}; + diff --git a/dom/workers/test/serviceworkers/mochitest.ini b/dom/workers/test/serviceworkers/mochitest.ini index c8e7660cc5b..f141a3bcd06 100644 --- a/dom/workers/test/serviceworkers/mochitest.ini +++ b/dom/workers/test/serviceworkers/mochitest.ini @@ -12,11 +12,18 @@ support-files = unregister/index.html sw_clients/simple.html get_serviced_worker.js + get_serviced_worker_advanced.js + message_posting_worker.js + sw_clients/service_worker_controlled.html + get_serviced_worker_enumerate.js [test_get_serviced.html] +[test_get_serviced_advanced.html] +[test_get_serviced_enumerate.html] [test_installation_simple.html] [test_install_event.html] [test_navigator.html] +[test_post_message.html] [test_scopes.html] [test_controller.html] [test_unregister.html] diff --git a/dom/workers/test/serviceworkers/sw_clients/service_worker_controlled.html b/dom/workers/test/serviceworkers/sw_clients/service_worker_controlled.html new file mode 100644 index 00000000000..a67679ee7d2 --- /dev/null +++ b/dom/workers/test/serviceworkers/sw_clients/service_worker_controlled.html @@ -0,0 +1,39 @@ + + + + + controlled page + + + + + + + + diff --git a/dom/workers/test/serviceworkers/test_get_serviced_advanced.html b/dom/workers/test/serviceworkers/test_get_serviced_advanced.html new file mode 100644 index 00000000000..539a3f1f10e --- /dev/null +++ b/dom/workers/test/serviceworkers/test_get_serviced_advanced.html @@ -0,0 +1,80 @@ + + + + + Bug 982726 - test get_serviced + + + + +

+ +

+
+
+
+
+
diff --git a/dom/workers/test/serviceworkers/test_get_serviced_enumerate.html b/dom/workers/test/serviceworkers/test_get_serviced_enumerate.html
new file mode 100644
index 00000000000..7ba0d190f8e
--- /dev/null
+++ b/dom/workers/test/serviceworkers/test_get_serviced_enumerate.html
@@ -0,0 +1,82 @@
+
+
+
+
+  Bug 982726 - test get_serviced 
+  
+  
+
+
+

+ +

+
+
+
+
+
diff --git a/dom/workers/test/serviceworkers/test_post_message.html b/dom/workers/test/serviceworkers/test_post_message.html
new file mode 100644
index 00000000000..e9c8c0f916a
--- /dev/null
+++ b/dom/workers/test/serviceworkers/test_post_message.html
@@ -0,0 +1,62 @@
+
+
+
+
+  Bug 982726 - Test service worker post message 
+  
+  
+
+
+

+ +

+
+
+
+
+