Bug 1142015 - Add source for messages dispatched to a Service Worker. r=baku

This commit is contained in:
Catalin Badea 2015-03-16 22:23:42 +02:00
parent 06875768a5
commit 02dc461839
9 changed files with 157 additions and 10 deletions

View File

@ -13,6 +13,9 @@
#include "jsapi.h"
#include "nsGlobalWindow.h" // So we can assign an nsGlobalWindow* to mWindowSource
#include "ServiceWorker.h"
#include "ServiceWorkerClient.h"
namespace mozilla {
namespace dom {
@ -103,12 +106,14 @@ MessageEvent::GetSource(nsIDOMWindow** aSource)
}
void
MessageEvent::GetSource(Nullable<OwningWindowProxyOrMessagePort>& aValue) const
MessageEvent::GetSource(Nullable<OwningWindowProxyOrMessagePortOrClient>& aValue) const
{
if (mWindowSource) {
aValue.SetValue().SetAsWindowProxy() = mWindowSource;
} else if (mPortSource) {
aValue.SetValue().SetAsMessagePort() = mPortSource;
} else if (mClientSource) {
aValue.SetValue().SetAsClient() = mClientSource;
}
}
@ -206,6 +211,12 @@ MessageEvent::SetSource(mozilla::dom::MessagePort* aPort)
mPortSource = aPort;
}
void
MessageEvent::SetSource(mozilla::dom::workers::ServiceWorkerClient* aClient)
{
mClientSource = aClient;
}
} // namespace dom
} // namespace mozilla

View File

@ -18,7 +18,13 @@ struct MessageEventInit;
class MessagePort;
class MessagePortBase;
class MessagePortList;
class OwningWindowProxyOrMessagePort;
class OwningWindowProxyOrMessagePortOrClient;
namespace workers {
class ServiceWorkerClient;
}
/**
* Implements the MessageEvent event, used for cross-document messaging and
@ -48,7 +54,7 @@ public:
void GetData(JSContext* aCx, JS::MutableHandle<JS::Value> aData,
ErrorResult& aRv);
void GetSource(Nullable<OwningWindowProxyOrMessagePort>& aValue) const;
void GetSource(Nullable<OwningWindowProxyOrMessagePortOrClient>& aValue) const;
MessagePortList* GetPorts()
{
@ -60,6 +66,8 @@ public:
// Non WebIDL methods
void SetSource(mozilla::dom::MessagePort* aPort);
void SetSource(workers::ServiceWorkerClient* aClient);
void SetSource(nsPIDOMWindow* aWindow)
{
mWindowSource = aWindow;
@ -86,6 +94,7 @@ private:
nsString mLastEventId;
nsCOMPtr<nsIDOMWindow> mWindowSource;
nsRefPtr<MessagePortBase> mPortSource;
nsRefPtr<workers::ServiceWorkerClient> mClientSource;
nsRefPtr<MessagePortList> mPorts;
};

View File

@ -31,9 +31,12 @@ interface MessageEvent : Event {
readonly attribute DOMString lastEventId;
/**
* The window or the port which originated this event.
* The window, port or client which originated this event.
* FIXME(catalinb): Update this when the spec changes are implemented.
* https://www.w3.org/Bugs/Public/show_bug.cgi?id=28199
* https://bugzilla.mozilla.org/show_bug.cgi?id=1143717
*/
readonly attribute (WindowProxy or MessagePort)? source;
readonly attribute (WindowProxy or MessagePort or Client)? source;
/**
* Initializes this event with the given data, in a manner analogous to

View File

@ -6,6 +6,7 @@
#include "ServiceWorker.h"
#include "nsPIDOMWindow.h"
#include "ServiceWorkerClient.h"
#include "ServiceWorkerManager.h"
#include "SharedWorker.h"
#include "WorkerPrivate.h"
@ -95,7 +96,12 @@ ServiceWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
return;
}
workerPrivate->PostMessage(aCx, aMessage, aTransferable, aRv);
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(GetParentObject());
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
nsAutoPtr<ServiceWorkerClientInfo> clientInfo(new ServiceWorkerClientInfo(doc));
workerPrivate->PostMessageToServiceWorker(aCx, aMessage, aTransferable,
clientInfo, aRv);
}
WorkerPrivate*

View File

@ -985,6 +985,9 @@ class MessageEventRunnable MOZ_FINAL : public WorkerRunnable
uint64_t mMessagePortSerial;
bool mToMessagePort;
// This is only used for messages dispatched to a service worker.
nsAutoPtr<ServiceWorkerClientInfo> mEventSource;
public:
MessageEventRunnable(WorkerPrivate* aWorkerPrivate,
TargetAndBusyBehavior aBehavior,
@ -999,6 +1002,12 @@ public:
mClonedObjects.SwapElements(aClonedObjects);
}
void
SetMessageSource(ServiceWorkerClientInfo* aSource)
{
mEventSource = aSource;
}
bool
DispatchDOMEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
DOMEventTargetHelper* aTarget, bool aIsMainThread)
@ -1024,6 +1033,12 @@ public:
EmptyString(),
EmptyString(),
nullptr);
if (mEventSource) {
nsRefPtr<ServiceWorkerClient> client =
new ServiceWorkerWindowClient(aTarget, *mEventSource);
event->SetSource(client);
}
if (NS_FAILED(rv)) {
xpc::Throw(aCx, rv);
return false;
@ -3089,9 +3104,10 @@ void
WorkerPrivateParent<Derived>::PostMessageInternal(
JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value> >& aTransferable,
const Optional<Sequence<JS::Value>>& aTransferable,
bool aToMessagePort,
uint64_t aMessagePortSerial,
ServiceWorkerClientInfo* aClientInfo,
ErrorResult& aRv)
{
AssertIsOnParentThread();
@ -3155,11 +3171,26 @@ WorkerPrivateParent<Derived>::PostMessageInternal(
WorkerRunnable::WorkerThreadModifyBusyCount,
Move(buffer), clonedObjects, aToMessagePort,
aMessagePortSerial);
runnable->SetMessageSource(aClientInfo);
if (!runnable->Dispatch(aCx)) {
aRv.Throw(NS_ERROR_FAILURE);
}
}
template <class Derived>
void
WorkerPrivateParent<Derived>::PostMessageToServiceWorker(
JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable,
nsAutoPtr<ServiceWorkerClientInfo>& aClientInfo,
ErrorResult& aRv)
{
AssertIsOnMainThread();
PostMessageInternal(aCx, aMessage, aTransferable, false, 0,
aClientInfo.forget(), aRv);
}
template <class Derived>
void
WorkerPrivateParent<Derived>::PostMessageToMessagePort(
@ -3172,7 +3203,7 @@ WorkerPrivateParent<Derived>::PostMessageToMessagePort(
AssertIsOnMainThread();
PostMessageInternal(aCx, aMessage, aTransferable, true, aMessagePortSerial,
aRv);
nullptr, aRv);
}
template <class Derived>

View File

@ -61,6 +61,7 @@ BEGIN_WORKERS_NAMESPACE
class AutoSyncLoopHolder;
class MessagePort;
class SharedWorker;
class ServiceWorkerClientInfo;
class WorkerControlRunnable;
class WorkerDebugger;
class WorkerDebuggerGlobalScope;
@ -221,8 +222,9 @@ private:
void
PostMessageInternal(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value> >& aTransferable,
const Optional<Sequence<JS::Value>>& aTransferable,
bool aToMessagePort, uint64_t aMessagePortSerial,
ServiceWorkerClientInfo* aClientInfo,
ErrorResult& aRv);
nsresult
@ -327,9 +329,15 @@ public:
const Optional<Sequence<JS::Value> >& aTransferable,
ErrorResult& aRv)
{
PostMessageInternal(aCx, aMessage, aTransferable, false, 0, aRv);
PostMessageInternal(aCx, aMessage, aTransferable, false, 0, nullptr, aRv);
}
void
PostMessageToServiceWorker(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable,
nsAutoPtr<ServiceWorkerClientInfo>& aClientInfo,
ErrorResult& aRv);
void
PostMessageToMessagePort(JSContext* aCx,
uint64_t aMessagePortSerial,

View File

@ -41,6 +41,7 @@ support-files =
serviceworker_not_sharedworker.js
match_all_client/match_all_client_id.html
match_all_client_id_worker.js
source_message_posting_worker.js
[test_unregister.html]
[test_installation_simple.html]
@ -56,6 +57,7 @@ support-files =
[test_workerUnregister.html]
[test_post_message.html]
[test_post_message_advanced.html]
[test_post_message_source.html]
[test_match_all_client_properties.html]
[test_close.html]
[test_serviceworker_interfaces.html]

View File

@ -0,0 +1,12 @@
onmessage = function(e) {
if (!e.source) {
dump("ERROR: message doesn't have a source.");
}
// The client should be a window client
if (e.source instanceof WindowClient) {
e.source.postMessage(e.data);
} else {
e.source.postMessage("ERROR. source is not a window client.");
}
};

View File

@ -0,0 +1,65 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1142015 - Test service worker post message source </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script class="testbody" type="text/javascript">
var magic_value = "MAGIC_VALUE_RANDOM";
var registration;
function start() {
return navigator.serviceWorker.register("source_message_posting_worker.js",
{ scope: "./nonexistent_scope/" })
.then((swr) => registration = swr);
}
function unregister() {
return registration.unregister().then(function(result) {
ok(result, "Unregister should return true.");
});
}
function testPostMessage(swr) {
var p = new Promise(function(res, rej) {
navigator.serviceWorker.onmessage = function(e) {
ok(e.data === magic_value, "Worker posted the correct value.");
res();
}
});
ok(swr.installing, "Installing worker exists.");
swr.installing.postMessage(magic_value);
return p;
}
function runTest() {
start()
.then(testPostMessage)
.then(unregister)
.catch(function(e) {
ok(false, "Some test failed with error " + e);
}).then(SimpleTest.finish);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true]
]}, runTest);
</script>
</pre>
</body>
</html>