--- a/dom/base/domerr.msg
+++ b/dom/base/domerr.msg
@@ -151,11 +151,13 @@ DOM4_MSG_DEF(InvalidStateError, "A mutat
DOM4_MSG_DEF(AbortError, "A request was aborted, for example through a call to FileHandle.abort.", NS_ERROR_DOM_FILEHANDLE_ABORT_ERR)
DOM4_MSG_DEF(QuotaExceededError, "The current file handle exceeded its quota limitations.", NS_ERROR_DOM_FILEHANDLE_QUOTA_ERR)
/* Push API errors. */
DOM4_MSG_DEF(InvalidStateError, "Invalid service worker registration.", NS_ERROR_DOM_PUSH_INVALID_REGISTRATION_ERR)
DOM4_MSG_DEF(PermissionDeniedError, "User denied permission to use the Push API.", NS_ERROR_DOM_PUSH_DENIED_ERR)
DOM4_MSG_DEF(AbortError, "Error retrieving push subscription.", NS_ERROR_DOM_PUSH_ABORT_ERR)
DOM4_MSG_DEF(NetworkError, "Push service unreachable.", NS_ERROR_DOM_PUSH_SERVICE_UNREACHABLE)
+DOM4_MSG_DEF(InvalidAccessError, "Invalid raw ECDSA P-256 public key.", NS_ERROR_DOM_PUSH_INVALID_KEY_ERR)
+DOM4_MSG_DEF(InvalidStateError, "A subscription with a different application server key already exists.", NS_ERROR_DOM_PUSH_MISMATCHED_KEY_ERR)
DOM_MSG_DEF(NS_ERROR_DOM_JS_EXCEPTION, "A callback threw an exception")
DOM_MSG_DEF(NS_ERROR_DOM_DOMEXCEPTION, "A DOMException was thrown")
--- a/dom/interfaces/push/nsIPushService.idl
+++ b/dom/interfaces/push/nsIPushService.idl
@@ -92,16 +92,26 @@ interface nsIPushService : nsISupports
* 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.
*/
void subscribe(in DOMString scope, in nsIPrincipal principal,
in nsIPushSubscriptionCallback callback);
/**
+ * Creates a restricted push subscription with the given public |key|. The
+ * application server must use the corresponding private key to authenticate
+ * message delivery requests, as described in draft-thomson-webpush-vapid.
+ */
+ void subscribeWithKey(in DOMString scope, in nsIPrincipal principal,
+ in uint32_t keyLength,
+ [const, array, size_is(keyLength)] in uint8_t key,
+ in nsIPushSubscriptionCallback callback);
+
+ /**
* Removes a push subscription for the given |scope|.
*/
void unsubscribe(in DOMString scope, in nsIPrincipal principal,
in nsIUnsubscribeResultCallback callback);
/**
* Retrieves the subscription record associated with the given
* |(scope, principal)| pair. If the subscription does not exist, the
--- a/dom/push/Push.js
+++ b/dom/push/Push.js
@@ -41,37 +41,37 @@ Push.prototype = {
contractID: "@mozilla.org/push/PushManager;1",
classID : PUSH_CID,
QueryInterface : XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
Ci.nsISupportsWeakReference,
Ci.nsIObserver]),
- init: function(aWindow) {
+ init: function(window) {
console.debug("init()");
- this._window = aWindow;
+ this._window = window;
- this.initDOMRequestHelper(aWindow);
+ this.initDOMRequestHelper(window);
- this._principal = aWindow.document.nodePrincipal;
+ this._principal = window.document.nodePrincipal;
},
__init: function(scope) {
this._scope = scope;
},
- askPermission: function (aAllowCallback, aCancelCallback) {
+ askPermission: function () {
console.debug("askPermission()");
return this.createPromise((resolve, reject) => {
let permissionDenied = () => {
reject(new this._window.DOMException(
- "User denied permission to use the Push API",
+ "User denied permission to use the Push API.",
"PermissionDeniedError"
));
};
let permission = Ci.nsIPermissionManager.UNKNOWN_ACTION;
try {
permission = this._testPermission();
} catch (e) {
@@ -84,25 +84,40 @@ Push.prototype = {
} else if (permission == Ci.nsIPermissionManager.DENY_ACTION) {
permissionDenied();
} else {
this._requestPermission(resolve, permissionDenied);
}
});
},
- subscribe: function() {
+ subscribe: function(options) {
console.debug("subscribe()", this._scope);
let histogram = Services.telemetry.getHistogramById("PUSH_API_USED");
histogram.add(true);
return this.askPermission().then(() =>
this.createPromise((resolve, reject) => {
let callback = new PushSubscriptionCallback(this, resolve, reject);
- PushService.subscribe(this._scope, this._principal, callback);
+
+ if (!options || !options.applicationServerKey) {
+ PushService.subscribe(this._scope, this._principal, callback);
+ return;
+ }
+
+ let appServerKey = options.applicationServerKey;
+ let keyView = new Uint8Array(ArrayBuffer.isView(appServerKey) ?
+ appServerKey.buffer : appServerKey);
+ if (keyView.byteLength === 0) {
+ callback._rejectWithError(Cr.NS_ERROR_DOM_PUSH_INVALID_KEY_ERR);
+ return;
+ }
+ PushService.subscribeWithKey(this._scope, this._principal,
+ appServerKey.length, appServerKey,
+ callback);
})
);
},
getSubscription: function() {
console.debug("getSubscription()", this._scope);
return this.createPromise((resolve, reject) => {
@@ -185,43 +200,74 @@ function PushSubscriptionCallback(pushMa
}
PushSubscriptionCallback.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPushSubscriptionCallback]),
onPushSubscription: function(ok, subscription) {
let {pushManager} = this;
if (!Components.isSuccessCode(ok)) {
- this.reject(new pushManager._window.DOMException(
- "Error retrieving push subscription",
- "AbortError"
- ));
+ this._rejectWithError(ok);
return;
}
if (!subscription) {
this.resolve(null);
return;
}
- let publicKey = this._getKey(subscription, "p256dh");
+ let p256dhKey = this._getKey(subscription, "p256dh");
let authSecret = this._getKey(subscription, "auth");
- let sub = new pushManager._window.PushSubscription(subscription.endpoint,
- pushManager._scope,
- publicKey,
- authSecret);
+ let options = {
+ endpoint: subscription.endpoint,
+ scope: pushManager._scope,
+ p256dhKey: p256dhKey,
+ authSecret: authSecret,
+ };
+ let appServerKey = this._getKey(subscription, "appServer");
+ if (appServerKey) {
+ // Avoid passing null keys to work around bug 1256449.
+ options.appServerKey = appServerKey;
+ }
+ let sub = new pushManager._window.PushSubscription(options);
this.resolve(sub);
},
_getKey: function(subscription, name) {
let outKeyLen = {};
let rawKey = subscription.getKey(name, outKeyLen);
if (!outKeyLen.value) {
return null;
}
let key = new ArrayBuffer(outKeyLen.value);
let keyView = new Uint8Array(key);
keyView.set(rawKey);
return key;
},
+
+ _rejectWithError: function(result) {
+ let error;
+ switch (result) {
+ case Cr.NS_ERROR_DOM_PUSH_INVALID_KEY_ERR:
+ error = new this.pushManager._window.DOMException(
+ "Invalid raw ECDSA P-256 public key.",
+ "InvalidAccessError"
+ );
+ break;
+
+ case Cr.NS_ERROR_DOM_PUSH_MISMATCHED_KEY_ERR:
+ error = new this.pushManager._window.DOMException(
+ "A subscription with a different application server key already exists.",
+ "InvalidStateError"
+ );
+ break;
+
+ default:
+ error = new this.pushManager._window.DOMException(
+ "Error retrieving push subscription.",
+ "AbortError"
+ );
+ }
+ this.reject(error);
+ },
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Push]);
--- a/dom/push/PushManager.cpp
+++ b/dom/push/PushManager.cpp
@@ -5,16 +5,18 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/PushManager.h"
#include "mozilla/Services.h"
#include "mozilla/unused.h"
#include "mozilla/dom/PushManagerBinding.h"
#include "mozilla/dom/PushSubscription.h"
+#include "mozilla/dom/PushSubscriptionOptionsBinding.h"
+#include "mozilla/dom/PushUtil.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseWorkerProxy.h"
#include "nsIGlobalObject.h"
#include "nsIPermissionManager.h"
#include "nsIPrincipal.h"
#include "nsIPushService.h"
@@ -58,46 +60,124 @@ GetPermissionState(nsIPrincipal* aPrinci
aState = PushPermissionState::Denied;
} else {
aState = PushPermissionState::Prompt;
}
return NS_OK;
}
+// A helper class that frees an `nsIPushSubscription` key buffer when it
+// goes out of scope.
+class MOZ_RAII AutoFreeKeyBuffer final
+{
+ uint8_t** mKeyBuffer;
+
+public:
+ explicit AutoFreeKeyBuffer(uint8_t** aKeyBuffer)
+ : mKeyBuffer(aKeyBuffer)
+ {
+ MOZ_ASSERT(mKeyBuffer);
+ }
+
+ ~AutoFreeKeyBuffer()
+ {
+ NS_Free(*mKeyBuffer);
+ }
+};
+
+// Copies a subscription key buffer into an array.
+nsresult
+CopySubscriptionKeyToArray(nsIPushSubscription* aSubscription,
+ const nsAString& aKeyName,
+ nsTArray<uint8_t>& aKey)
+{
+ uint8_t* keyBuffer = nullptr;
+ AutoFreeKeyBuffer autoFree(&keyBuffer);
+
+ uint32_t keyLen;
+ nsresult rv = aSubscription->GetKey(aKeyName, &keyLen, &keyBuffer);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ if (!aKey.SetLength(keyLen, fallible) ||
+ !aKey.ReplaceElementsAt(0, keyLen, keyBuffer, keyLen, fallible)) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ return NS_OK;
+}
+
+nsresult
+GetSubscriptionParams(nsIPushSubscription* aSubscription,
+ nsAString& aEndpoint,
+ nsTArray<uint8_t>& aRawP256dhKey,
+ nsTArray<uint8_t>& aAuthSecret,
+ nsTArray<uint8_t>& aAppServerKey)
+{
+ if (!aSubscription) {
+ return NS_OK;
+ }
+
+ nsresult rv = aSubscription->GetEndpoint(aEndpoint);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ rv = CopySubscriptionKeyToArray(aSubscription, NS_LITERAL_STRING("p256dh"),
+ aRawP256dhKey);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ rv = CopySubscriptionKeyToArray(aSubscription, NS_LITERAL_STRING("auth"),
+ aAuthSecret);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ rv = CopySubscriptionKeyToArray(aSubscription, NS_LITERAL_STRING("appServer"),
+ aAppServerKey);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ return NS_OK;
+}
+
class GetSubscriptionResultRunnable final : public WorkerRunnable
{
public:
GetSubscriptionResultRunnable(WorkerPrivate* aWorkerPrivate,
already_AddRefed<PromiseWorkerProxy>&& aProxy,
nsresult aStatus,
const nsAString& aEndpoint,
const nsAString& aScope,
nsTArray<uint8_t>&& aRawP256dhKey,
- nsTArray<uint8_t>&& aAuthSecret)
+ nsTArray<uint8_t>&& aAuthSecret,
+ nsTArray<uint8_t>&& aAppServerKey)
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
, mProxy(Move(aProxy))
, mStatus(aStatus)
, mEndpoint(aEndpoint)
, mScope(aScope)
, mRawP256dhKey(Move(aRawP256dhKey))
, mAuthSecret(Move(aAuthSecret))
+ , mAppServerKey(Move(aAppServerKey))
{ }
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
RefPtr<Promise> promise = mProxy->WorkerPromise();
if (NS_SUCCEEDED(mStatus)) {
if (mEndpoint.IsEmpty()) {
promise->MaybeResolve(JS::NullHandleValue);
} else {
RefPtr<PushSubscription> sub =
new PushSubscription(nullptr, mEndpoint, mScope,
- Move(mRawP256dhKey), Move(mAuthSecret));
+ Move(mRawP256dhKey), Move(mAuthSecret),
+ Move(mAppServerKey));
promise->MaybeResolve(sub);
}
} else if (NS_ERROR_GET_MODULE(mStatus) == NS_ERROR_MODULE_DOM_PUSH ) {
promise->MaybeReject(mStatus);
} else {
promise->MaybeReject(NS_ERROR_DOM_PUSH_ABORT_ERR);
}
@@ -110,16 +190,17 @@ private:
{}
RefPtr<PromiseWorkerProxy> mProxy;
nsresult mStatus;
nsString mEndpoint;
nsString mScope;
nsTArray<uint8_t> mRawP256dhKey;
nsTArray<uint8_t> mAuthSecret;
+ nsTArray<uint8_t> mAppServerKey;
};
class GetSubscriptionCallback final : public nsIPushSubscriptionCallback
{
public:
NS_DECL_ISUPPORTS
explicit GetSubscriptionCallback(PromiseWorkerProxy* aProxy,
@@ -136,31 +217,32 @@ public:
MOZ_ASSERT(mProxy, "OnPushSubscription() called twice?");
MutexAutoLock lock(mProxy->Lock());
if (mProxy->CleanedUp()) {
return NS_OK;
}
nsAutoString endpoint;
- nsTArray<uint8_t> rawP256dhKey, authSecret;
+ nsTArray<uint8_t> rawP256dhKey, authSecret, appServerKey;
if (NS_SUCCEEDED(aStatus)) {
aStatus = GetSubscriptionParams(aSubscription, endpoint, rawP256dhKey,
- authSecret);
+ authSecret, appServerKey);
}
WorkerPrivate* worker = mProxy->GetWorkerPrivate();
RefPtr<GetSubscriptionResultRunnable> r =
new GetSubscriptionResultRunnable(worker,
mProxy.forget(),
aStatus,
endpoint,
mScope,
Move(rawP256dhKey),
- Move(authSecret));
+ Move(authSecret),
+ Move(appServerKey));
MOZ_ALWAYS_TRUE(r->Dispatch());
return NS_OK;
}
// Convenience method for use in this file.
void
OnPushSubscriptionError(nsresult aStatus)
@@ -169,82 +251,33 @@ public:
OnPushSubscription(aStatus, nullptr)));
}
protected:
~GetSubscriptionCallback()
{}
private:
- inline nsresult
- FreeKeys(nsresult aStatus, uint8_t* aKey, uint8_t* aAuthSecret)
- {
- NS_Free(aKey);
- NS_Free(aAuthSecret);
-
- return aStatus;
- }
-
- nsresult
- GetSubscriptionParams(nsIPushSubscription* aSubscription,
- nsAString& aEndpoint,
- nsTArray<uint8_t>& aRawP256dhKey,
- nsTArray<uint8_t>& aAuthSecret)
- {
- if (!aSubscription) {
- return NS_OK;
- }
-
- nsresult rv = aSubscription->GetEndpoint(aEndpoint);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- uint8_t* key = nullptr;
- uint8_t* authSecret = nullptr;
-
- uint32_t keyLen;
- rv = aSubscription->GetKey(NS_LITERAL_STRING("p256dh"), &keyLen, &key);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return FreeKeys(rv, key, authSecret);
- }
-
- uint32_t authSecretLen;
- rv = aSubscription->GetKey(NS_LITERAL_STRING("auth"), &authSecretLen,
- &authSecret);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return FreeKeys(rv, key, authSecret);
- }
-
- if (!aRawP256dhKey.SetLength(keyLen, fallible) ||
- !aRawP256dhKey.ReplaceElementsAt(0, keyLen, key, keyLen, fallible) ||
- !aAuthSecret.SetLength(authSecretLen, fallible) ||
- !aAuthSecret.ReplaceElementsAt(0, authSecretLen, authSecret,
- authSecretLen, fallible)) {
-
- return FreeKeys(NS_ERROR_OUT_OF_MEMORY, key, authSecret);
- }
-
- return FreeKeys(NS_OK, key, authSecret);
- }
-
RefPtr<PromiseWorkerProxy> mProxy;
nsString mScope;
};
NS_IMPL_ISUPPORTS(GetSubscriptionCallback, nsIPushSubscriptionCallback)
class GetSubscriptionRunnable final : public nsRunnable
{
public:
GetSubscriptionRunnable(PromiseWorkerProxy* aProxy,
const nsAString& aScope,
- PushManager::SubscriptionAction aAction)
+ PushManager::SubscriptionAction aAction,
+ nsTArray<uint8_t>&& aAppServerKey)
: mProxy(aProxy)
- , mScope(aScope), mAction(aAction)
+ , mScope(aScope)
+ , mAction(aAction)
+ , mAppServerKey(Move(aAppServerKey))
{}
NS_IMETHOD
Run() override
{
AssertIsOnMainThread();
nsCOMPtr<nsIPrincipal> principal;
@@ -284,17 +317,23 @@ public:
nsCOMPtr<nsIPushService> service =
do_GetService("@mozilla.org/push/Service;1");
if (NS_WARN_IF(!service)) {
callback->OnPushSubscriptionError(NS_ERROR_FAILURE);
return NS_OK;
}
if (mAction == PushManager::SubscribeAction) {
- rv = service->Subscribe(mScope, principal, callback);
+ if (mAppServerKey.IsEmpty()) {
+ rv = service->Subscribe(mScope, principal, callback);
+ } else {
+ rv = service->SubscribeWithKey(mScope, principal,
+ mAppServerKey.Length(),
+ mAppServerKey.Elements(), callback);
+ }
} else {
MOZ_ASSERT(mAction == PushManager::GetSubscriptionAction);
rv = service->GetSubscription(mScope, principal, callback);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
callback->OnPushSubscriptionError(NS_ERROR_FAILURE);
return NS_OK;
@@ -305,16 +344,17 @@ public:
private:
~GetSubscriptionRunnable()
{}
RefPtr<PromiseWorkerProxy> mProxy;
nsString mScope;
PushManager::SubscriptionAction mAction;
+ nsTArray<uint8_t> mAppServerKey;
};
class PermissionResultRunnable final : public WorkerRunnable
{
public:
PermissionResultRunnable(PromiseWorkerProxy *aProxy,
nsresult aStatus,
PushPermissionState aState)
@@ -448,43 +488,45 @@ PushManager::Constructor(GlobalObject& a
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
RefPtr<PushManager> ret = new PushManager(global, impl);
return ret.forget();
}
already_AddRefed<Promise>
-PushManager::Subscribe(ErrorResult& aRv)
+PushManager::Subscribe(const PushSubscriptionOptionsInit& aOptions,
+ ErrorResult& aRv)
{
if (mImpl) {
MOZ_ASSERT(NS_IsMainThread());
- return mImpl->Subscribe(aRv);
+ return mImpl->Subscribe(aOptions, aRv);
}
- return PerformSubscriptionActionFromWorker(SubscribeAction, aRv);
+ return PerformSubscriptionActionFromWorker(SubscribeAction, aOptions, aRv);
}
already_AddRefed<Promise>
PushManager::GetSubscription(ErrorResult& aRv)
{
if (mImpl) {
MOZ_ASSERT(NS_IsMainThread());
return mImpl->GetSubscription(aRv);
}
return PerformSubscriptionActionFromWorker(GetSubscriptionAction, aRv);
}
already_AddRefed<Promise>
-PushManager::PermissionState(ErrorResult& aRv)
+PushManager::PermissionState(const PushSubscriptionOptionsInit& aOptions,
+ ErrorResult& aRv)
{
if (mImpl) {
MOZ_ASSERT(NS_IsMainThread());
- return mImpl->PermissionState(aRv);
+ return mImpl->PermissionState(aOptions, aRv);
}
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(worker);
worker->AssertIsOnWorkerThread();
nsCOMPtr<nsIGlobalObject> global = worker->GlobalScope();
RefPtr<Promise> p = Promise::Create(global, aRv);
@@ -501,18 +543,27 @@ PushManager::PermissionState(ErrorResult
RefPtr<PermissionStateRunnable> r =
new PermissionStateRunnable(proxy);
NS_DispatchToMainThread(r);
return p.forget();
}
already_AddRefed<Promise>
-PushManager::PerformSubscriptionActionFromWorker(
- SubscriptionAction aAction, ErrorResult& aRv)
+PushManager::PerformSubscriptionActionFromWorker(SubscriptionAction aAction,
+ ErrorResult& aRv)
+{
+ PushSubscriptionOptionsInit options;
+ return PerformSubscriptionActionFromWorker(aAction, options, aRv);
+}
+
+already_AddRefed<Promise>
+PushManager::PerformSubscriptionActionFromWorker(SubscriptionAction aAction,
+ const PushSubscriptionOptionsInit& aOptions,
+ ErrorResult& aRv)
{
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(worker);
worker->AssertIsOnWorkerThread();
nsCOMPtr<nsIGlobalObject> global = worker->GlobalScope();
RefPtr<Promise> p = Promise::Create(global, aRv);
if (NS_WARN_IF(aRv.Failed())) {
@@ -520,17 +571,28 @@ PushManager::PerformSubscriptionActionFr
}
RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, p);
if (!proxy) {
p->MaybeReject(NS_ERROR_DOM_PUSH_ABORT_ERR);
return p.forget();
}
+ nsTArray<uint8_t> appServerKey;
+ if (!aOptions.mApplicationServerKey.IsNull()) {
+ const OwningArrayBufferViewOrArrayBuffer& bufferSource =
+ aOptions.mApplicationServerKey.Value();
+ if (!PushUtil::CopyBufferSourceToArray(bufferSource, appServerKey) ||
+ appServerKey.IsEmpty()) {
+ p->MaybeReject(NS_ERROR_DOM_PUSH_INVALID_KEY_ERR);
+ return p.forget();
+ }
+ }
+
RefPtr<GetSubscriptionRunnable> r =
- new GetSubscriptionRunnable(proxy, mScope, aAction);
+ new GetSubscriptionRunnable(proxy, mScope, aAction, Move(appServerKey));
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
return p.forget();
}
} // namespace dom
} // namespace mozilla
--- a/dom/push/PushManager.h
+++ b/dom/push/PushManager.h
@@ -43,16 +43,17 @@ namespace mozilla {
namespace dom {
namespace workers {
class WorkerPrivate;
}
class Promise;
class PushManagerImpl;
+struct PushSubscriptionOptionsInit;
class PushManager final : public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PushManager)
@@ -80,28 +81,33 @@ public:
Constructor(GlobalObject& aGlobal, const nsAString& aScope,
ErrorResult& aRv);
already_AddRefed<Promise>
PerformSubscriptionActionFromWorker(SubscriptionAction aAction,
ErrorResult& aRv);
already_AddRefed<Promise>
- Subscribe(ErrorResult& aRv);
+ PerformSubscriptionActionFromWorker(SubscriptionAction aAction,
+ const PushSubscriptionOptionsInit& aOptions,
+ ErrorResult& aRv);
+
+ already_AddRefed<Promise>
+ Subscribe(const PushSubscriptionOptionsInit& aOptions, ErrorResult& aRv);
already_AddRefed<Promise>
GetSubscription(ErrorResult& aRv);
already_AddRefed<Promise>
- PermissionState(ErrorResult& aRv);
+ PermissionState(const PushSubscriptionOptionsInit& aOptions,
+ ErrorResult& aRv);
-protected:
+private:
~PushManager();
-private:
// The following are only set and accessed on the main thread.
nsCOMPtr<nsIGlobalObject> mGlobal;
RefPtr<PushManagerImpl> mImpl;
// Only used on the worker thread.
nsString mScope;
};
} // namespace dom
--- a/dom/push/PushSubscription.cpp
+++ b/dom/push/PushSubscription.cpp
@@ -7,16 +7,18 @@
#include "nsIPushService.h"
#include "nsIScriptObjectPrincipal.h"
#include "mozilla/Base64.h"
#include "mozilla/unused.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseWorkerProxy.h"
+#include "mozilla/dom/PushSubscriptionOptions.h"
+#include "mozilla/dom/PushUtil.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerScope.h"
#include "mozilla/dom/workers/Workers.h"
namespace mozilla {
namespace dom {
using namespace workers;
@@ -186,97 +188,103 @@ public:
private:
~UnsubscribeRunnable()
{}
RefPtr<PromiseWorkerProxy> mProxy;
nsString mScope;
};
-bool
-CopyArrayBufferToArray(const ArrayBuffer& aBuffer,
- nsTArray<uint8_t>& aArray)
-{
- aBuffer.ComputeLengthAndData();
- if (!aArray.SetLength(aBuffer.Length(), fallible) ||
- !aArray.ReplaceElementsAt(0, aBuffer.Length(), aBuffer.Data(),
- aBuffer.Length(), fallible)) {
- return false;
- }
- return true;
-}
-
} // anonymous namespace
PushSubscription::PushSubscription(nsIGlobalObject* aGlobal,
const nsAString& aEndpoint,
const nsAString& aScope,
nsTArray<uint8_t>&& aRawP256dhKey,
- nsTArray<uint8_t>&& aAuthSecret)
+ nsTArray<uint8_t>&& aAuthSecret,
+ nsTArray<uint8_t>&& aAppServerKey)
: mEndpoint(aEndpoint)
, mScope(aScope)
, mRawP256dhKey(Move(aRawP256dhKey))
, mAuthSecret(Move(aAuthSecret))
{
if (NS_IsMainThread()) {
mGlobal = aGlobal;
} else {
#ifdef DEBUG
// There's only one global on a worker, so we don't need to pass a global
// object to the constructor.
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(worker);
worker->AssertIsOnWorkerThread();
#endif
}
+ mOptions = new PushSubscriptionOptions(mGlobal, Move(aAppServerKey));
}
PushSubscription::~PushSubscription()
{}
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PushSubscription, mGlobal)
-
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PushSubscription, mGlobal, mOptions)
NS_IMPL_CYCLE_COLLECTING_ADDREF(PushSubscription)
NS_IMPL_CYCLE_COLLECTING_RELEASE(PushSubscription)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PushSubscription)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
JSObject*
PushSubscription::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return PushSubscriptionBinding::Wrap(aCx, this, aGivenProto);
}
// static
already_AddRefed<PushSubscription>
PushSubscription::Constructor(GlobalObject& aGlobal,
- const nsAString& aEndpoint,
- const nsAString& aScope,
- const Nullable<ArrayBuffer>& aP256dhKey,
- const Nullable<ArrayBuffer>& aAuthSecret,
+ const PushSubscriptionInit& aInitDict,
ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
- nsTArray<uint8_t> rawKey, authSecret;
- if ((!aP256dhKey.IsNull() && !CopyArrayBufferToArray(aP256dhKey.Value(),
- rawKey)) ||
- (!aAuthSecret.IsNull() && !CopyArrayBufferToArray(aAuthSecret.Value(),
- authSecret))) {
+ nsTArray<uint8_t> rawKey;
+ if (aInitDict.mP256dhKey.WasPassed() &&
+ !aInitDict.mP256dhKey.Value().IsNull() &&
+ !PushUtil::CopyArrayBufferToArray(aInitDict.mP256dhKey.Value().Value(),
+ rawKey)) {
+ aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return nullptr;
+ }
+
+ nsTArray<uint8_t> authSecret;
+ if (aInitDict.mAuthSecret.WasPassed() &&
+ !aInitDict.mAuthSecret.Value().IsNull() &&
+ !PushUtil::CopyArrayBufferToArray(aInitDict.mAuthSecret.Value().Value(),
+ authSecret)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;
}
+ nsTArray<uint8_t> appServerKey;
+ if (aInitDict.mAppServerKey.WasPassed() &&
+ !aInitDict.mAppServerKey.Value().IsNull()) {
+ const OwningArrayBufferViewOrArrayBuffer& bufferSource =
+ aInitDict.mAppServerKey.Value().Value();
+ if (!PushUtil::CopyBufferSourceToArray(bufferSource, appServerKey)) {
+ aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return nullptr;
+ }
+ }
+
RefPtr<PushSubscription> sub = new PushSubscription(global,
- aEndpoint,
- aScope,
+ aInitDict.mEndpoint,
+ aInitDict.mScope,
Move(rawKey),
- Move(authSecret));
+ Move(authSecret),
+ Move(appServerKey));
return sub.forget();
}
already_AddRefed<Promise>
PushSubscription::Unsubscribe(ErrorResult& aRv)
{
if (!NS_IsMainThread()) {
@@ -310,26 +318,23 @@ PushSubscription::Unsubscribe(ErrorResul
service->Unsubscribe(mScope, sop->GetPrincipal(), callback)));
return p.forget();
}
void
PushSubscription::GetKey(JSContext* aCx,
PushEncryptionKeyName aType,
- JS::MutableHandle<JSObject*> aKey)
+ JS::MutableHandle<JSObject*> aKey,
+ ErrorResult& aRv)
{
- if (aType == PushEncryptionKeyName::P256dh && !mRawP256dhKey.IsEmpty()) {
- aKey.set(ArrayBuffer::Create(aCx,
- mRawP256dhKey.Length(),
- mRawP256dhKey.Elements()));
- } else if (aType == PushEncryptionKeyName::Auth && !mAuthSecret.IsEmpty()) {
- aKey.set(ArrayBuffer::Create(aCx,
- mAuthSecret.Length(),
- mAuthSecret.Elements()));
+ if (aType == PushEncryptionKeyName::P256dh) {
+ PushUtil::CopyArrayToArrayBuffer(aCx, mRawP256dhKey, aKey, aRv);
+ } else if (aType == PushEncryptionKeyName::Auth) {
+ PushUtil::CopyArrayToArrayBuffer(aCx, mAuthSecret, aKey, aRv);
} else {
aKey.set(nullptr);
}
}
void
PushSubscription::ToJSON(PushSubscriptionJSON& aJSON, ErrorResult& aRv)
{
@@ -353,16 +358,23 @@ PushSubscription::ToJSON(PushSubscriptio
rv = Base64URLEncode(mAuthSecret.Length(), mAuthSecret.Elements(),
encodeOptions, aJSON.mKeys.mAuth.Value());
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
return;
}
}
+already_AddRefed<PushSubscriptionOptions>
+PushSubscription::Options()
+{
+ RefPtr<PushSubscriptionOptions> options = mOptions;
+ return options.forget();
+}
+
already_AddRefed<Promise>
PushSubscription::UnsubscribeFromWorker(ErrorResult& aRv)
{
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(worker);
worker->AssertIsOnWorkerThread();
nsCOMPtr<nsIGlobalObject> global = worker->GlobalScope();
--- a/dom/push/PushSubscription.h
+++ b/dom/push/PushSubscription.h
@@ -10,16 +10,17 @@
#include "nsWrapperCache.h"
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/RefPtr.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/PushSubscriptionBinding.h"
+#include "mozilla/dom/PushSubscriptionOptionsBinding.h"
#include "mozilla/dom/TypedArray.h"
class nsIGlobalObject;
namespace mozilla {
namespace dom {
namespace workers {
@@ -34,17 +35,18 @@ class PushSubscription final : public ns
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PushSubscription)
PushSubscription(nsIGlobalObject* aGlobal,
const nsAString& aEndpoint,
const nsAString& aScope,
nsTArray<uint8_t>&& aP256dhKey,
- nsTArray<uint8_t>&& aAuthSecret);
+ nsTArray<uint8_t>&& aAuthSecret,
+ nsTArray<uint8_t>&& aAppServerKey);
JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
nsIGlobalObject*
GetParentObject() const
{
return mGlobal;
@@ -54,42 +56,43 @@ public:
GetEndpoint(nsAString& aEndpoint) const
{
aEndpoint = mEndpoint;
}
void
GetKey(JSContext* cx,
PushEncryptionKeyName aType,
- JS::MutableHandle<JSObject*> aKey);
+ JS::MutableHandle<JSObject*> aKey,
+ ErrorResult& aRv);
static already_AddRefed<PushSubscription>
Constructor(GlobalObject& aGlobal,
- const nsAString& aEndpoint,
- const nsAString& aScope,
- const Nullable<ArrayBuffer>& aP256dhKey,
- const Nullable<ArrayBuffer>& aAuthSecret,
+ const PushSubscriptionInit& aInitDict,
ErrorResult& aRv);
already_AddRefed<Promise>
Unsubscribe(ErrorResult& aRv);
void
ToJSON(PushSubscriptionJSON& aJSON, ErrorResult& aRv);
-protected:
+ already_AddRefed<PushSubscriptionOptions>
+ Options();
+
+private:
~PushSubscription();
-private:
already_AddRefed<Promise>
UnsubscribeFromWorker(ErrorResult& aRv);
nsString mEndpoint;
nsString mScope;
nsTArray<uint8_t> mRawP256dhKey;
nsTArray<uint8_t> mAuthSecret;
nsCOMPtr<nsIGlobalObject> mGlobal;
+ RefPtr<PushSubscriptionOptions> mOptions;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_PushSubscription_h
new file mode 100644
--- /dev/null
+++ b/dom/push/PushSubscriptionOptions.cpp
@@ -0,0 +1,48 @@
+/* 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/. */
+
+#include "mozilla/dom/PushSubscriptionOptions.h"
+
+#include "mozilla/dom/PushSubscriptionOptionsBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+PushSubscriptionOptions::PushSubscriptionOptions(nsIGlobalObject* aGlobal,
+ nsTArray<uint8_t>&& aAppServerKey)
+ : mGlobal(aGlobal)
+ , mAppServerKey(Move(aAppServerKey))
+{
+ // There's only one global on a worker, so we don't need to pass a global
+ // object to the constructor.
+ MOZ_ASSERT_IF(NS_IsMainThread(), mGlobal);
+}
+
+PushSubscriptionOptions::~PushSubscriptionOptions() {}
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PushSubscriptionOptions, mGlobal)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(PushSubscriptionOptions)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(PushSubscriptionOptions)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PushSubscriptionOptions)
+ NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+JSObject*
+PushSubscriptionOptions::WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto)
+{
+ return PushSubscriptionOptionsBinding::Wrap(aCx, this, aGivenProto);
+}
+
+void
+PushSubscriptionOptions::GetApplicationServerKey(JSContext* aCx,
+ JS::MutableHandle<JSObject*> aKey,
+ ErrorResult& aRv)
+{
+ PushUtil::CopyArrayToArrayBuffer(aCx, mAppServerKey, aKey, aRv);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/push/PushSubscriptionOptions.h
@@ -0,0 +1,45 @@
+/* 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/. */
+
+#ifndef mozilla_dom_PushSubscriptionOptions_h
+#define mozilla_dom_PushSubscriptionOptions_h
+
+namespace mozilla {
+namespace dom {
+
+class PushSubscriptionOptions final : public nsISupports
+ , public nsWrapperCache
+{
+public:
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PushSubscriptionOptions)
+
+ PushSubscriptionOptions(nsIGlobalObject* aGlobal,
+ nsTArray<uint8_t>&& aAppServerKey);
+
+ nsIGlobalObject*
+ GetParentObject() const
+ {
+ return mGlobal;
+ }
+
+ JSObject*
+ WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+ void
+ GetApplicationServerKey(JSContext* aCx,
+ JS::MutableHandle<JSObject*> aKey,
+ ErrorResult& aRv);
+
+private:
+ ~PushSubscriptionOptions();
+
+ nsCOMPtr<nsIGlobalObject> mGlobal;
+ nsTArray<uint8_t> mAppServerKey;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_PushSubscriptionOptions_h
new file mode 100644
--- /dev/null
+++ b/dom/push/PushUtil.cpp
@@ -0,0 +1,58 @@
+/* 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/. */
+
+#include "mozilla/dom/PushUtil.h"
+
+namespace mozilla {
+namespace dom {
+
+/* static */ bool
+PushUtil::CopyArrayBufferToArray(const ArrayBuffer& aBuffer,
+ nsTArray<uint8_t>& aArray)
+{
+ aBuffer.ComputeLengthAndData();
+ return aArray.SetLength(aBuffer.Length(), fallible) &&
+ aArray.ReplaceElementsAt(0, aBuffer.Length(), aBuffer.Data(),
+ aBuffer.Length(), fallible);
+}
+
+/* static */ bool
+PushUtil::CopyBufferSourceToArray(
+ const OwningArrayBufferViewOrArrayBuffer& aSource, nsTArray<uint8_t>& aArray)
+{
+ if (aSource.IsArrayBuffer()) {
+ return CopyArrayBufferToArray(aSource.GetAsArrayBuffer(), aArray);
+ }
+ if (aSource.IsArrayBufferView()) {
+ const ArrayBufferView& view = aSource.GetAsArrayBufferView();
+ view.ComputeLengthAndData();
+ return aArray.SetLength(view.Length(), fallible) &&
+ aArray.ReplaceElementsAt(0, view.Length(), view.Data(),
+ view.Length(), fallible);
+ }
+ MOZ_CRASH("Uninitialized union: expected buffer or view");
+}
+
+/* static */ void
+PushUtil::CopyArrayToArrayBuffer(JSContext* aCx,
+ const nsTArray<uint8_t>& aArray,
+ JS::MutableHandle<JSObject*> aValue,
+ ErrorResult& aRv)
+{
+ if (aArray.IsEmpty()) {
+ aValue.set(nullptr);
+ return;
+ }
+ JS::Rooted<JSObject*> buffer(aCx, ArrayBuffer::Create(aCx,
+ aArray.Length(),
+ aArray.Elements()));
+ if (NS_WARN_IF(!buffer)) {
+ aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+ aValue.set(buffer);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/push/PushUtil.h
@@ -0,0 +1,35 @@
+/* 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/. */
+
+#ifndef mozilla_dom_PushUtil_h
+#define mozilla_dom_PushUtil_h
+
+namespace mozilla {
+namespace dom {
+
+class OwningArrayBufferViewOrArrayBuffer;
+
+class PushUtil final
+{
+private:
+ PushUtil() = delete;
+
+public:
+ static bool
+ CopyArrayBufferToArray(const ArrayBuffer& aBuffer,
+ nsTArray<uint8_t>& aArray);
+
+ static bool
+ CopyBufferSourceToArray(const OwningArrayBufferViewOrArrayBuffer& aSource,
+ nsTArray<uint8_t>& aArray);
+
+ static void
+ CopyArrayToArrayBuffer(JSContext* aCx, const nsTArray<uint8_t>& aArray,
+ JS::MutableHandle<JSObject*> aValue, ErrorResult& aRv);
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_PushUtil_h
--- a/dom/push/moz.build
+++ b/dom/push/moz.build
@@ -35,22 +35,26 @@ MOCHITEST_MANIFESTS += [
XPCSHELL_TESTS_MANIFESTS += [
'test/xpcshell/xpcshell.ini',
]
EXPORTS.mozilla.dom += [
'PushManager.h',
'PushNotifier.h',
'PushSubscription.h',
+ 'PushSubscriptionOptions.h',
+ 'PushUtil.h',
]
UNIFIED_SOURCES += [
'PushManager.cpp',
'PushNotifier.cpp',
'PushSubscription.cpp',
+ 'PushSubscriptionOptions.cpp',
+ 'PushUtil.cpp',
]
TEST_DIRS += ['test/xpcshell']
include('/ipc/chromium/chromium-config.mozbuild')
if CONFIG['GNU_CXX']:
CXXFLAGS += ['-Wshadow']
--- a/dom/webidl/PushManager.webidl
+++ b/dom/webidl/PushManager.webidl
@@ -2,35 +2,40 @@
/* 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/
*/
+dictionary PushSubscriptionOptionsInit {
+ // boolean userVisibleOnly = false;
+ BufferSource? applicationServerKey = null;
+};
+
// The main thread JS implementation. Please see comments in
// dom/push/PushManager.h for the split between PushManagerImpl and PushManager.
[JSImplementation="@mozilla.org/push/PushManager;1",
ChromeOnly, Constructor(DOMString scope)]
interface PushManagerImpl {
- Promise<PushSubscription> subscribe();
+ Promise<PushSubscription> subscribe(optional PushSubscriptionOptionsInit options);
Promise<PushSubscription?> getSubscription();
- Promise<PushPermissionState> permissionState();
+ Promise<PushPermissionState> permissionState(optional PushSubscriptionOptionsInit options);
};
[Exposed=(Window,Worker), Func="nsContentUtils::PushEnabled",
ChromeConstructor(DOMString scope)]
interface PushManager {
[Throws, UseCounter]
- Promise<PushSubscription> subscribe();
+ Promise<PushSubscription> subscribe(optional PushSubscriptionOptionsInit options);
[Throws]
Promise<PushSubscription?> getSubscription();
[Throws]
- Promise<PushPermissionState> permissionState();
+ Promise<PushPermissionState> permissionState(optional PushSubscriptionOptionsInit options);
};
enum PushPermissionState
{
"granted",
"denied",
"prompt"
};
--- a/dom/webidl/PushSubscription.webidl
+++ b/dom/webidl/PushSubscription.webidl
@@ -22,22 +22,32 @@ dictionary PushSubscriptionKeys
};
dictionary PushSubscriptionJSON
{
USVString endpoint;
PushSubscriptionKeys keys;
};
+dictionary PushSubscriptionInit
+{
+ required USVString endpoint;
+ required USVString scope;
+ ArrayBuffer? p256dhKey;
+ ArrayBuffer? authSecret;
+ BufferSource? appServerKey;
+};
+
[Exposed=(Window,Worker), Func="nsContentUtils::PushEnabled",
- ChromeConstructor(DOMString pushEndpoint, DOMString scope,
- ArrayBuffer? key, ArrayBuffer? authSecret)]
+ ChromeConstructor(PushSubscriptionInit initDict)]
interface PushSubscription
{
- readonly attribute USVString endpoint;
- ArrayBuffer? getKey(PushEncryptionKeyName name);
- [Throws, UseCounter]
- Promise<boolean> unsubscribe();
+ readonly attribute USVString endpoint;
+ readonly attribute PushSubscriptionOptions options;
+ [Throws]
+ ArrayBuffer? getKey(PushEncryptionKeyName name);
+ [Throws, UseCounter]
+ Promise<boolean> unsubscribe();
- // Implements the custom serializer specified in Push API, section 9.
- [Throws]
- PushSubscriptionJSON toJSON();
+ // Implements the custom serializer specified in Push API, section 9.
+ [Throws]
+ PushSubscriptionJSON toJSON();
};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/PushSubscriptionOptions.webidl
@@ -0,0 +1,15 @@
+/* -*- 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/.
+*
+* The origin of this IDL file is
+* https://w3c.github.io/push-api/
+*/
+
+[Exposed=(Window,Worker), Func="nsContentUtils::PushEnabled"]
+interface PushSubscriptionOptions
+{
+ [Throws]
+ readonly attribute ArrayBuffer? applicationServerKey;
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -721,16 +721,17 @@ if CONFIG['MOZ_SIMPLEPUSH']:
]
else:
WEBIDL_FILES += [
'PushEvent.webidl',
'PushManager.webidl',
'PushManager.webidl',
'PushMessageData.webidl',
'PushSubscription.webidl',
+ 'PushSubscriptionOptions.webidl',
]
if CONFIG['MOZ_NFC']:
WEBIDL_FILES += [
'MozIsoDepTech.webidl',
'MozNDEFRecord.webidl',
'MozNFC.webidl',
'MozNfcATech.webidl',
--- a/js/xpconnect/src/xpc.msg
+++ b/js/xpconnect/src/xpc.msg
@@ -213,8 +213,12 @@ XPC_MSG_DEF(NS_ERROR_GFX_PRINTER_NAME_NO
XPC_MSG_DEF(NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE , "Failed to open output file for print to file.")
XPC_MSG_DEF(NS_ERROR_GFX_PRINTER_STARTDOC , "Printing failed while starting the print job.")
XPC_MSG_DEF(NS_ERROR_GFX_PRINTER_ENDDOC , "Printing failed while completing the print job.")
XPC_MSG_DEF(NS_ERROR_GFX_PRINTER_STARTPAGE , "Printing failed while starting a new page.")
XPC_MSG_DEF(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY , "Cannot print this document yet, it is still being loaded.")
/* Codes related to content */
XPC_MSG_DEF(NS_ERROR_CONTENT_CRASHED , "The process that hosted this content has crashed.")
+
+/* Codes for the JS-implemented Push DOM API. These can be removed as part of bug 1252660. */
+XPC_MSG_DEF(NS_ERROR_DOM_PUSH_INVALID_KEY_ERR , "Invalid raw ECDSA P-256 public key.")
+XPC_MSG_DEF(NS_ERROR_DOM_PUSH_MISMATCHED_KEY_ERR , "A subscription with a different application server key already exists.")
--- a/xpcom/base/ErrorList.h
+++ b/xpcom/base/ErrorList.h
@@ -946,19 +946,21 @@
ERROR(NS_ERROR_DOM_ANIM_NO_TARGET_ERR, FAILURE(2)),
#undef MODULE
/* ======================================================================= */
/* 40: NS_ERROR_MODULE_DOM_PUSH */
/* ======================================================================= */
#define MODULE NS_ERROR_MODULE_DOM_PUSH
ERROR(NS_ERROR_DOM_PUSH_INVALID_REGISTRATION_ERR, FAILURE(1)),
- ERROR(NS_ERROR_DOM_PUSH_DENIED_ERR, FAILURE(2)),
- ERROR(NS_ERROR_DOM_PUSH_ABORT_ERR, FAILURE(3)),
- ERROR(NS_ERROR_DOM_PUSH_SERVICE_UNREACHABLE, FAILURE(4)),
+ ERROR(NS_ERROR_DOM_PUSH_DENIED_ERR, FAILURE(2)),
+ ERROR(NS_ERROR_DOM_PUSH_ABORT_ERR, FAILURE(3)),
+ ERROR(NS_ERROR_DOM_PUSH_SERVICE_UNREACHABLE, FAILURE(4)),
+ ERROR(NS_ERROR_DOM_PUSH_INVALID_KEY_ERR, FAILURE(5)),
+ ERROR(NS_ERROR_DOM_PUSH_MISMATCHED_KEY_ERR, FAILURE(6)),
#undef MODULE
/* ======================================================================= */
/* 51: NS_ERROR_MODULE_GENERAL */
/* ======================================================================= */
#define MODULE NS_ERROR_MODULE_GENERAL
/* Error code used internally by the incremental downloader to cancel the
* network channel when the download is already complete. */