Bug 1207068 - Implement ExtendableMessageEvent interface. r=baku a=ritu
authordimi <dlee@mozilla.com>
Tue, 10 Nov 2015 14:31:41 +0800
changeset 305720 3f7cc875e92e16af8b707509125132294ad1e04f
parent 305719 3b528ca2a11a3cbb49046a2a84969791be638dff
child 305721 4e62acda19b73dfd211ada6a8beef4762d632ac0
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku, ritu
bugs1207068
milestone44.0a2
Bug 1207068 - Implement ExtendableMessageEvent interface. r=baku a=ritu
dom/bindings/Bindings.conf
dom/events/MessageEvent.cpp
dom/events/MessageEvent.h
dom/webidl/ExtendableMessageEvent.webidl
dom/webidl/MessageEvent.webidl
dom/webidl/moz.build
dom/workers/ServiceWorkerEvents.cpp
dom/workers/ServiceWorkerEvents.h
dom/workers/WorkerPrivate.cpp
dom/workers/test/serviceworkers/source_message_posting_worker.js
dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -485,16 +485,21 @@ DOMInterfaces = {
 },
 
 'ExtendableEvent': {
     'headerFile': 'mozilla/dom/ServiceWorkerEvents.h',
     'nativeType': 'mozilla::dom::workers::ExtendableEvent',
     'implicitJSContext': [ 'waitUntil' ],
 },
 
+'ExtendableMessageEvent': {
+    'headerFile': 'mozilla/dom/ServiceWorkerEvents.h',
+    'nativeType': 'mozilla::dom::workers::ExtendableMessageEvent',
+},
+
 'FetchEvent': {
     'headerFile': 'ServiceWorkerEvents.h',
     'nativeType': 'mozilla::dom::workers::FetchEvent',
     'binaryNames': {
         'request': 'request_'
     },
     'implicitJSContext': [ 'respondWith' ],
 },
--- a/dom/events/MessageEvent.cpp
+++ b/dom/events/MessageEvent.cpp
@@ -9,19 +9,16 @@
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/MessagePortBinding.h"
 #include "mozilla/dom/MessagePortList.h"
 
 #include "mozilla/HoldDropJSObjects.h"
 #include "jsapi.h"
 #include "nsGlobalWindow.h" // So we can assign an nsGlobalWindow* to mWindowSource
 
-#include "ServiceWorker.h"
-#include "ServiceWorkerClient.h"
-
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(MessageEvent)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessageEvent, Event)
   tmp->mData.setUndefined();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindowSource)
@@ -102,24 +99,22 @@ MessageEvent::GetLastEventId(nsAString& 
 NS_IMETHODIMP
 MessageEvent::GetSource(nsIDOMWindow** aSource)
 {
   NS_IF_ADDREF(*aSource = mWindowSource);
   return NS_OK;
 }
 
 void
-MessageEvent::GetSource(Nullable<OwningWindowProxyOrMessagePortOrClient>& aValue) const
+MessageEvent::GetSource(Nullable<OwningWindowProxyOrMessagePort>& aValue) const
 {
   if (mWindowSource) {
     aValue.SetValue().SetAsWindowProxy() = mWindowSource;
   } else if (mPortSource) {
     aValue.SetValue().SetAsMessagePort() = mPortSource;
-  } else if (mClientSource) {
-    aValue.SetValue().SetAsClient() = mClientSource;
   }
 }
 
 /* static */ already_AddRefed<MessageEvent>
 MessageEvent::Constructor(const GlobalObject& aGlobal,
                           const nsAString& aType,
                           const MessageEventInit& aParam,
                           ErrorResult& aRv)
@@ -250,22 +245,16 @@ MessageEvent::SetPorts(MessagePortList* 
 }
 
 void
 MessageEvent::SetSource(mozilla::dom::MessagePort* aPort)
 {
   mPortSource = aPort;
 }
 
-void
-MessageEvent::SetSource(mozilla::dom::workers::ServiceWorkerClient* aClient)
-{
-  mClientSource = aClient;
-}
-
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 already_AddRefed<MessageEvent>
 NS_NewDOMMessageEvent(EventTarget* aOwner,
--- a/dom/events/MessageEvent.h
+++ b/dom/events/MessageEvent.h
@@ -14,25 +14,19 @@
 #include "nsIDOMMessageEvent.h"
 
 namespace mozilla {
 namespace dom {
 
 struct MessageEventInit;
 class MessagePort;
 class MessagePortList;
-class OwningWindowProxyOrMessagePortOrClient;
+class OwningWindowProxyOrMessagePort;
 class WindowProxyOrMessagePort;
 
-namespace workers {
-
-class ServiceWorkerClient;
-
-} // namespace workers
-
 /**
  * Implements the MessageEvent event, used for cross-document messaging and
  * server-sent events.
  *
  * See http://www.whatwg.org/specs/web-apps/current-work/#messageevent for
  * further details.
  */
 class MessageEvent final : public Event,
@@ -51,30 +45,28 @@ public:
   // Forward to base class
   NS_FORWARD_TO_EVENT
 
   virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   void GetData(JSContext* aCx, JS::MutableHandle<JS::Value> aData,
                ErrorResult& aRv);
 
-  void GetSource(Nullable<OwningWindowProxyOrMessagePortOrClient>& aValue) const;
+  void GetSource(Nullable<OwningWindowProxyOrMessagePort>& aValue) const;
 
   MessagePortList* GetPorts()
   {
     return mPorts;
   }
 
   void SetPorts(MessagePortList* aPorts);
 
   // Non WebIDL methods
   void SetSource(mozilla::dom::MessagePort* aPort);
 
-  void SetSource(workers::ServiceWorkerClient* aClient);
-
   void SetSource(nsPIDOMWindow* aWindow)
   {
     mWindowSource = aWindow;
   }
 
   static already_AddRefed<MessageEvent>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aType,
@@ -98,17 +90,16 @@ protected:
   ~MessageEvent();
 
 private:
   JS::Heap<JS::Value> mData;
   nsString mOrigin;
   nsString mLastEventId;
   nsCOMPtr<nsIDOMWindow> mWindowSource;
   RefPtr<MessagePort> mPortSource;
-  RefPtr<workers::ServiceWorkerClient> mClientSource;
   RefPtr<MessagePortList> mPorts;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 already_AddRefed<mozilla::dom::MessageEvent>
 NS_NewDOMMessageEvent(mozilla::dom::EventTarget* aOwner,
new file mode 100644
--- /dev/null
+++ b/dom/webidl/ExtendableMessageEvent.webidl
@@ -0,0 +1,43 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * For more information on this interface, please see
+ * http://www.whatwg.org/specs/web-apps/current-work/#messageevent
+ */
+
+[Constructor(DOMString type, optional ExtendableMessageEventInit eventInitDict),
+ Exposed=(ServiceWorker)]
+interface ExtendableMessageEvent : ExtendableEvent {
+  /**
+   * Custom data associated with this event.
+   */
+  [GetterThrows]
+  readonly attribute any data;
+
+  /**
+   * The origin of the site from which this event originated.
+   */
+  readonly attribute DOMString origin;
+
+  /**
+   * The last event ID string of the event source.
+   */
+  readonly attribute DOMString lastEventId;
+
+  /**
+   * The client, service worker or port which originated this event.
+   */
+  readonly attribute (Client or ServiceWorker or MessagePort)? source;
+
+  readonly attribute MessagePortList? ports;
+};
+
+dictionary ExtendableMessageEventInit : ExtendableEventInit {
+  any data;
+  DOMString origin = "";
+  DOMString lastEventId = "";
+  (Client or ServiceWorker or MessagePort)? source;
+  sequence<MessagePort>? ports;
+};
--- a/dom/webidl/MessageEvent.webidl
+++ b/dom/webidl/MessageEvent.webidl
@@ -26,22 +26,19 @@ interface MessageEvent : Event {
 
   /**
    * The last event ID string of the event source, for server-sent DOM events; this
    * value is the empty string for cross-origin messaging.
    */
   readonly attribute DOMString lastEventId;
 
   /**
-   * 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
+   * The window or port which originated this event.
    */
-  readonly attribute (WindowProxy or MessagePort or Client)? source;
+  readonly attribute (WindowProxy or MessagePort)? source;
 
   /**
    * Initializes this event with the given data, in a manner analogous to
    * the similarly-named method on the nsIDOMEvent interface, also setting the
    * data, origin, source, and lastEventId attributes of this appropriately.
    */
   readonly attribute MessagePortList? ports;
 
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -143,16 +143,17 @@ WEBIDL_FILES = [
     'Element.webidl',
     'EngineeringMode.webidl',
     'Event.webidl',
     'EventHandler.webidl',
     'EventListener.webidl',
     'EventSource.webidl',
     'EventTarget.webidl',
     'ExtendableEvent.webidl',
+    'ExtendableMessageEvent.webidl',
     'FakePluginTagInit.webidl',
     'Fetch.webidl',
     'FetchEvent.webidl',
     'File.webidl',
     'FileList.webidl',
     'FileMode.webidl',
     'FileReader.webidl',
     'FileReaderSync.webidl',
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -20,16 +20,18 @@
 #include "nsSerializationHelper.h"
 #include "nsQueryObject.h"
 
 #include "mozilla/ErrorResult.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/DOMException.h"
 #include "mozilla/dom/DOMExceptionBinding.h"
 #include "mozilla/dom/FetchEventBinding.h"
+#include "mozilla/dom/MessagePort.h"
+#include "mozilla/dom/MessagePortList.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/Request.h"
 #include "mozilla/dom/Response.h"
 #include "mozilla/dom/WorkerScope.h"
 #include "mozilla/dom/workers/bindings/ServiceWorker.h"
 
 #ifndef MOZ_SIMPLEPUSH
 #include "nsIUnicodeDecoder.h"
@@ -1076,9 +1078,154 @@ NS_IMPL_RELEASE_INHERITED(PushEvent, Ext
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PushEvent)
 NS_INTERFACE_MAP_END_INHERITING(ExtendableEvent)
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(PushEvent, ExtendableEvent, mData)
 
 #endif /* ! MOZ_SIMPLEPUSH */
 
+ExtendableMessageEvent::ExtendableMessageEvent(EventTarget* aOwner)
+  : ExtendableEvent(aOwner)
+  , mData(JS::UndefinedValue())
+{
+  mozilla::HoldJSObjects(this);
+}
+
+ExtendableMessageEvent::~ExtendableMessageEvent()
+{
+  mData.setUndefined();
+  DropJSObjects(this);
+}
+
+void
+ExtendableMessageEvent::GetData(JSContext* aCx,
+                                JS::MutableHandle<JS::Value> aData,
+                                ErrorResult& aRv)
+{
+  JS::ExposeValueToActiveJS(mData);
+  aData.set(mData);
+  if (!JS_WrapValue(aCx, aData)) {
+    aRv.Throw(NS_ERROR_FAILURE);
+  }
+}
+
+void
+ExtendableMessageEvent::GetSource(Nullable<OwningClientOrServiceWorkerOrMessagePort>& aValue) const
+{
+  if (mClient) {
+    aValue.SetValue().SetAsClient() = mClient;
+  } else if (mServiceWorker) {
+    aValue.SetValue().SetAsServiceWorker() = mServiceWorker;
+  } else if (mMessagePort) {
+    aValue.SetValue().SetAsMessagePort() = mMessagePort;
+  } else {
+    MOZ_CRASH("Unexpected source value");
+  }
+}
+
+/* static */ already_AddRefed<ExtendableMessageEvent>
+ExtendableMessageEvent::Constructor(const GlobalObject& aGlobal,
+                                    const nsAString& aType,
+                                    const ExtendableMessageEventInit& aOptions,
+                                    ErrorResult& aRv)
+{
+  nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
+  return Constructor(t, aType, aOptions, aRv);
+}
+
+/* static */ already_AddRefed<ExtendableMessageEvent>
+ExtendableMessageEvent::Constructor(mozilla::dom::EventTarget* aEventTarget,
+                                    const nsAString& aType,
+                                    const ExtendableMessageEventInit& aOptions,
+                                    ErrorResult& aRv)
+{
+  RefPtr<ExtendableMessageEvent> event = new ExtendableMessageEvent(aEventTarget);
+
+  aRv = event->InitEvent(aType, aOptions.mBubbles, aOptions.mCancelable);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
+  bool trusted = event->Init(aEventTarget);
+  event->SetTrusted(trusted);
+
+  event->mData = aOptions.mData;
+  event->mOrigin = aOptions.mOrigin;
+  event->mLastEventId = aOptions.mLastEventId;
+
+  if (aOptions.mSource.WasPassed() && !aOptions.mSource.Value().IsNull()) {
+    if (aOptions.mSource.Value().Value().IsClient()) {
+      event->mClient = aOptions.mSource.Value().Value().GetAsClient();
+    } else if (aOptions.mSource.Value().Value().IsServiceWorker()){
+      event->mServiceWorker = aOptions.mSource.Value().Value().GetAsServiceWorker();
+    } else if (aOptions.mSource.Value().Value().IsServiceWorker()){
+      event->mMessagePort = aOptions.mSource.Value().Value().GetAsMessagePort();
+    }
+    MOZ_ASSERT(event->mClient || event->mServiceWorker || event->mMessagePort);
+  }
+
+  if (aOptions.mPorts.WasPassed() && !aOptions.mPorts.Value().IsNull()) {
+    nsTArray<RefPtr<MessagePort>> ports;
+    const Sequence<OwningNonNull<MessagePort>>& portsParam =
+      aOptions.mPorts.Value().Value();
+    for (uint32_t i = 0, len = portsParam.Length(); i < len; ++i) {
+      ports.AppendElement(portsParam[i].get());
+    }
+    event->mPorts = new MessagePortList(static_cast<EventBase*>(event), ports);
+  }
+
+  return event.forget();
+}
+
+MessagePortList*
+ExtendableMessageEvent::GetPorts() const
+{
+  return mPorts;
+}
+
+void
+ExtendableMessageEvent::SetPorts(MessagePortList* aPorts)
+{
+  MOZ_ASSERT(!mPorts && aPorts);
+  mPorts = aPorts;
+}
+
+void
+ExtendableMessageEvent::SetSource(ServiceWorkerClient* aClient)
+{
+  mClient = aClient;
+}
+
+void
+ExtendableMessageEvent::SetSource(ServiceWorker* aServiceWorker)
+{
+  mServiceWorker = aServiceWorker;
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(ExtendableMessageEvent)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ExtendableMessageEvent, Event)
+  tmp->mData.setUndefined();
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mClient)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mServiceWorker)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessagePort)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPorts)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ExtendableMessageEvent, Event)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClient)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorker)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessagePort)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPorts)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ExtendableMessageEvent, Event)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mData)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ExtendableMessageEvent)
+NS_INTERFACE_MAP_END_INHERITING(Event)
+
+NS_IMPL_ADDREF_INHERITED(ExtendableMessageEvent, Event)
+NS_IMPL_RELEASE_INHERITED(ExtendableMessageEvent, Event)
+
 END_WORKERS_NAMESPACE
--- a/dom/workers/ServiceWorkerEvents.h
+++ b/dom/workers/ServiceWorkerEvents.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_workers_serviceworkerevents_h__
 #define mozilla_dom_workers_serviceworkerevents_h__
 
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/ExtendableEventBinding.h"
+#include "mozilla/dom/ExtendableMessageEventBinding.h"
 #include "mozilla/dom/FetchEventBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/Response.h"
 #include "mozilla/dom/workers/bindings/ServiceWorker.h"
 
 #ifndef MOZ_SIMPLEPUSH
 #include "mozilla/dom/PushEventBinding.h"
 #include "mozilla/dom/PushMessageDataBinding.h"
@@ -23,16 +24,18 @@
 #include "nsProxyRelease.h"
 #include "nsContentUtils.h"
 
 class nsIInterceptedChannel;
 
 namespace mozilla {
 namespace dom {
 class Blob;
+class MessagePort;
+class MessagePortList;
 class Request;
 class ResponseOrPromise;
 } // namespace dom
 } // namespace mozilla
 
 BEGIN_WORKERS_NAMESPACE
 
 class CancelChannelRunnable final : public nsRunnable
@@ -241,10 +244,76 @@ public:
   PushMessageData*
   GetData() const
   {
     return mData;
   }
 };
 #endif /* ! MOZ_SIMPLEPUSH */
 
+class ExtendableMessageEvent final : public ExtendableEvent
+{
+  JS::Heap<JS::Value> mData;
+  nsString mOrigin;
+  nsString mLastEventId;
+  RefPtr<ServiceWorkerClient> mClient;
+  RefPtr<ServiceWorker> mServiceWorker;
+  RefPtr<MessagePort> mMessagePort;
+  RefPtr<MessagePortList> mPorts;
+
+protected:
+  explicit ExtendableMessageEvent(EventTarget* aOwner);
+  ~ExtendableMessageEvent();
+
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ExtendableMessageEvent,
+                                                         ExtendableEvent)
+
+  NS_FORWARD_TO_EVENT
+
+  virtual JSObject* WrapObjectInternal(
+    JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
+  {
+    return mozilla::dom::ExtendableMessageEventBinding::Wrap(aCx, this, aGivenProto);
+  }
+
+  static already_AddRefed<ExtendableMessageEvent>
+  Constructor(mozilla::dom::EventTarget* aOwner,
+              const nsAString& aType,
+              const ExtendableMessageEventInit& aOptions,
+              ErrorResult& aRv);
+
+  static already_AddRefed<ExtendableMessageEvent>
+  Constructor(const GlobalObject& aGlobal,
+              const nsAString& aType,
+              const ExtendableMessageEventInit& aOptions,
+              ErrorResult& aRv);
+
+  void GetData(JSContext* aCx, JS::MutableHandle<JS::Value> aData,
+               ErrorResult& aRv);
+
+  void GetSource(Nullable<OwningClientOrServiceWorkerOrMessagePort>& aValue) const;
+
+  NS_IMETHOD GetOrigin(nsAString& aOrigin)
+  {
+    aOrigin = mOrigin;
+    return NS_OK;
+  }
+
+  NS_IMETHOD GetLastEventId(nsAString& aLastEventId)
+  {
+    aLastEventId = mLastEventId;
+    return NS_OK;
+  }
+
+  MessagePortList* GetPorts() const;
+
+  void SetPorts(MessagePortList* aPorts);
+
+  void SetSource(ServiceWorkerClient* aClient);
+
+  void SetSource(ServiceWorker* aServiceWorker);
+};
+
 END_WORKERS_NAMESPACE
+
 #endif /* mozilla_dom_workers_serviceworkerevents_h__ */
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -664,41 +664,63 @@ public:
       timelines->AddMarkerForAllObservedDocShells(end);
     }
 
     if (NS_WARN_IF(rv.Failed())) {
       xpc::Throw(aCx, rv.StealNSResult());
       return false;
     }
 
-    RefPtr<MessageEvent> event = new MessageEvent(aTarget, nullptr, nullptr);
-    rv = event->InitMessageEvent(NS_LITERAL_STRING("message"),
-                                 false /* non-bubbling */,
-                                 false /* cancelable */,
-                                 messageData,
-                                 EmptyString(),
-                                 EmptyString(),
-                                 nullptr);
+    nsTArray<RefPtr<MessagePort>> ports = TakeTransferredPorts();
+
+    nsCOMPtr<nsIDOMEvent> domEvent;
+    // For messages dispatched to service worker, use ExtendableMessageEvent
+    // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#extendablemessage-event-section
     if (mEventSource) {
       RefPtr<ServiceWorkerClient> client =
         new ServiceWorkerWindowClient(aTarget, *mEventSource);
+
+      RootedDictionary<ExtendableMessageEventInit> init(aCx);
+
+      init.mBubbles = false;
+      init.mCancelable = false;
+
+      init.mData = messageData;
+      init.mPorts.Construct();
+      init.mPorts.Value().SetNull();
+
+      ErrorResult rv;
+      RefPtr<ExtendableMessageEvent> event = ExtendableMessageEvent::Constructor(
+        aTarget, NS_LITERAL_STRING("message"), init, rv);
+      if (NS_WARN_IF(rv.Failed())) {
+        return false;
+      }
       event->SetSource(client);
-    }
-
-    if (NS_WARN_IF(rv.Failed())) {
-      xpc::Throw(aCx, rv.StealNSResult());
-      return false;
-    }
-
-    nsTArray<RefPtr<MessagePort>> ports = TakeTransferredPorts();
-
-    event->SetTrusted(true);
-    event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
-                                        ports));
-    nsCOMPtr<nsIDOMEvent> domEvent = do_QueryObject(event);
+      event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
+                                          ports));
+      domEvent = do_QueryObject(event);
+    } else {
+      RefPtr<MessageEvent> event = new MessageEvent(aTarget, nullptr, nullptr);
+      nsresult rv = event->InitMessageEvent(NS_LITERAL_STRING("message"),
+                                            false /* non-bubbling */,
+                                            false /* cancelable */,
+                                            messageData,
+                                            EmptyString(),
+                                            EmptyString(),
+                                            nullptr);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        xpc::Throw(aCx, rv);
+        return false;
+      }
+      event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
+                                          ports));
+      domEvent = do_QueryObject(event);
+    }
+
+    domEvent->SetTrusted(true);
 
     nsEventStatus dummy = nsEventStatus_eIgnore;
     aTarget->DispatchDOMEvent(nullptr, domEvent, nullptr, &dummy);
     return true;
   }
 
 private:
   virtual bool
--- a/dom/workers/test/serviceworkers/source_message_posting_worker.js
+++ b/dom/workers/test/serviceworkers/source_message_posting_worker.js
@@ -1,12 +1,16 @@
 onmessage = function(e) {
   if (!e.source) {
     dump("ERROR: message doesn't have a source.");
   }
 
+  if (!(e instanceof ExtendableMessageEvent)) {
+    e.source.postMessage("ERROR. event is not an extendable message event.");
+  }
+
   // 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.");
   }
 };
--- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
+++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
@@ -113,16 +113,18 @@ var interfaceNamesInGlobalScope =
     "DOMStringList",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Event",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "EventTarget",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ExtendableEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    "ExtendableMessageEvent",
+// IMPORTANT: Do not change this list without review from a DOM peer!
     "FetchEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "File",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "FileReaderSync",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "FormData",
 // IMPORTANT: Do not change this list without review from a DOM peer!