Backed out changeset 98c7277a8fb5 (bug 1166350) for xpcshell failures.
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 24 Jun 2015 16:10:45 -0400
changeset 280933 c0ab4a5c0acfe873aecdaa966302e6aa3fe310ea
parent 280932 44002ebe4e2cf60cc69e1f0bf1388172b87c1836
child 280934 71457f81430af5b0599c8b620394747ff1576a7c
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1166350
milestone41.0a1
backs out98c7277a8fb58539508970911f7835ce77ce342f
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
Backed out changeset 98c7277a8fb5 (bug 1166350) for xpcshell failures.
dom/base/ChromeUtils.cpp
dom/base/ChromeUtils.h
dom/interfaces/base/nsIServiceWorkerManager.idl
dom/interfaces/push/nsIPushNotificationService.idl
dom/push/Push.js
dom/push/PushDB.jsm
dom/push/PushNotificationService.js
dom/push/PushService.jsm
dom/push/PushServiceHttp2.jsm
dom/push/PushServiceWebSocket.jsm
dom/push/test/test_multiple_register.html
dom/push/test/xpcshell/test_notification_ack.js
dom/push/test/xpcshell/test_notification_duplicate.js
dom/push/test/xpcshell/test_notification_error.js
dom/push/test/xpcshell/test_notification_version_string.js
dom/push/test/xpcshell/test_register_5xxCode_http2.js
dom/push/test/xpcshell/test_register_case.js
dom/push/test/xpcshell/test_register_flush.js
dom/push/test/xpcshell/test_register_invalid_channel.js
dom/push/test/xpcshell/test_register_invalid_endpoint.js
dom/push/test/xpcshell/test_register_invalid_json.js
dom/push/test/xpcshell/test_register_no_id.js
dom/push/test/xpcshell/test_register_request_queue.js
dom/push/test/xpcshell/test_register_rollback.js
dom/push/test/xpcshell/test_register_success.js
dom/push/test/xpcshell/test_register_timeout.js
dom/push/test/xpcshell/test_register_wrong_id.js
dom/push/test/xpcshell/test_register_wrong_type.js
dom/push/test/xpcshell/test_registration_error.js
dom/push/test/xpcshell/test_registration_error_http2.js
dom/push/test/xpcshell/test_registration_missing_scope.js
dom/push/test/xpcshell/test_registration_none.js
dom/push/test/xpcshell/test_registration_success.js
dom/push/test/xpcshell/test_unregister_empty_scope.js
dom/push/test/xpcshell/test_unregister_error.js
dom/push/test/xpcshell/test_unregister_invalid_json.js
dom/push/test/xpcshell/test_unregister_not_found.js
dom/push/test/xpcshell/test_unregister_success.js
dom/push/test/xpcshell/test_webapps_cleardata.js
dom/push/test/xpcshell/xpcshell.ini
dom/webidl/ChromeUtils.webidl
dom/webidl/PushSubscription.webidl
dom/workers/ServiceWorkerManager.cpp
toolkit/content/aboutServiceWorkers.js
--- a/dom/base/ChromeUtils.cpp
+++ b/dom/base/ChromeUtils.cpp
@@ -14,19 +14,10 @@ namespace dom {
 ChromeUtils::OriginAttributesToCookieJar(GlobalObject& aGlobal,
                                          const OriginAttributesDictionary& aAttrs,
                                          nsCString& aCookieJar)
 {
   OriginAttributes attrs(aAttrs);
   attrs.CookieJar(aCookieJar);
 }
 
-/* static */ void
-ChromeUtils::OriginAttributesToSuffix(dom::GlobalObject& aGlobal,
-                                      const dom::OriginAttributesDictionary& aAttrs,
-                                      nsCString& aSuffix)
-
-{
-  OriginAttributes attrs(aAttrs);
-  attrs.CreateSuffix(aSuffix);
-}
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/ChromeUtils.h
+++ b/dom/base/ChromeUtils.h
@@ -39,19 +39,14 @@ public:
 
 class ChromeUtils : public ThreadSafeChromeUtils
 {
 public:
   static void
   OriginAttributesToCookieJar(dom::GlobalObject& aGlobal,
                               const dom::OriginAttributesDictionary& aAttrs,
                               nsCString& aCookieJar);
-
-  static void
-  OriginAttributesToSuffix(dom::GlobalObject& aGlobal,
-                           const dom::OriginAttributesDictionary& aAttrs,
-                           nsCString& aSuffix);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_ChromeUtils__
--- a/dom/interfaces/base/nsIServiceWorkerManager.idl
+++ b/dom/interfaces/base/nsIServiceWorkerManager.idl
@@ -15,30 +15,30 @@ interface nsIURI;
 interface nsIServiceWorkerUnregisterCallback : nsISupports
 {
   // aState is true if the unregistration succeded.
   // It's false if this ServiceWorkerRegistration doesn't exist.
   void unregisterSucceeded(in bool aState);
   void unregisterFailed();
 };
 
-[scriptable, builtinclass, uuid(e633b73b-a734-4d04-a09c-b7779a439f3f)]
+[scriptable, builtinclass, uuid(103763c8-53ba-42e4-8b26-e601d5bc4afe)]
 interface nsIServiceWorkerInfo : nsISupports
 {
   readonly attribute nsIPrincipal principal;
 
   readonly attribute DOMString scope;
   readonly attribute DOMString scriptSpec;
   readonly attribute DOMString currentWorkerURL;
 
   readonly attribute DOMString activeCacheName;
   readonly attribute DOMString waitingCacheName;
 };
 
-[scriptable, builtinclass, uuid(e9abb123-0099-4d9e-85db-c8cd0aff19e6)]
+[scriptable, builtinclass, uuid(aee94712-9adb-4c0b-80a7-a8df34dfa2e8)]
 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.
    *
@@ -121,20 +121,20 @@ interface nsIServiceWorkerManager : nsIS
 
   // Note: This is meant to be used only by about:serviceworkers.
   // It calls unregister() in each child process. The callback is used to
   // inform when unregister() is completed on the current process.
   void propagateUnregister(in nsIPrincipal aPrincipal,
                            in nsIServiceWorkerUnregisterCallback aCallback,
                            in DOMString aScope);
 
-  void sendPushEvent(in ACString aOriginAttributes,
-                     in ACString aScope,
-                     in DOMString aData);
-  void sendPushSubscriptionChangeEvent(in ACString aOriginAttributes,
-                                       in ACString scope);
+  [implicit_jscontext] void sendPushEvent(in jsval aOriginAttributes,
+                                          in ACString aScope,
+                                          in DOMString aData);
+  [implicit_jscontext] void sendPushSubscriptionChangeEvent(in jsval aOriginAttributes,
+                                                            in ACString scope);
 
   void updateAllRegistrations();
 };
 
 %{ C++
 #define SERVICEWORKERMANAGER_CONTRACTID "@mozilla.org/serviceworkers/manager;1"
 %}
--- a/dom/interfaces/push/nsIPushNotificationService.idl
+++ b/dom/interfaces/push/nsIPushNotificationService.idl
@@ -6,17 +6,17 @@
 #include "nsISupports.idl"
 
 /**
  * A service for components to subscribe and receive push messages from web
  * services. This functionality is exposed to content via the Push API, which
  * uses service workers to notify applications. This interface exists to allow
  * privileged code to receive messages without migrating to service workers.
  */
-[scriptable, uuid(abde228b-7d14-4cab-b1f9-9f87750ede0f)]
+[scriptable, uuid(3da6a16c-69f8-4843-9149-1e89d58a53e2)]
 interface nsIPushNotificationService : nsISupports
 {
   /**
    * Creates a push subscription for the given |scope| URL and |pageURL|.
    * Returns a promise for the new subscription record, or the existing
    * record if this |scope| already has a subscription.
    *
    * The |pushEndpoint| property of the subscription record is a URL string
@@ -27,28 +27,28 @@ interface nsIPushNotificationService : n
    * notification, with an `nsIPushObserverNotification` as the subject and
    * the |scope| as the data.
    *
    * If the server drops a subscription, a `push-subscription-change` observer
    * will be fired, with the subject set to `null` and the data set to |scope|.
    * Servers may drop subscriptions at any time, so callers should recreate
    * subscriptions if desired.
    */
-  jsval register(in string scope, in jsval originAttributes);
+  jsval register(in string scope, [optional] in string pageURL);
 
   /**
    * Revokes a push subscription for the given |scope|. Returns a promise
    * for the revoked subscription record, or `null` if the |scope| is not
    * subscribed to receive notifications.
    */
-  jsval unregister(in string scope, in jsval originAttributes);
+  jsval unregister(in string scope);
 
   /**
    * Returns a promise for the subscription record associated with the
    * given |scope|, or `null` if the |scope| does not have a subscription.
    */
-  jsval registration(in string scope, in jsval originAttributes);
+  jsval registration(in string scope);
 
   /**
    * Clear all subscriptions
    */
    jsval clearAll();
 };
--- a/dom/push/Push.js
+++ b/dom/push/Push.js
@@ -18,21 +18,21 @@ const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
 Cu.import("resource://gre/modules/AppsUtils.jsm");
 
 const PUSH_SUBSCRIPTION_CID = Components.ID("{CA86B665-BEDA-4212-8D0F-5C9F65270B58}");
 
-function PushSubscription(pushEndpoint, scope, principal) {
+function PushSubscription(pushEndpoint, scope, pageURL) {
   debug("PushSubscription Constructor");
   this._pushEndpoint = pushEndpoint;
   this._scope = scope;
-  this._principal = principal;
+  this._pageURL = pageURL;
 }
 
 PushSubscription.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
 
   contractID: "@mozilla.org/push/PushSubscription;1",
 
   classID : PUSH_SUBSCRIPTION_CID,
@@ -48,38 +48,39 @@ PushSubscription.prototype = {
       "PushService:Unregister:OK",
       "PushService:Unregister:KO",
     ]);
 
     this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
                    .getService(Ci.nsISyncMessageSender);
   },
 
-  __init: function(endpoint, scope, principal) {
+  __init: function(endpoint, scope, pageURL) {
     this._pushEndpoint = endpoint;
     this._scope = scope;
-    this._principal = principal;
+    this._pageURL = pageURL;
   },
 
   get endpoint() {
     return this._pushEndpoint;
   },
 
   unsubscribe: function() {
     debug("unsubscribe! ")
 
     let promiseInit = function(resolve, reject) {
       let resolverId = this.getPromiseResolverId({resolve: resolve,
                                                   reject: reject });
 
       this._cpmm.sendAsyncMessage("Push:Unregister", {
+                                  pageURL: this._pageURL,
                                   scope: this._scope,
                                   pushEndpoint: this._pushEndpoint,
                                   requestID: resolverId
-                                }, null, this._principal);
+                                });
     }.bind(this);
 
     return this.createPromise(promiseInit);
   },
 
   receiveMessage: function(aMessage) {
     debug("push subscription receiveMessage(): " + JSON.stringify(aMessage))
 
@@ -127,43 +128,45 @@ Push.prototype = {
 
   init: function(aWindow) {
     // Set debug first so that all debugging actually works.
     // NOTE: We don't add an observer here like in PushService. Flipping the
     // pref will require a reload of the app/page, which seems acceptable.
     gDebuggingEnabled = Services.prefs.getBoolPref("dom.push.debug");
     debug("init()");
 
+    this._pageURL = aWindow.document.nodePrincipal.URI;
     this._window = aWindow;
 
     this.initDOMRequestHelper(aWindow, [
       "PushService:Register:OK",
       "PushService:Register:KO",
       "PushService:Registration:OK",
       "PushService:Registration:KO"
     ]);
 
     this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
                    .getService(Ci.nsISyncMessageSender);
-    this._principal = aWindow.document.nodePrincipal;
   },
 
   setScope: function(scope){
     debug('setScope ' + scope);
     this._scope = scope;
   },
 
   askPermission: function (aAllowCallback, aCancelCallback) {
     debug("askPermission");
 
     let principal = this._window.document.nodePrincipal;
     let type = "push";
     let permValue =
       Services.perms.testExactPermissionFromPrincipal(principal, type);
 
+    debug("Existing permission " + permValue);
+
     if (permValue == Ci.nsIPermissionManager.ALLOW_ACTION) {
         aAllowCallback();
       return;
     }
 
     if (permValue == Ci.nsIPermissionManager.DENY_ACTION) {
       aCancelCallback();
       return;
@@ -211,32 +214,31 @@ Push.prototype = {
 
     if (!resolver) {
       return;
     }
 
     switch (aMessage.name) {
       case "PushService:Register:OK":
       {
-        let subscription =
-          new this._window.PushSubscription(json.pushEndpoint, this._scope,
-                                            this._principal);
+        let subscription = new this._window.PushSubscription(json.pushEndpoint,
+                                                             this._scope,
+                                                             this._pageURL.spec);
         resolver.resolve(subscription);
         break;
       }
       case "PushService:Register:KO":
         resolver.reject(null);
         break;
       case "PushService:Registration:OK":
       {
         let subscription = null;
         try {
-          subscription =
-            new this._window.PushSubscription(json.registration.pushEndpoint,
-                                              this._scope, this._principal);
+          subscription = new this._window.PushSubscription(json.registration.pushEndpoint,
+                                                          this._scope, this._pageURL.spec);
         } catch(error) {
         }
         resolver.resolve(subscription);
         break;
       }
       case "PushService:Registration:KO":
         resolver.reject(null);
         break;
@@ -248,19 +250,20 @@ Push.prototype = {
   subscribe: function() {
     debug("subscribe()");
     let p = this.createPromise(function(resolve, reject) {
       let resolverId = this.getPromiseResolverId({ resolve: resolve, reject: reject });
 
       this.askPermission(
         function() {
           this._cpmm.sendAsyncMessage("Push:Register", {
+                                      pageURL: this._pageURL.spec,
                                       scope: this._scope,
                                       requestID: resolverId
-                                    }, null, this._principal);
+                                    });
         }.bind(this),
 
         function() {
           reject("PermissionDeniedError");
         }
       );
     }.bind(this));
     return p;
@@ -271,38 +274,36 @@ Push.prototype = {
 
     let p = this.createPromise(function(resolve, reject) {
 
       let resolverId = this.getPromiseResolverId({ resolve: resolve, reject: reject });
 
       this.askPermission(
         function() {
           this._cpmm.sendAsyncMessage("Push:Registration", {
+                                      pageURL: this._pageURL.spec,
                                       scope: this._scope,
                                       requestID: resolverId
-                                    }, null, this._principal);
+                                    });
         }.bind(this),
 
         function() {
           reject("PermissionDeniedError");
         }
       );
     }.bind(this));
     return p;
   },
 
   hasPermission: function() {
-    debug("hasPermission()" + this._scope);
+    debug("getSubscription()" + this._scope);
 
     let p = this.createPromise(function(resolve, reject) {
-      let permissionManager = Cc["@mozilla.org/permissionmanager;1"]
-                              .getService(Ci.nsIPermissionManager);
-      let permission =
-        permissionManager.testExactPermissionFromPrincipal(this._principal,
-                                                           "push");
+      let permissionManager = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
+      let permission = permissionManager.testExactPermission(this._pageURL, "push");
 
       let pushPermissionStatus = "default";
       if (permission == Ci.nsIPermissionManager.ALLOW_ACTION) {
         pushPermissionStatus = "granted";
       } else if (permission == Ci.nsIPermissionManager.DENY_ACTION) {
         pushPermissionStatus = "denied";
       }
       resolve(pushPermissionStatus);
--- a/dom/push/PushDB.jsm
+++ b/dom/push/PushDB.jsm
@@ -142,85 +142,47 @@ this.PushDB.prototype = {
           };
         },
         resolve,
         reject
       )
     );
   },
 
-  // Perform a unique match against { scope, originAttributes }
-  getByIdentifiers: function(aPageRecord) {
-    debug("getByIdentifiers() { " + aPageRecord.scope + ", " +
-          JSON.stringify(aPageRecord.originAttributes) + " }");
-    if (!aPageRecord.scope || aPageRecord.originAttributes == undefined) {
-      return Promise.reject(
-               new TypeError("Scope and originAttributes are required! " +
-                             JSON.stringify(aPageRecord)));
-    }
+
+  getByScope: function(aScope) {
+    debug("getByScope() " + aScope);
 
     return new Promise((resolve, reject) =>
       this.newTxn(
         "readonly",
         this._dbStoreName,
         function txnCb(aTxn, aStore) {
           aTxn.result = undefined;
 
-          let index = aStore.index("identifiers");
-          let request = index.get(IDBKeyRange.only([aPageRecord.scope, aPageRecord.originAttributes]));
-          request.onsuccess = function setTxnResult(aEvent) {
+          let index = aStore.index("scope");
+          index.get(aScope).onsuccess = function setTxnResult(aEvent) {
             aTxn.result = aEvent.target.result;
-          }
+            debug("Fetch successful " + aEvent.target.result);
+          };
         },
         resolve,
         reject
       )
     );
   },
 
-  _getAllByKey: function(aKeyName, aKeyValue) {
-    return new Promise((resolve, reject) =>
-      this.newTxn(
-        "readonly",
-        this._dbStoreName,
-        function txnCb(aTxn, aStore) {
-          aTxn.result = undefined;
-
-          let index = aStore.index(aKeyName);
-          // It seems ok to use getAll here, since unlike contacts or other
-          // high storage APIs, we don't expect more than a handful of
-          // registrations per domain, and usually only one.
-          let getAllReq = index.mozGetAll(aKeyValue);
-          getAllReq.onsuccess = function setTxnResult(aEvent) {
-            aTxn.result = aEvent.target.result;
-          }
-        },
-        resolve,
-        reject
-      )
-    );
-  },
-
-  // aOriginAttributes must be a string!
-  getAllByOriginAttributes: function(aOriginAttributes) {
-    if (typeof aOriginAttributes !== "string") {
-      return Promise.reject("Expected string!");
-    }
-    return this._getAllByKey("originAttributes", aOriginAttributes);
-  },
-
   getAllKeyIDs: function() {
     debug("getAllKeyIDs()");
 
     return new Promise((resolve, reject) =>
       this.newTxn(
         "readonly",
         this._dbStoreName,
         function txnCb(aTxn, aStore) {
-          aTxn.result = undefined;
           aStore.mozGetAll().onsuccess = function(event) {
             aTxn.result = event.target.result;
           };
         },
         resolve,
         reject
       )
     );
--- a/dom/push/PushNotificationService.js
+++ b/dom/push/PushNotificationService.js
@@ -33,26 +33,26 @@ PushNotificationService.prototype = {
 
   contractID: "@mozilla.org/push/NotificationService;1",
 
   _xpcom_factory: XPCOMUtils.generateSingletonFactory(PushNotificationService),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference,
                                          Ci.nsIPushNotificationService]),
 
-  register: function register(scope, originAttributes) {
-    return PushService._register({scope, originAttributes});
+  register: function register(scope, pageURL) {
+    return PushService._register({scope, pageURL});
   },
 
-  unregister: function unregister(scope, originAttributes) {
-    return PushService._unregister({scope, originAttributes});
+  unregister: function unregister(scope) {
+    return PushService._unregister({scope});
   },
 
-  registration: function registration(scope, originAttributes) {
-    return PushService._registration({scope, originAttributes});
+  registration: function registration(scope) {
+    return PushService._registration({scope});
   },
 
   clearAll: function clearAll() {
     return PushService._clearAll();
   },
 
   observe: function observe(subject, topic, data) {
     switch (topic) {
--- a/dom/push/PushService.jsm
+++ b/dom/push/PushService.jsm
@@ -111,36 +111,16 @@ this.PushService = {
     } else {
       return (this._activated) ? this._activated :
                                  this._activated = new Promise((res, rej) =>
                                    this._notifyActivated = {resolve: res,
                                                             reject: rej});
     }
   },
 
-  _makePendingKey: function(aPageRecord) {
-    return aPageRecord.scope + "|" + aPageRecord.originAttributes;
-  },
-
-  _lookupOrPutPendingRequest: function(aPageRecord) {
-    let key = this._makePendingKey(aPageRecord);
-    if (this._pendingRegisterRequest[key]) {
-      return this._pendingRegisterRequest[key];
-    }
-
-    return this._pendingRegisterRequest[key] = this._registerWithServer(aPageRecord);
-  },
-
-  _deletePendingRequest: function(aPageRecord) {
-    let key = this._makePendingKey(aPageRecord);
-    if (this._pendingRegisterRequest[key]) {
-      delete this._pendingRegisterRequest[key];
-    }
-  },
-
   _setState: function(aNewState) {
     debug("new state: " + aNewState + " old state: " + this._state);
 
     if (this._state == aNewState) {
       return;
     }
 
     if (this._state == PUSH_SERVICE_ACTIVATING) {
@@ -248,51 +228,34 @@ this.PushService = {
         let data = aSubject
                      .QueryInterface(Ci.mozIApplicationClearPrivateDataParams);
         if (!data) {
           debug("webapps-clear-data: Failed to get information about " +
                 "application");
           return;
         }
 
-        var originAttributes =
-          ChromeUtils.originAttributesToSuffix({ appId: data.appId,
-                                                 inBrowser: data.browserOnly });
-        this._db.getAllByOriginAttributes(originAttributes)
-          .then(records => {
-            records.forEach(record => {
-              this._db.delete(this._service.getKeyFromRecord(record))
-                .then(_ => {
-                  // courtesy, but don't establish a connection
-                  // just for it
-                  if (this._ws) {
-                    debug("Had a connection, so telling the server");
-                    this._sendRequest("unregister", {channelID: records.channelID})
-                        .catch(function(e) {
-                          debug("Unregister errored " + e);
-                        });
-                  }
-                }, err => {
-                  debug("webapps-clear-data: " + scope +
-                        " Could not delete entry " + records.channelID);
+        // TODO 1149274.  We should support site permissions as well as a way to
+        // go from manifest url to 'all scopes registered for push in this app'
+        let appsService = Cc["@mozilla.org/AppsService;1"]
+                            .getService(Ci.nsIAppsService);
+        let scope = appsService.getScopeByLocalId(data.appId);
+        if (!scope) {
+          debug("webapps-clear-data: No scope found for " + data.appId);
+          return;
+        }
 
-                  // courtesy, but don't establish a connection
-                  // just for it
-                  if (this._ws) {
-                    debug("Had a connection, so telling the server");
-                    this._sendRequest("unregister", {channelID: records.channelID})
-                        .catch(function(e) {
-                          debug("Unregister errored " + e);
-                        });
-                  }
-                  throw "Database error";
-                });
-            });
-          }, _ => {
-            debug("webapps-clear-data: Error in getAllByOriginAttributes(" + originAttributes + ")");
+        this._db.getByScope(scope)
+          .then(record =>
+            Promise.all([
+              this._db.delete(this._service.getKeyFromRecord(record)),
+              this._sendRequest("unregister", record)
+            ])
+          ).catch(_ => {
+            debug("webapps-clear-data: Error in getByScope(" + scope + ")");
           });
 
         break;
     }
   },
 
   // utility function used to add/remove observers in startObservers() and
   // stopObservers()
@@ -655,29 +618,33 @@ this.PushService = {
 
   // Fires a push-register system message to all applications that have
   // registration.
   _notifyAllAppsRegister: function() {
     debug("notifyAllAppsRegister()");
     // records are objects describing the registration as stored in IndexedDB.
     return this._db.getAllKeyIDs()
       .then(records => {
+        let scopes = new Set();
+        for (let record of records) {
+          scopes.add(record.scope);
+        }
         let globalMM = Cc['@mozilla.org/globalmessagemanager;1']
                          .getService(Ci.nsIMessageListenerManager);
-        for (let record of records) {
+        for (let scope of scopes) {
           // Notify XPCOM observers.
           Services.obs.notifyObservers(
             null,
             "push-subscription-change",
             scope
           );
 
           let data = {
-            originAttributes: record.originAttributes,
-            scope: record.scope
+            originAttributes: {}, // TODO bug 1166350
+            scope: scope
           };
 
           globalMM.broadcastAsyncMessage('pushsubscriptionchange', data);
         }
       });
   },
 
   dropRegistrationAndNotifyApp: function(aKeyId) {
@@ -687,17 +654,17 @@ this.PushService = {
                          .getService(Ci.nsIMessageListenerManager);
         Services.obs.notifyObservers(
           null,
           "push-subscription-change",
           record.scope
         );
 
         let data = {
-          originAttributes: record.originAttributes,
+          originAttributes: {}, // TODO bug 1166350
           scope: record.scope
         };
 
         globalMM.broadcastAsyncMessage('pushsubscriptionchange', data);
       })
       .then(_ => this._db.delete(aKeyId));
   },
 
@@ -709,32 +676,31 @@ this.PushService = {
                            .getService(Ci.nsIMessageListenerManager);
           Services.obs.notifyObservers(
             null,
             "push-subscription-change",
             record.scope
           );
 
           let data = {
-            originAttributes: record.originAttributes,
+            originAttributes: {}, // TODO bug 1166350
             scope: record.scope
           };
 
           globalMM.broadcastAsyncMessage('pushsubscriptionchange', data);
         }));
   },
 
   receivedPushMessage: function(aPushRecord, message) {
     this._db.put(aPushRecord)
       .then(_ => this._notifyApp(aPushRecord, message));
   },
 
   _notifyApp: function(aPushRecord, message) {
-    if (!aPushRecord || !aPushRecord.scope ||
-        aPushRecord.originAttributes === undefined) {
+    if (!aPushRecord || !aPushRecord.scope) {
       debug("notifyApp() something is undefined.  Dropping notification: " +
         JSON.stringify(aPushRecord) );
       return;
     }
 
     debug("notifyApp() " + aPushRecord.scope);
     let scopeURI = Services.io.newURI(aPushRecord.scope, null, null);
     // Notify XPCOM observers.
@@ -757,76 +723,78 @@ this.PushService = {
         Ci.nsIPermissionManager.ALLOW_ACTION) {
       debug("Does not have permission for push.");
       return;
     }
 
     // TODO data.
     let data = {
       payload: message,
-      originAttributes: aPushRecord.originAttributes,
+      originAttributes: {}, // TODO bug 1166350
       scope: aPushRecord.scope
     };
 
     let globalMM = Cc['@mozilla.org/globalmessagemanager;1']
                  .getService(Ci.nsIMessageListenerManager);
     globalMM.broadcastAsyncMessage('push', data);
   },
 
   getByKeyID: function(aKeyID) {
     return this._db.getByKeyID(aKeyID);
   },
 
   getAllKeyIDs: function() {
     return this._db.getAllKeyIDs();
   },
 
-  _sendRequest: function(action, aRecord) {
+  _sendRequest(action, aRecord) {
     if (this._state == PUSH_SERVICE_CONNECTION_DISABLE) {
       return Promise.reject({state: 0, error: "Service not active"});
     } else if (this._state == PUSH_SERVICE_ACTIVE_OFFLINE) {
       return Promise.reject({state: 0, error: "NetworkError"});
     }
     return this._service.request(action, aRecord);
   },
 
   /**
    * Called on message from the child process. aPageRecord is an object sent by
    * navigator.push, identifying the sending page and other fields.
    */
   _registerWithServer: function(aPageRecord) {
-    debug("registerWithServer()" + JSON.stringify(aPageRecord));
+    debug("registerWithServer()");
 
     return this._sendRequest("register", aPageRecord)
       .then(pushRecord => this._onRegisterSuccess(pushRecord),
             err => this._onRegisterError(err))
       .then(pushRecord => {
-        this._deletePendingRequest(aPageRecord);
+        if (this._pendingRegisterRequest[aPageRecord.scope]) {
+          delete this._pendingRegisterRequest[aPageRecord.scope];
+        }
         return pushRecord;
       }, err => {
-        this._deletePendingRequest(aPageRecord);
+        if (this._pendingRegisterRequest[aPageRecord.scope]) {
+          delete this._pendingRegisterRequest[aPageRecord.scope];
+        }
         throw err;
      });
   },
 
   _register: function(aPageRecord) {
-    debug("_register()");
-    if (!aPageRecord.scope || aPageRecord.originAttributes === undefined) {
-      return Promise.reject({state: 0, error: "NotFoundError"});
-    }
-
     return this._checkActivated()
-      .then(_ => this._db.getByIdentifiers(aPageRecord))
+      .then(_ => this._db.getByScope(aPageRecord.scope))
       .then(pushRecord => {
         if (pushRecord === undefined) {
-          return this._lookupOrPutPendingRequest(aPageRecord);
+          if (this._pendingRegisterRequest[aPageRecord.scope]) {
+            return this._pendingRegisterRequest[aPageRecord.scope];
+          }
+          return this._pendingRegisterRequest[aPageRecord.scope] = this._registerWithServer(aPageRecord);
         }
         return pushRecord;
       }, error => {
-        debug("getByIdentifiers failed");
+        debug("getByScope failed");
         throw error;
       });
   },
 
   /**
    * Exceptions thrown in _onRegisterSuccess are caught by the promise obtained
    * from _service.request, causing the promise to be rejected instead.
    */
@@ -860,49 +828,20 @@ this.PushService = {
   receiveMessage: function(aMessage) {
     debug("receiveMessage(): " + aMessage.name);
 
     if (kCHILD_PROCESS_MESSAGES.indexOf(aMessage.name) == -1) {
       debug("Invalid message from child " + aMessage.name);
       return;
     }
 
-    if (!aMessage.target.assertPermission("push")) {
-      debug("Got message from a child process that does not have 'push' permission.");
-      return null;
-    }
-
     let mm = aMessage.target.QueryInterface(Ci.nsIMessageSender);
-    let pageRecord = aMessage.data;
+    let json = aMessage.data;
 
-    let principal = aMessage.principal;
-    if (!principal) {
-      debug("No principal passed!");
-      let message = {
-        requestID: aPageRecord.requestID,
-        error: "SecurityError"
-      };
-      mm.sendAsyncMessage("PushService:Register:KO", message);
-      return;
-    }
-
-    pageRecord.originAttributes =
-      ChromeUtils.originAttributesToSuffix(principal.originAttributes);
-
-    if (!pageRecord.scope || pageRecord.originAttributes === undefined) {
-      debug("Incorrect identifier values set! " + JSON.stringify(pageRecord));
-      let message = {
-        requestID: aPageRecord.requestID,
-        error: "SecurityError"
-      };
-      mm.sendAsyncMessage("PushService:Register:KO", message);
-      return;
-    }
-
-    this[aMessage.name.slice("Push:".length).toLowerCase()](pageRecord, mm);
+    this[aMessage.name.slice("Push:".length).toLowerCase()](json, mm);
   },
 
   register: function(aPageRecord, aMessageManager) {
     debug("register(): " + JSON.stringify(aPageRecord));
 
     this._register(aPageRecord)
       .then(pushRecord => {
         let message = this._service.prepareRegister(pushRecord);
@@ -939,22 +878,23 @@ this.PushService = {
    * reason at which point the server will say it does not know of this
    * unregistration.  We'll have to make the registration/unregistration phases
    * have retries and attempts to resend messages from the server, and have the
    * client acknowledge. On a server, data is cheap, reliable notification is
    * not.
    */
   _unregister: function(aPageRecord) {
     debug("_unregister()");
-    if (!aPageRecord.scope || aPageRecord.originAttributes === undefined) {
+
+    if (!aPageRecord.scope) {
       return Promise.reject({state: 0, error: "NotFoundError"});
     }
 
     return this._checkActivated()
-      .then(_ => this._db.getByIdentifiers(aPageRecord))
+      .then(_ => this._db.getByScope(aPageRecord.scope))
       .then(record => {
         // If the endpoint didn't exist, let's just fail.
         if (record === undefined) {
           throw "NotFoundError";
         }
 
         return Promise.all([
           this._sendRequest("unregister", record),
@@ -987,22 +927,22 @@ this.PushService = {
       });
   },
 
   /**
    * Called on message from the child process
    */
   _registration: function(aPageRecord) {
     debug("_registration()");
-    if (!aPageRecord.scope || aPageRecord.originAttributes === undefined) {
-      return Promise.reject({state: 0, error: "NotFoundError"});
+    if (!aPageRecord.scope) {
+      return Promise.reject({state: 0, error: "Database error"});
     }
 
     return this._checkActivated()
-      .then(_ => this._db.getByIdentifiers(aPageRecord))
+      .then(_ => this._db.getByScope(aPageRecord.scope))
       .then(pushRecord => {
         if (!pushRecord) {
           return null;
         }
         return this._service.prepareRegistration(pushRecord);
       });
   },
 
--- a/dom/push/PushServiceHttp2.jsm
+++ b/dom/push/PushServiceHttp2.jsm
@@ -28,17 +28,17 @@ var gDebuggingEnabled = prefs.get("debug
 
 function debug(s) {
   if (gDebuggingEnabled) {
     dump("-*- PushServiceHttp2.jsm: " + s + "\n");
   }
 }
 
 const kPUSHHTTP2DB_DB_NAME = "pushHttp2";
-const kPUSHHTTP2DB_DB_VERSION = 3; // Change this if the IndexedDB format changes
+const kPUSHHTTP2DB_DB_VERSION = 1; // Change this if the IndexedDB format changes
 const kPUSHHTTP2DB_STORE_NAME = "pushHttp2";
 
 /**
  * A proxy between the PushService and connections listening for incoming push
  * messages. The PushService can silence messages from the connections by
  * setting PushSubscriptionListener._pushService to null. This is required
  * because it can happen that there is an outstanding push message that will
  * be send on OnStopRequest but the PushService may not be interested in these.
@@ -286,17 +286,16 @@ SubscriptionListener.prototype = {
     }
 
     var reply = {
       subscriptionUri: subscriptionUri,
       pushEndpoint: linkParserResult.pushEndpoint,
       pushReceiptEndpoint: linkParserResult.pushReceiptEndpoint,
       pageURL: this._subInfo.record.pageURL,
       scope: this._subInfo.record.scope,
-      originAttributes: this._subInfo.record.originAttributes,
       pushCount: 0,
       lastPush: 0
     };
     this._subInfo.resolve(reply);
   },
 };
 
 function retryAfterParser(aRequest) {
@@ -381,43 +380,25 @@ this.PushServiceHttp2 = {
 
   upgradeSchema: function(aTransaction,
                           aDb,
                           aOldVersion,
                           aNewVersion,
                           aDbInstance) {
     debug("upgradeSchemaHttp2()");
 
-    //XXXnsm We haven't shipped Push during this upgrade, so I'm just going to throw old
-    //registrations away without even informing the app.
-    if (aNewVersion != aOldVersion) {
-      try {
-        aDb.deleteObjectStore(aDbInstance._dbStoreName);
-      } catch (e) {
-        if (e.name === "NotFoundError") {
-          debug("No existing object store found");
-        } else {
-          throw e;
-        }
-      }
-    }
-
     let objectStore = aDb.createObjectStore(aDbInstance._dbStoreName,
                                             { keyPath: "subscriptionUri" });
 
     // index to fetch records based on endpoints. used by unregister
     objectStore.createIndex("pushEndpoint", "pushEndpoint", { unique: true });
 
-    // index to fetch records by identifiers.
-    // In the current security model, the originAttributes distinguish between
-    // different 'apps' on the same origin. Since ServiceWorkers are
-    // same-origin to the scope they are registered for, the attributes and
-    // scope are enough to reconstruct a valid principal.
-    objectStore.createIndex("identifiers", ["scope", "originAttributes"], { unique: true });
-    objectStore.createIndex("originAttributes", "originAttributes", { unique: false });
+    // index to fetch records per scope, so we can identify endpoints
+    // associated with an app.
+    objectStore.createIndex("scope", "scope", { unique: true });
   },
 
   getKeyFromRecord: function(aRecord) {
     return aRecord.subscriptionUri;
   },
 
   newPushDB: function() {
     return new PushDB(kPUSHHTTP2DB_DB_NAME,
--- a/dom/push/PushServiceWebSocket.jsm
+++ b/dom/push/PushServiceWebSocket.jsm
@@ -27,17 +27,17 @@ XPCOMUtils.defineLazyServiceGetter(this,
                                    "@mozilla.org/power/powermanagerservice;1",
                                    "nsIPowerManagerService");
 #endif
 
 var threadManager = Cc["@mozilla.org/thread-manager;1"]
                       .getService(Ci.nsIThreadManager);
 
 const kPUSHWSDB_DB_NAME = "pushapi";
-const kPUSHWSDB_DB_VERSION = 3; // Change this if the IndexedDB format changes
+const kPUSHWSDB_DB_VERSION = 1; // Change this if the IndexedDB format changes
 const kPUSHWSDB_STORE_NAME = "pushapi";
 
 const kUDP_WAKEUP_WS_STATUS_CODE = 4774;  // WebSocket Close status code sent
                                           // by server to signal that it can
                                           // wake client up using UDP.
 
 const kWS_MAX_WENTDOWN = 2;
 
@@ -127,43 +127,25 @@ this.PushServiceWebSocket = {
 
   upgradeSchema: function(aTransaction,
                           aDb,
                           aOldVersion,
                           aNewVersion,
                           aDbInstance) {
     debug("upgradeSchemaWS()");
 
-    //XXXnsm We haven't shipped Push during this upgrade, so I'm just going to throw old
-    //registrations away without even informing the app.
-    if (aNewVersion != aOldVersion) {
-      try {
-        aDb.deleteObjectStore(aDbInstance._dbStoreName);
-      } catch (e) {
-        if (e.name === "NotFoundError") {
-          debug("No existing object store found");
-        } else {
-          throw e;
-        }
-      }
-    }
-
     let objectStore = aDb.createObjectStore(aDbInstance._dbStoreName,
                                             { keyPath: "channelID" });
 
     // index to fetch records based on endpoints. used by unregister
     objectStore.createIndex("pushEndpoint", "pushEndpoint", { unique: true });
 
-    // index to fetch records by identifiers.
-    // In the current security model, the originAttributes distinguish between
-    // different 'apps' on the same origin. Since ServiceWorkers are
-    // same-origin to the scope they are registered for, the attributes and
-    // scope are enough to reconstruct a valid principal.
-    objectStore.createIndex("identifiers", ["scope", "originAttributes"], { unique: true });
-    objectStore.createIndex("originAttributes", "originAttributes", { unique: false });
+    // index to fetch records per scope, so we can identify endpoints
+    // associated with an app.
+    objectStore.createIndex("scope", "scope", { unique: true });
   },
 
   getKeyFromRecord: function(aRecord) {
     return aRecord.channelID;
   },
 
   newPushDB: function() {
     return new PushDB(kPUSHWSDB_DB_NAME,
@@ -883,22 +865,20 @@ this.PushServiceWebSocket = {
         return;
       }
 
       let record = {
         channelID: reply.channelID,
         pushEndpoint: reply.pushEndpoint,
         pageURL: tmp.record.pageURL,
         scope: tmp.record.scope,
-        originAttributes: tmp.record.originAttributes,
         pushCount: 0,
         lastPush: 0,
         version: null
       };
-      dump("PushWebSocket " +  JSON.stringify(record));
       tmp.resolve(record);
     } else {
       tmp.reject(reply);
     }
   },
 
   /**
    * Protocol handler invoked by server message.
--- a/dom/push/test/test_multiple_register.html
+++ b/dom/push/test/test_multiple_register.html
@@ -115,17 +115,16 @@ http://creativecommons.org/licenses/publ
     .then(unregister)
     .catch(function(e) {
       ok(false, "Some test failed with error " + e);
     }).then(SimpleTest.finish);
   }
 
   SpecialPowers.pushPrefEnv({"set": [
     ["dom.push.enabled", true],
-    ["dom.push.debug", true],
     ["dom.serviceWorkers.exemptFromPerDomainMax", true],
     ["dom.serviceWorkers.enabled", true],
     ["dom.serviceWorkers.testing.enabled", true]
     ]}, runTest);
   SpecialPowers.addPermission('push', true, document);
   SimpleTest.waitForExplicitFinish();
 </script>
 </body>
--- a/dom/push/test/xpcshell/test_notification_ack.js
+++ b/dom/push/test/xpcshell/test_notification_ack.js
@@ -20,29 +20,26 @@ function run_test() {
 
 add_task(function* test_notification_ack() {
   let db = PushServiceWebSocket.newPushDB();
   do_register_cleanup(() => {return db.drop().then(_ => db.close());});
   let records = [{
     channelID: '21668e05-6da8-42c9-b8ab-9cc3f4d5630c',
     pushEndpoint: 'https://example.com/update/1',
     scope: 'https://example.org/1',
-    originAttributes: '',
     version: 1
   }, {
     channelID: '9a5ff87f-47c9-4215-b2b8-0bdd38b4b305',
     pushEndpoint: 'https://example.com/update/2',
     scope: 'https://example.org/2',
-    originAttributes: '',
     version: 2
   }, {
     channelID: '5477bfda-22db-45d4-9614-fee369630260',
     pushEndpoint: 'https://example.com/update/3',
     scope: 'https://example.org/3',
-    originAttributes: '',
     version: 3
   }];
   for (let record of records) {
     yield db.put(record);
   }
 
   let notifyPromise = Promise.all([
     promiseObserverNotification('push-notification'),
--- a/dom/push/test/xpcshell/test_notification_duplicate.js
+++ b/dom/push/test/xpcshell/test_notification_duplicate.js
@@ -18,23 +18,21 @@ function run_test() {
 // Should acknowledge duplicate notifications, but not notify apps.
 add_task(function* test_notification_duplicate() {
   let db = PushServiceWebSocket.newPushDB();
   do_register_cleanup(() => {return db.drop().then(_ => db.close());});
   let records = [{
     channelID: '8d2d9400-3597-4c5a-8a38-c546b0043bcc',
     pushEndpoint: 'https://example.org/update/1',
     scope: 'https://example.com/1',
-    originAttributes: "",
     version: 2
   }, {
     channelID: '27d1e393-03ef-4c72-a5e6-9e890dfccad0',
     pushEndpoint: 'https://example.org/update/2',
     scope: 'https://example.com/2',
-    originAttributes: "",
     version: 2
   }];
   for (let record of records) {
     yield db.put(record);
   }
 
   let notifyPromise = promiseObserverNotification('push-notification');
 
--- a/dom/push/test/xpcshell/test_notification_error.js
+++ b/dom/push/test/xpcshell/test_notification_error.js
@@ -14,35 +14,30 @@ function run_test() {
     'https://example.com/c'
   );
   run_next_test();
 }
 
 add_task(function* test_notification_error() {
   let db = PushServiceWebSocket.newPushDB();
   do_register_cleanup(() => {return db.drop().then(_ => db.close());});
-
-  let originAttributes = '';
   let records = [{
     channelID: 'f04f1e46-9139-4826-b2d1-9411b0821283',
     pushEndpoint: 'https://example.org/update/success-1',
     scope: 'https://example.com/a',
-    originAttributes: originAttributes,
     version: 1
   }, {
     channelID: '3c3930ba-44de-40dc-a7ca-8a133ec1a866',
     pushEndpoint: 'https://example.org/update/error',
     scope: 'https://example.com/b',
-    originAttributes: originAttributes,
     version: 2
   }, {
     channelID: 'b63f7bef-0a0d-4236-b41e-086a69dfd316',
     pushEndpoint: 'https://example.org/update/success-2',
     scope: 'https://example.com/c',
-    originAttributes: originAttributes,
     version: 3
   }];
   for (let record of records) {
     yield db.put(record);
   }
 
   let notifyPromise = Promise.all([
     promiseObserverNotification(
@@ -107,29 +102,26 @@ add_task(function* test_notification_err
   let cPush = c.subject.QueryInterface(Ci.nsIPushObserverNotification);
   equal(cPush.pushEndpoint, 'https://example.org/update/success-2',
     'Wrong endpoint for notification C');
   equal(cPush.version, 4, 'Wrong version for notification C');
 
   yield waitForPromise(ackDefer.promise, DEFAULT_TIMEOUT,
     'Timed out waiting for acknowledgements');
 
-  let aRecord = yield db.getByIdentifiers({scope: 'https://example.com/a',
-                                           originAttributes: originAttributes });
+  let aRecord = yield db.getByScope('https://example.com/a');
   equal(aRecord.channelID, 'f04f1e46-9139-4826-b2d1-9411b0821283',
     'Wrong channel ID for record A');
   strictEqual(aRecord.version, 2,
     'Should return the new version for record A');
 
-  let bRecord = yield db.getByIdentifiers({scope: 'https://example.com/b',
-                                           originAttributes: originAttributes });
+  let bRecord = yield db.getByScope('https://example.com/b');
   equal(bRecord.channelID, '3c3930ba-44de-40dc-a7ca-8a133ec1a866',
     'Wrong channel ID for record B');
   strictEqual(bRecord.version, 2,
     'Should return the previous version for record B');
 
-  let cRecord = yield db.getByIdentifiers({scope: 'https://example.com/c',
-                                           originAttributes: originAttributes });
+  let cRecord = yield db.getByScope('https://example.com/c');
   equal(cRecord.channelID, 'b63f7bef-0a0d-4236-b41e-086a69dfd316',
     'Wrong channel ID for record C');
   strictEqual(cRecord.version, 4,
     'Should return the new version for record C');
 });
--- a/dom/push/test/xpcshell/test_notification_version_string.js
+++ b/dom/push/test/xpcshell/test_notification_version_string.js
@@ -16,17 +16,16 @@ function run_test() {
 
 add_task(function* test_notification_version_string() {
   let db = PushServiceWebSocket.newPushDB();
   do_register_cleanup(() => {return db.drop().then(_ => db.close());});
   yield db.put({
     channelID: '6ff97d56-d0c0-43bc-8f5b-61b855e1d93b',
     pushEndpoint: 'https://example.org/updates/1',
     scope: 'https://example.com/page/1',
-    originAttributes: '',
     version: 2
   });
 
   let notifyPromise = promiseObserverNotification('push-notification');
 
   let ackDefer = Promise.defer();
   PushService.init({
     serverURI: "wss://push.example.org/",
--- a/dom/push/test/xpcshell/test_register_5xxCode_http2.js
+++ b/dom/push/test/xpcshell/test_register_5xxCode_http2.js
@@ -79,18 +79,17 @@ add_task(function* test1() {
 
   PushService.init({
     serverURI: serverURL + "/subscribe5xxCode",
     service: PushServiceHttp2,
     db
   });
 
   let newRecord = yield PushNotificationService.register(
-    'https://example.com/retry5xxCode',
-    { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }
+    'https://example.com/retry5xxCode'
   );
 
   var subscriptionUri = serverURL + '/subscription';
   var pushEndpoint = serverURL + '/pushEndpoint';
   var pushReceiptEndpoint = serverURL + '/receiptPushEndpoint';
   equal(newRecord.subscriptionUri, subscriptionUri,
     'Wrong subscription ID in registration record');
   equal(newRecord.pushEndpoint, pushEndpoint,
--- a/dom/push/test/xpcshell/test_register_case.js
+++ b/dom/push/test/xpcshell/test_register_case.js
@@ -42,18 +42,17 @@ add_task(function* test_register_case() 
             pushEndpoint: 'https://example.com/update/case'
           }));
         }
       });
     }
   });
 
   let newRecord = yield waitForPromise(
-    PushNotificationService.register('https://example.net/case',
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+    PushNotificationService.register('https://example.net/case'),
     DEFAULT_TIMEOUT,
     'Mixed-case register response timed out'
   );
   equal(newRecord.pushEndpoint, 'https://example.com/update/case',
     'Wrong push endpoint in registration record');
   equal(newRecord.scope, 'https://example.net/case',
     'Wrong scope in registration record');
 
--- a/dom/push/test/xpcshell/test_register_flush.js
+++ b/dom/push/test/xpcshell/test_register_flush.js
@@ -24,17 +24,16 @@ function run_test() {
 
 add_task(function* test_register_flush() {
   let db = PushServiceWebSocket.newPushDB();
   do_register_cleanup(() => {return db.drop().then(_ => db.close());});
   let record = {
     channelID: '9bcc7efb-86c7-4457-93ea-e24e6eb59b74',
     pushEndpoint: 'https://example.org/update/1',
     scope: 'https://example.com/page/1',
-    originAttributes: '',
     version: 2
   };
   yield db.put(record);
 
   let notifyPromise = promiseObserverNotification('push-notification');
 
   let ackDefer = Promise.defer();
   let ackDone = after(2, ackDefer.resolve);
@@ -71,17 +70,18 @@ add_task(function* test_register_flush()
           }));
         },
         onACK: ackDone
       });
     }
   });
 
   let newRecord = yield PushNotificationService.register(
-    'https://example.com/page/2', '');
+    'https://example.com/page/2'
+  );
   equal(newRecord.pushEndpoint, 'https://example.org/update/2',
     'Wrong push endpoint in record');
   equal(newRecord.scope, 'https://example.com/page/2',
     'Wrong scope in record');
 
   let {data: scope} = yield waitForPromise(notifyPromise, DEFAULT_TIMEOUT,
     'Timed out waiting for notification');
   equal(scope, 'https://example.com/page/1', 'Wrong notification scope');
--- a/dom/push/test/xpcshell/test_register_invalid_channel.js
+++ b/dom/push/test/xpcshell/test_register_invalid_channel.js
@@ -43,18 +43,17 @@ add_task(function* test_register_invalid
             error: 'Invalid channel ID'
           }));
         }
       });
     }
   });
 
   yield rejects(
-    PushNotificationService.register('https://example.com/invalid-channel',
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+    PushNotificationService.register('https://example.com/invalid-channel'),
     function(error) {
       return error == 'Invalid channel ID';
     },
     'Wrong error for invalid channel ID'
   );
 
   let record = yield db.getByKeyID(channelID);
   ok(!record, 'Should not store records for error responses');
--- a/dom/push/test/xpcshell/test_register_invalid_endpoint.js
+++ b/dom/push/test/xpcshell/test_register_invalid_endpoint.js
@@ -45,18 +45,17 @@ add_task(function* test_register_invalid
           }));
         }
       });
     }
   });
 
   yield rejects(
     PushNotificationService.register(
-      'https://example.net/page/invalid-endpoint',
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      'https://example.net/page/invalid-endpoint'),
     function(error) {
       return error && error.includes('Invalid pushEndpoint');
     },
     'Wrong error for invalid endpoint'
   );
 
   let record = yield db.getByKeyID(channelID);
   ok(!record, 'Should not store records with invalid endpoints');
--- a/dom/push/test/xpcshell/test_register_invalid_json.js
+++ b/dom/push/test/xpcshell/test_register_invalid_json.js
@@ -44,18 +44,17 @@ add_task(function* test_register_invalid
           this.serverSendMsg(');alert(1);(');
           registers++;
         }
       });
     }
   });
 
   yield rejects(
-    PushNotificationService.register('https://example.net/page/invalid-json',
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+    PushNotificationService.register('https://example.net/page/invalid-json'),
     function(error) {
       return error == 'TimeoutError';
     },
     'Wrong error for invalid JSON response'
   );
 
   yield waitForPromise(helloDefer.promise, DEFAULT_TIMEOUT,
     'Reconnect after invalid JSON response timed out');
--- a/dom/push/test/xpcshell/test_register_no_id.js
+++ b/dom/push/test/xpcshell/test_register_no_id.js
@@ -48,18 +48,17 @@ add_task(function* test_register_no_id()
             status: 200
           }));
         }
       });
     }
   });
 
   yield rejects(
-    PushNotificationService.register('https://example.com/incomplete',
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+    PushNotificationService.register('https://example.com/incomplete'),
     function(error) {
       return error == 'TimeoutError';
     },
     'Wrong error for incomplete register response'
   );
 
   yield waitForPromise(helloDefer.promise, DEFAULT_TIMEOUT,
     'Reconnect after incomplete register response timed out');
--- a/dom/push/test/xpcshell/test_register_request_queue.js
+++ b/dom/push/test/xpcshell/test_register_request_queue.js
@@ -40,22 +40,20 @@ add_task(function* test_register_request
         onRegister() {
           ok(false, 'Should cancel timed-out requests');
         }
       });
     }
   });
 
   let firstRegister = PushNotificationService.register(
-    'https://example.com/page/1',
-    { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }
+    'https://example.com/page/1'
   );
   let secondRegister = PushNotificationService.register(
-    'https://example.com/page/1',
-    { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }
+    'https://example.com/page/1'
   );
 
   yield waitForPromise(Promise.all([
     rejects(firstRegister, function(error) {
       return error == 'TimeoutError';
     }, 'Should time out the first request'),
     rejects(secondRegister, function(error) {
       return error == 'TimeoutError';
--- a/dom/push/test/xpcshell/test_register_rollback.js
+++ b/dom/push/test/xpcshell/test_register_rollback.js
@@ -69,18 +69,17 @@ add_task(function* test_register_rollbac
           unregisterDefer.resolve();
         }
       });
     }
   });
 
   // Should return a rejected promise if storage fails.
   yield rejects(
-    PushNotificationService.register('https://example.com/storage-error',
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+    PushNotificationService.register('https://example.com/storage-error'),
     function(error) {
       return error == 'universe has imploded';
     },
     'Wrong error for unregister database failure'
   );
 
   // Should send an out-of-band unregister request.
   yield waitForPromise(unregisterDefer.promise, DEFAULT_TIMEOUT,
--- a/dom/push/test/xpcshell/test_register_success.js
+++ b/dom/push/test/xpcshell/test_register_success.js
@@ -52,18 +52,17 @@ add_task(function* test_register_success
             pushEndpoint: 'https://example.com/update/1',
           }));
         }
       });
     }
   });
 
   let newRecord = yield PushNotificationService.register(
-    'https://example.org/1',
-    { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }
+    'https://example.org/1'
   );
   equal(newRecord.channelID, channelID,
     'Wrong channel ID in registration record');
   equal(newRecord.pushEndpoint, 'https://example.com/update/1',
     'Wrong push endpoint in registration record');
   equal(newRecord.scope, 'https://example.org/1',
     'Wrong scope in registration record');
 
--- a/dom/push/test/xpcshell/test_register_timeout.js
+++ b/dom/push/test/xpcshell/test_register_timeout.js
@@ -78,18 +78,17 @@ add_task(function* test_register_timeout
           }, 2000);
           registers++;
         }
       });
     }
   });
 
   yield rejects(
-    PushNotificationService.register('https://example.net/page/timeout',
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+    PushNotificationService.register('https://example.net/page/timeout'),
     function(error) {
       return error == 'TimeoutError';
     },
     'Wrong error for request timeout'
   );
 
   let record = yield db.getByKeyID(channelID);
   ok(!record, 'Should not store records for timed-out responses');
--- a/dom/push/test/xpcshell/test_register_wrong_id.js
+++ b/dom/push/test/xpcshell/test_register_wrong_id.js
@@ -54,18 +54,17 @@ add_task(function* test_register_wrong_i
             channelID: serverChannelID
           }));
         }
       });
     }
   });
 
   yield rejects(
-    PushNotificationService.register('https://example.com/mismatched',
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+    PushNotificationService.register('https://example.com/mismatched'),
     function(error) {
       return error == 'TimeoutError';
     },
     'Wrong error for mismatched register reply'
   );
 
   yield waitForPromise(helloDefer.promise, DEFAULT_TIMEOUT,
     'Reconnect after mismatched register reply timed out');
--- a/dom/push/test/xpcshell/test_register_wrong_type.js
+++ b/dom/push/test/xpcshell/test_register_wrong_type.js
@@ -50,18 +50,17 @@ add_task(function* test_register_wrong_t
         }
       });
     }
   });
 
   let promise =
 
   yield rejects(
-    PushNotificationService.register('https://example.com/mistyped',
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+    PushNotificationService.register('https://example.com/mistyped'),
     function(error) {
       return error == 'TimeoutError';
     },
     'Wrong error for non-string channel ID'
   );
 
   yield waitForPromise(helloDefer.promise, DEFAULT_TIMEOUT,
     'Reconnect after sending non-string channel ID timed out');
--- a/dom/push/test/xpcshell/test_registration_error.js
+++ b/dom/push/test/xpcshell/test_registration_error.js
@@ -16,26 +16,25 @@ function run_test() {
 add_task(function* test_registrations_error() {
   let db = PushServiceWebSocket.newPushDB();
   do_register_cleanup(() => {return db.drop().then(_ => db.close());});
 
   PushService.init({
     serverURI: "wss://push.example.org/",
     networkInfo: new MockDesktopNetworkInfo(),
     db: makeStub(db, {
-      getByIdentifiers(prev, scope) {
+      getByScope(prev, scope) {
         return Promise.reject('Database error');
       }
     }),
     makeWebSocket(uri) {
       return new MockWebSocket(uri);
     }
   });
 
   yield rejects(
-    PushNotificationService.registration('https://example.net/1',
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+    PushNotificationService.registration('https://example.net/1'),
     function(error) {
       return error == 'Database error';
     },
     'Wrong message'
   );
 });
--- a/dom/push/test/xpcshell/test_registration_error_http2.js
+++ b/dom/push/test/xpcshell/test_registration_error_http2.js
@@ -13,17 +13,17 @@ function run_test() {
 add_task(function* test_registrations_error() {
   let db = PushServiceHttp2.newPushDB();
   do_register_cleanup(() => {return db.drop().then(_ => db.close());});
 
   PushService.init({
     serverURI: "https://push.example.org/",
     networkInfo: new MockDesktopNetworkInfo(),
     db: makeStub(db, {
-      getByIdentifiers() {
+      getByScope(prev, scope) {
         return Promise.reject('Database error');
       }
     }),
   });
 
   yield rejects(
     PushNotificationService.registration('https://example.net/1'),
     function(error) {
--- a/dom/push/test/xpcshell/test_registration_missing_scope.js
+++ b/dom/push/test/xpcshell/test_registration_missing_scope.js
@@ -15,15 +15,15 @@ add_task(function* test_registration_mis
   PushService.init({
     serverURI: "wss://push.example.org/",
     networkInfo: new MockDesktopNetworkInfo(),
     makeWebSocket(uri) {
       return new MockWebSocket(uri);
     }
   });
   yield rejects(
-    PushNotificationService.registration('', ''),
+    PushNotificationService.registration(''),
     function(error) {
-      return error.error == 'NotFoundError';
+      return error.error == 'Database error';
     },
     'Record missing page and manifest URLs'
   );
 });
--- a/dom/push/test/xpcshell/test_registration_none.js
+++ b/dom/push/test/xpcshell/test_registration_none.js
@@ -19,12 +19,11 @@ add_task(function* test_registration_non
     serverURI: "wss://push.example.org/",
     networkInfo: new MockDesktopNetworkInfo(),
     makeWebSocket(uri) {
       return new MockWebSocket(uri);
     }
   });
 
   let registration = yield PushNotificationService.registration(
-    'https://example.net/1',
-    { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false });
+    'https://example.net/1');
   ok(!registration, 'Should not open a connection without registration');
 });
--- a/dom/push/test/xpcshell/test_registration_success.js
+++ b/dom/push/test/xpcshell/test_registration_success.js
@@ -15,29 +15,26 @@ function run_test() {
 
 add_task(function* test_registration_success() {
   let db = PushServiceWebSocket.newPushDB();
   do_register_cleanup(() => {return db.drop().then(_ => db.close());});
   let records = [{
     channelID: 'bf001fe0-2684-42f2-bc4d-a3e14b11dd5b',
     pushEndpoint: 'https://example.com/update/same-manifest/1',
     scope: 'https://example.net/a',
-    originAttributes: '',
     version: 5
   }, {
     channelID: 'f6edfbcd-79d6-49b8-9766-48b9dcfeff0f',
     pushEndpoint: 'https://example.com/update/same-manifest/2',
     scope: 'https://example.net/b',
-    originAttributes: ChromeUtils.originAttributesToSuffix({ appId: 42 }),
     version: 10
   }, {
     channelID: 'b1cf38c9-6836-4d29-8a30-a3e98d59b728',
     pushEndpoint: 'https://example.org/update/different-manifest',
     scope: 'https://example.org/c',
-    originAttributes: ChromeUtils.originAttributesToSuffix({ appId: 42, inBrowser: true }),
     version: 15
   }];
   for (let record of records) {
     yield db.put(record);
   }
 
   PushService.init({
     serverURI: "wss://push.example.org/",
@@ -57,16 +54,16 @@ add_task(function* test_registration_suc
             uaid: userAgentID
           }));
         }
       });
     }
   });
 
   let registration = yield PushNotificationService.registration(
-    'https://example.net/a', '');
+    'https://example.net/a');
   equal(
     registration.pushEndpoint,
     'https://example.com/update/same-manifest/1',
     'Wrong push endpoint for scope'
   );
   equal(registration.version, 5, 'Wrong version for scope');
 });
--- a/dom/push/test/xpcshell/test_unregister_empty_scope.js
+++ b/dom/push/test/xpcshell/test_unregister_empty_scope.js
@@ -24,16 +24,15 @@ add_task(function* test_unregister_empty
             uaid: '5619557c-86fe-4711-8078-d1fd6987aef7'
           }));
         }
       });
     }
   });
 
   yield rejects(
-    PushNotificationService.unregister('',
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+    PushNotificationService.unregister(''),
     function(error) {
       return error.error == 'NotFoundError';
     },
     'Wrong error for empty endpoint'
   );
 });
--- a/dom/push/test/xpcshell/test_unregister_error.js
+++ b/dom/push/test/xpcshell/test_unregister_error.js
@@ -15,17 +15,16 @@ function run_test() {
 
 add_task(function* test_unregister_error() {
   let db = PushServiceWebSocket.newPushDB();
   do_register_cleanup(() => {return db.drop().then(_ => db.close());});
   yield db.put({
     channelID: channelID,
     pushEndpoint: 'https://example.org/update/failure',
     scope: 'https://example.net/page/failure',
-    originAttributes: '',
     version: 1
   });
 
   let unregisterDefer = Promise.defer();
   PushService.init({
     serverURI: "wss://push.example.org/",
     networkInfo: new MockDesktopNetworkInfo(),
     db,
@@ -50,17 +49,17 @@ add_task(function* test_unregister_error
           }));
           unregisterDefer.resolve();
         }
       });
     }
   });
 
   yield PushNotificationService.unregister(
-    'https://example.net/page/failure', '');
+    'https://example.net/page/failure');
 
   let result = yield db.getByKeyID(channelID);
   ok(!result, 'Deleted push record exists');
 
   // Make sure we send a request to the server.
   yield waitForPromise(unregisterDefer.promise, DEFAULT_TIMEOUT,
     'Timed out waiting for unregister');
 });
--- a/dom/push/test/xpcshell/test_unregister_invalid_json.js
+++ b/dom/push/test/xpcshell/test_unregister_invalid_json.js
@@ -19,23 +19,21 @@ function run_test() {
 
 add_task(function* test_unregister_invalid_json() {
   let db = PushServiceWebSocket.newPushDB();
   do_register_cleanup(() => {return db.drop().then(_ => db.close());});
   let records = [{
     channelID: '87902e90-c57e-4d18-8354-013f4a556559',
     pushEndpoint: 'https://example.org/update/1',
     scope: 'https://example.edu/page/1',
-    originAttributes: '',
     version: 1
   }, {
     channelID: '057caa8f-9b99-47ff-891c-adad18ce603e',
     pushEndpoint: 'https://example.com/update/2',
     scope: 'https://example.net/page/1',
-    originAttributes: '',
     version: 1
   }];
   for (let record of records) {
     yield db.put(record);
   }
 
   let unregisterDefer = Promise.defer();
   let unregisterDone = after(2, unregisterDefer.resolve);
@@ -58,23 +56,23 @@ add_task(function* test_unregister_inval
         }
       });
     }
   });
 
   // "unregister" is fire-and-forget: it's sent via _send(), not
   // _sendRequest().
   yield PushNotificationService.unregister(
-    'https://example.edu/page/1', '');
+    'https://example.edu/page/1');
   let record = yield db.getByKeyID(
     '87902e90-c57e-4d18-8354-013f4a556559');
   ok(!record, 'Failed to delete unregistered record');
 
   yield PushNotificationService.unregister(
-    'https://example.net/page/1', '');
+    'https://example.net/page/1');
   record = yield db.getByKeyID(
     '057caa8f-9b99-47ff-891c-adad18ce603e');
   ok(!record,
     'Failed to delete unregistered record after receiving invalid JSON');
 
   yield waitForPromise(unregisterDefer.promise, DEFAULT_TIMEOUT,
     'Timed out waiting for unregister');
 });
--- a/dom/push/test/xpcshell/test_unregister_not_found.js
+++ b/dom/push/test/xpcshell/test_unregister_not_found.js
@@ -24,14 +24,13 @@ add_task(function* test_unregister_not_f
             uaid: 'f074ed80-d479-44fa-ba65-792104a79ea9'
           }));
         }
       });
     }
   });
 
   let promise = PushNotificationService.unregister(
-    'https://example.net/nonexistent',
-    { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false });
+    'https://example.net/nonexistent');
   yield rejects(promise, function(error) {
     return error == 'NotFoundError';
   }, 'Wrong error for nonexistent scope');
 });
--- a/dom/push/test/xpcshell/test_unregister_success.js
+++ b/dom/push/test/xpcshell/test_unregister_success.js
@@ -15,17 +15,16 @@ function run_test() {
 
 add_task(function* test_unregister_success() {
   let db = PushServiceWebSocket.newPushDB();
   do_register_cleanup(() => {return db.drop().then(_ => db.close());});
   yield db.put({
     channelID,
     pushEndpoint: 'https://example.org/update/unregister-success',
     scope: 'https://example.com/page/unregister-success',
-    originAttributes: '',
     version: 1
   });
 
   let unregisterDefer = Promise.defer();
   PushService.init({
     serverURI: "wss://push.example.org/",
     networkInfo: new MockDesktopNetworkInfo(),
     db,
@@ -47,15 +46,15 @@ add_task(function* test_unregister_succe
           }));
           unregisterDefer.resolve();
         }
       });
     }
   });
 
   yield PushNotificationService.unregister(
-    'https://example.com/page/unregister-success', '');
+    'https://example.com/page/unregister-success');
   let record = yield db.getByKeyID(channelID);
   ok(!record, 'Unregister did not remove record');
 
   yield waitForPromise(unregisterDefer.promise, DEFAULT_TIMEOUT,
     'Timed out waiting for unregister');
 });
deleted file mode 100644
--- a/dom/push/test/xpcshell/test_webapps_cleardata.js
+++ /dev/null
@@ -1,89 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-'use strict';
-
-const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
-
-const userAgentID = 'bd744428-f125-436a-b6d0-dd0c9845837f';
-const channelIDs = ['0ef2ad4a-6c49-41ad-af6e-95d2425276bf', '4818b54a-97c5-4277-ad5d-0bfe630e4e50'];
-var channelIDCounter = 0;
-
-function run_test() {
-  do_get_profile();
-  setPrefs({
-    userAgentID,
-    requestTimeout: 1000,
-    retryBaseInterval: 150
-  });
-  disableServiceWorkerEvents(
-    'https://example.org/1'
-  );
-  run_next_test();
-}
-
-add_task(function* test_webapps_cleardata() {
-  let db = PushServiceWebSocket.newPushDB();
-  do_register_cleanup(() => {return db.drop().then(_ => db.close());});
-
-  PushService._generateID = () => channelID;
-  PushService.init({
-    serverURI: "wss://push.example.org",
-    networkInfo: new MockDesktopNetworkInfo(),
-    db,
-    makeWebSocket(uri) {
-      return new MockWebSocket(uri, {
-        onHello(data) {
-          equal(data.messageType, 'hello', 'Handshake: wrong message type');
-          equal(data.uaid, userAgentID, 'Handshake: wrong device ID');
-          this.serverSendMsg(JSON.stringify({
-            messageType: 'hello',
-            status: 200,
-            uaid: userAgentID
-          }));
-        },
-        onRegister(data) {
-          equal(data.messageType, 'register', 'Register: wrong message type');
-          this.serverSendMsg(JSON.stringify({
-            messageType: 'register',
-            status: 200,
-            channelID: data.channelID,
-            uaid: userAgentID,
-            pushEndpoint: 'https://example.com/update/' + Math.random(),
-          }));
-        }
-      });
-    }
-  });
-
-  let registers = yield Promise.all([
-    PushNotificationService.register(
-      'https://example.org/1',
-      ChromeUtils.originAttributesToSuffix({ appId: 1, inBrowser: false })),
-    PushNotificationService.register(
-      'https://example.org/1',
-      ChromeUtils.originAttributesToSuffix({ appId: 1, inBrowser: true })),
-  ]);
-
-  Services.obs.notifyObservers(
-      { appId: 1, browserOnly: false,
-        QueryInterface: XPCOMUtils.generateQI([Ci.mozIApplicationClearPrivateDataParams])},
-      "webapps-clear-data", "");
-
-  let waitAWhile = new Promise(function(res) {
-    setTimeout(res, 2000);
-  });
-  yield waitAWhile;
-
-  let registration;
-  registration = yield PushNotificationService.registration(
-    'https://example.org/1',
-    ChromeUtils.originAttributesToSuffix({ appId: 1, inBrowser: false }));
-  ok(!registration, 'Registration for { 1, false } should not exist.');
-
-  registration = yield PushNotificationService.registration(
-    'https://example.org/1',
-    ChromeUtils.originAttributesToSuffix({ appId: 1, inBrowser: true }));
-  ok(registration, 'Registration for { 1, true } should still exist.');
-});
-
--- a/dom/push/test/xpcshell/xpcshell.ini
+++ b/dom/push/test/xpcshell/xpcshell.ini
@@ -25,17 +25,16 @@ skip-if = toolkit == 'android'
 [test_registration_missing_scope.js]
 [test_registration_none.js]
 [test_registration_success.js]
 [test_unregister_empty_scope.js]
 [test_unregister_error.js]
 [test_unregister_invalid_json.js]
 [test_unregister_not_found.js]
 [test_unregister_success.js]
-[test_webapps_cleardata.js]
 #http2 test
 [test_resubscribe_4xxCode_http2.js]
 [test_resubscribe_5xxCode_http2.js]
 [test_resubscribe_listening_for_msg_error_http2.js]
 [test_register_5xxCode_http2.js]
 [test_register_success_http2.js]
 skip-if = !hasNode
 run-sequentially = node server exceptions dont replay well
--- a/dom/webidl/ChromeUtils.webidl
+++ b/dom/webidl/ChromeUtils.webidl
@@ -13,24 +13,16 @@ interface ChromeUtils : ThreadSafeChrome
   /**
    * A helper that converts OriginAttributesDictionary to cookie jar opaque
    * identfier.
    *
    * @param originAttrs       The originAttributes from the caller.
    */
   static ByteString
   originAttributesToCookieJar(optional OriginAttributesDictionary originAttrs);
-
-  /**
-   * A helper that converts OriginAttributesDictionary to a opaque suffix string.
-   *
-   * @param originAttrs       The originAttributes from the caller.
-   */
-  static ByteString
-  originAttributesToSuffix(optional OriginAttributesDictionary originAttrs);
 };
 
 /**
  * Used by principals and the script security manager to represent origin
  * attributes.
  *
  * IMPORTANT: If you add any members here, you need to update the
  * methods on mozilla::OriginAttributes, and bump the CIDs of all
--- a/dom/webidl/PushSubscription.webidl
+++ b/dom/webidl/PushSubscription.webidl
@@ -2,18 +2,16 @@
 /* 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/.
 *
 * The origin of this IDL file is
 * https://w3c.github.io/push-api/
 */
 
-interface Principal;
-
 [JSImplementation="@mozilla.org/push/PushSubscription;1",
- Constructor(DOMString pushEndpoint, DOMString scope, Principal principal), ChromeOnly]
+ Constructor(DOMString pushEndpoint, DOMString scope, DOMString pageURL), ChromeOnly]
 interface PushSubscription
 {
     readonly attribute USVString endpoint;
     Promise<boolean> unsubscribe();
     jsonifier;
 };
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -2195,78 +2195,76 @@ public:
     globalScope->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
     return true;
   }
 };
 
 #endif /* ! MOZ_SIMPLEPUSH */
 
 NS_IMETHODIMP
-ServiceWorkerManager::SendPushEvent(const nsACString& aOriginAttributes,
+ServiceWorkerManager::SendPushEvent(JS::Handle<JS::Value> aOriginAttributes,
                                     const nsACString& aScope,
-                                    const nsAString& aData)
+                                    const nsAString& aData,
+                                    JSContext* aCx)
 {
 #ifdef MOZ_SIMPLEPUSH
   return NS_ERROR_NOT_AVAILABLE;
 #else
   OriginAttributes attrs;
-  if (!attrs.PopulateFromSuffix(aOriginAttributes)) {
+  if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   nsRefPtr<ServiceWorker> serviceWorker =
     CreateServiceWorkerForScope(attrs, aScope);
   if (!serviceWorker) {
     return NS_ERROR_FAILURE;
   }
 
   nsMainThreadPtrHandle<ServiceWorker> serviceWorkerHandle(
     new nsMainThreadPtrHolder<ServiceWorker>(serviceWorker));
 
   nsRefPtr<SendPushEventRunnable> r =
     new SendPushEventRunnable(serviceWorker->GetWorkerPrivate(), aData,
                               serviceWorkerHandle);
 
-  AutoJSAPI jsapi;
-  jsapi.Init();
-  if (NS_WARN_IF(!r->Dispatch(jsapi.cx()))) {
+  if (NS_WARN_IF(!r->Dispatch(aCx))) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 #endif
 }
 
 NS_IMETHODIMP
-ServiceWorkerManager::SendPushSubscriptionChangeEvent(const nsACString& aOriginAttributes,
-                                                      const nsACString& aScope)
+ServiceWorkerManager::SendPushSubscriptionChangeEvent(JS::Handle<JS::Value> aOriginAttributes,
+                                                      const nsACString& aScope,
+                                                      JSContext* aCx)
 {
 #ifdef MOZ_SIMPLEPUSH
   return NS_ERROR_NOT_AVAILABLE;
 #else
   OriginAttributes attrs;
-  if (!attrs.PopulateFromSuffix(aOriginAttributes)) {
+  if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   nsRefPtr<ServiceWorker> serviceWorker =
     CreateServiceWorkerForScope(attrs, aScope);
   if (!serviceWorker) {
     return NS_ERROR_FAILURE;
   }
   nsMainThreadPtrHandle<ServiceWorker> serviceWorkerHandle(
     new nsMainThreadPtrHolder<ServiceWorker>(serviceWorker));
 
   nsRefPtr<SendPushSubscriptionChangeEventRunnable> r =
     new SendPushSubscriptionChangeEventRunnable(
       serviceWorker->GetWorkerPrivate(), serviceWorkerHandle);
 
-  AutoJSAPI jsapi;
-  jsapi.Init();
-  if (NS_WARN_IF(!r->Dispatch(jsapi.cx()))) {
+  if (NS_WARN_IF(!r->Dispatch(aCx))) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 #endif
 }
 
 NS_IMETHODIMP
--- a/toolkit/content/aboutServiceWorkers.js
+++ b/toolkit/content/aboutServiceWorkers.js
@@ -115,17 +115,17 @@ function display(info) {
 
   createItem(bundle.GetStringFromName('scope'), info.scope);
   createItem(bundle.GetStringFromName('scriptSpec'), info.scriptSpec, true);
   createItem(bundle.GetStringFromName('currentWorkerURL'), info.currentWorkerURL, true);
   createItem(bundle.GetStringFromName('activeCacheName'), info.activeCacheName);
   createItem(bundle.GetStringFromName('waitingCacheName'), info.waitingCacheName);
 
   let pushItem = createItem(bundle.GetStringFromName('pushEndpoint'), bundle.GetStringFromName('waiting'));
-  PushNotificationService.registration(info.scope, info.principal.originAttributes).then(
+  PushNotificationService.registration(info.scope).then(
     pushRecord => {
       pushItem.data = JSON.stringify(pushRecord);
     },
     error => {
       dump("about:serviceworkers - push registration failed\n");
     }
   );