Bug 1205112 - Make `PushEvent.data` nullable. r=mt,smaug
authorKit Cambridge <kcambridge@mozilla.com>
Thu, 17 Sep 2015 05:13:04 -0700
changeset 297699 9fafe1d5f32c636106e3adf3d9dd17e41779f7b0
parent 297698 a39aa7c8e1ee5ed2d5e4c7de4a50f5d1da96ba85
child 297700 02d5b9e9a3486b5dfcfa4db774db0aae5307e211
push id962
push userjlund@mozilla.com
push dateFri, 04 Dec 2015 23:28:54 +0000
treeherdermozilla-release@23a2d286e80f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmt, smaug
bugs1205112
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1205112 - Make `PushEvent.data` nullable. r=mt,smaug
dom/interfaces/base/nsIServiceWorkerManager.idl
dom/push/PushServiceChildPreload.jsm
dom/push/test/test_data.html
dom/webidl/PushEvent.webidl
dom/workers/ServiceWorkerEvents.h
dom/workers/ServiceWorkerManager.cpp
--- a/dom/interfaces/base/nsIServiceWorkerManager.idl
+++ b/dom/interfaces/base/nsIServiceWorkerManager.idl
@@ -29,17 +29,17 @@ interface nsIServiceWorkerInfo : nsISupp
   readonly attribute DOMString scope;
   readonly attribute DOMString scriptSpec;
   readonly attribute DOMString currentWorkerURL;
 
   readonly attribute DOMString activeCacheName;
   readonly attribute DOMString waitingCacheName;
 };
 
-[scriptable, builtinclass, uuid(02d52950-f311-42c7-b573-fd3a2c5d3210)]
+[scriptable, builtinclass, uuid(471b2d5d-64c3-4dea-bde1-219853dcaac8)]
 interface nsIServiceWorkerManager : nsISupports
 {
   /**
    * Registers a ServiceWorker with script loaded from `aScriptURI` to act as
    * the ServiceWorker for aScope.  Requires a valid entry settings object on
    * the stack. This means you must call this from content code 'within'
    * a window.
    *
@@ -136,20 +136,20 @@ interface nsIServiceWorkerManager : nsIS
                                   in AString aTitle,
                                   in AString aDir,
                                   in AString aLang,
                                   in AString aBody,
                                   in AString aTag,
                                   in AString aIcon,
                                   in AString aData,
                                   in AString aBehavior);
-  void sendPushEvent(in ACString aOriginAttributes,
-                     in ACString aScope,
-                     in uint32_t aDataLength,
-                     [array, size_is(aDataLength)] in uint8_t aDataBytes);
+  [optional_argc] void sendPushEvent(in ACString aOriginAttributes,
+                                     in ACString aScope,
+                                     [optional] in uint32_t aDataLength,
+                                     [optional, array, size_is(aDataLength)] in uint8_t aDataBytes);
   void sendPushSubscriptionChangeEvent(in ACString aOriginAttributes,
                                        in ACString scope);
 
   void updateAllRegistrations();
 };
 
 %{ C++
 #define SERVICEWORKERMANAGER_CONTRACTID "@mozilla.org/serviceworkers/manager;1"
--- a/dom/push/PushServiceChildPreload.jsm
+++ b/dom/push/PushServiceChildPreload.jsm
@@ -18,22 +18,22 @@ XPCOMUtils.defineLazyServiceGetter(this,
                                    "@mozilla.org/serviceworkers/manager;1",
                                    "nsIServiceWorkerManager");
 
 var processType = Cc["@mozilla.org/xre/app-info;1"]
                     .getService(Ci.nsIXULRuntime).processType;
 var isParent = processType === Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
 
 Services.cpmm.addMessageListener("push", function (aMessage) {
-  let {payload} = aMessage.data;
-  let length = payload ? payload.length : 0;
-  swm.sendPushEvent(aMessage.data.originAttributes,
-                    aMessage.data.scope,
-                    length,
-                    payload);
+  let {originAttributes, scope, payload} = aMessage.data;
+  if (payload) {
+    swm.sendPushEvent(originAttributes, scope, payload.length, payload);
+  } else {
+    swm.sendPushEvent(originAttributes, scope);
+  }
 });
 
 Services.cpmm.addMessageListener("pushsubscriptionchange", function (aMessage) {
   swm.sendPushSubscriptionChangeEvent(aMessage.data.originAttributes,
                                       aMessage.data.scope);
 });
 
 if (!isParent) {
--- a/dom/push/test/test_data.html
+++ b/dom/push/test/test_data.html
@@ -127,16 +127,30 @@ http://creativecommons.org/licenses/publ
             } else {
               resolve(reader.result);
             }
           };
           reader.readAsText(message.data.blob);
         });
       }).then(text => {
         is(text, "Hi! \ud83d\udc40", "Wrong blob data for message with emoji");
+        is(text, "Hi! \ud83d\udc40", "Wrong blob data for message with emoji");
+        // Send a blank message.
+        return Promise.all([
+          controlledFrame.contentWindow.waitOnPushMessage(pushSubscription),
+          fetch("http://mochi.test:8888/tests/dom/push/test/push-server.sjs", {
+            method: "PUT",
+            headers: {
+              "X-Push-Method": "POST",
+              "X-Push-Server": pushSubscription.endpoint,
+            },
+          }),
+        ]).then(([message]) => message);
+      }).then(message => {
+        ok(!message.data, "Should exclude data for blank messages");
         return pushSubscription;
       });
   }
 
   function unsubscribe(pushSubscription) {
     controlledFrame.parentNode.removeChild(controlledFrame);
     controlledFrame = null;
     return pushSubscription.unsubscribe();
--- a/dom/webidl/PushEvent.webidl
+++ b/dom/webidl/PushEvent.webidl
@@ -6,16 +6,16 @@
  * The origin of this IDL file is
  * https://w3c.github.io/push-api/
  */
 
 [Constructor(DOMString type, optional PushEventInit eventInitDict),
  Func="nsContentUtils::PushEnabled",
  Exposed=ServiceWorker]
 interface PushEvent : ExtendableEvent {
-  readonly attribute PushMessageData data;
+  readonly attribute PushMessageData? data;
 };
 
 typedef (BufferSource or USVString) PushMessageDataInit;
 
 dictionary PushEventInit : ExtendableEventInit {
   PushMessageDataInit data;
 };
--- a/dom/workers/ServiceWorkerEvents.h
+++ b/dom/workers/ServiceWorkerEvents.h
@@ -235,17 +235,17 @@ public:
     return Constructor(owner, aType, aOptions, aRv);
   }
 
   void PostInit(nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker)
   {
     mServiceWorker = aServiceWorker;
   }
 
-  PushMessageData* Data()
+  PushMessageData* GetData() const
   {
     return mData;
   }
 };
 #endif /* ! MOZ_SIMPLEPUSH */
 
 END_WORKERS_NAMESPACE
 #endif /* mozilla_dom_workers_serviceworkerevents_h__ */
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -2292,45 +2292,49 @@ public:
     return NS_OK;
   }
 };
 
 #ifndef MOZ_SIMPLEPUSH
 
 class SendPushEventRunnable final : public WorkerRunnable
 {
-  nsTArray<uint8_t> mData;
+  Maybe<nsTArray<uint8_t>> mData;
   nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
 
 public:
   SendPushEventRunnable(
     WorkerPrivate* aWorkerPrivate,
+    nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker)
+      : SendPushEventRunnable(aWorkerPrivate, aServiceWorker,
+                              Nothing()) {}
+
+  SendPushEventRunnable(
+    WorkerPrivate* aWorkerPrivate,
     const nsTArray<uint8_t>& aData,
     nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker)
-      : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
-      , mData(aData)
-      , mServiceWorker(aServiceWorker)
-  {
-    AssertIsOnMainThread();
-    MOZ_ASSERT(aWorkerPrivate);
-    MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
-  }
+      : SendPushEventRunnable(aWorkerPrivate, aServiceWorker,
+                              Some(aData)) {}
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
     MOZ_ASSERT(aWorkerPrivate);
     GlobalObject globalObj(aCx, aWorkerPrivate->GlobalScope()->GetWrapper());
 
-    JSObject* data = Uint8Array::Create(aCx, mData.Length(), mData.Elements());
-    if (!data) {
-      return false;
+
+    PushEventInit pei;
+    if (mData) {
+      const nsTArray<uint8_t>& bytes = mData.ref();
+      JSObject* data = Uint8Array::Create(aCx, bytes.Length(), bytes.Elements());
+      if (!data) {
+        return false;
+      }
+      pei.mData.Construct().SetAsArrayBufferView().Init(data);
     }
-    PushEventInit pei;
-    pei.mData.Construct().SetAsArrayBufferView().Init(data);
     pei.mBubbles = false;
     pei.mCancelable = false;
 
     ErrorResult result;
     nsRefPtr<PushEvent> event =
       PushEvent::Constructor(globalObj, NS_LITERAL_STRING("push"), pei, result);
     if (NS_WARN_IF(result.Failed())) {
       result.SuppressException();
@@ -2344,16 +2348,30 @@ public:
       DispatchExtendableEventOnWorkerScope(aCx, aWorkerPrivate->GlobalScope(), event);
     if (waitUntilPromise) {
       nsRefPtr<KeepAliveHandler> handler = new KeepAliveHandler(mServiceWorker);
       waitUntilPromise->AppendNativeHandler(handler);
     }
 
     return true;
   }
+
+private:
+  SendPushEventRunnable(
+    WorkerPrivate* aWorkerPrivate,
+    nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker,
+    Maybe<nsTArray<uint8_t>> aData)
+      : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
+      , mData(aData)
+      , mServiceWorker(aServiceWorker)
+  {
+    AssertIsOnMainThread();
+    MOZ_ASSERT(aWorkerPrivate);
+    MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
+  }
 };
 
 class SendPushSubscriptionChangeEventRunnable final : public WorkerRunnable
 {
   nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
 
 public:
   SendPushSubscriptionChangeEventRunnable(
@@ -2390,17 +2408,18 @@ public:
 };
 
 #endif /* ! MOZ_SIMPLEPUSH */
 
 NS_IMETHODIMP
 ServiceWorkerManager::SendPushEvent(const nsACString& aOriginAttributes,
                                     const nsACString& aScope,
                                     uint32_t aDataLength,
-                                    uint8_t* aDataBytes)
+                                    uint8_t* aDataBytes,
+                                    uint8_t optional_argc)
 {
 #ifdef MOZ_SIMPLEPUSH
   return NS_ERROR_NOT_AVAILABLE;
 #else
   OriginAttributes attrs;
   if (!attrs.PopulateFromSuffix(aOriginAttributes)) {
     return NS_ERROR_INVALID_ARG;
   }
@@ -2409,24 +2428,29 @@ ServiceWorkerManager::SendPushEvent(cons
     CreateServiceWorkerForScope(attrs, aScope, nullptr /* failure runnable */);
   if (NS_WARN_IF(!serviceWorker)) {
     return NS_ERROR_FAILURE;
   }
 
   nsMainThreadPtrHandle<ServiceWorker> serviceWorkerHandle(
     new nsMainThreadPtrHolder<ServiceWorker>(serviceWorker));
 
-  nsTArray<uint8_t> data;
-  if (!data.InsertElementsAt(0, aDataBytes, aDataLength, fallible)) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  nsRefPtr<SendPushEventRunnable> r =
-    new SendPushEventRunnable(serviceWorker->GetWorkerPrivate(), data,
-                              serviceWorkerHandle);
+  nsRefPtr<SendPushEventRunnable> r;
+  if (optional_argc == 2) {
+    nsTArray<uint8_t> data;
+    if (!data.InsertElementsAt(0, aDataBytes, aDataLength, fallible)) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+    r = new SendPushEventRunnable(serviceWorker->GetWorkerPrivate(), data,
+                                  serviceWorkerHandle);
+  } else {
+    MOZ_ASSERT(optional_argc == 0);
+    r = new SendPushEventRunnable(serviceWorker->GetWorkerPrivate(),
+                                  serviceWorkerHandle);
+  }
 
   AutoJSAPI jsapi;
   jsapi.Init();
   if (NS_WARN_IF(!r->Dispatch(jsapi.cx()))) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;