diff --git a/configure.in b/configure.in index 2efbb00391..16cf2c1bba 100644 --- a/configure.in +++ b/configure.in @@ -968,8 +968,6 @@ MOZ_FIX_LINK_PATHS="-Wl,-rpath-link,${DIST}/bin -Wl,-rpath-link,${prefix}/lib" MOZ_FS_LAYOUT=unix -USE_DEPENDENT_LIBS=1 - _PLATFORM_DEFAULT_TOOLKIT=cairo-gtk2 if test -n "$CROSS_COMPILE"; then @@ -5236,8 +5234,8 @@ if test -n "$MOZ_OMX_PLUGIN"; then dnl Only allow building OMX plugin on Gonk (B2G) or Android AC_DEFINE(MOZ_OMX_PLUGIN) else - dnl fail if we're not building on Gonk or Android - AC_MSG_ERROR([OMX media plugin can only be built on B2G or Android]) + dnl fail if we're not building on Gonk or Android + AC_MSG_ERROR([OMX media plugin can only be built on B2G or Android]) fi fi @@ -8284,8 +8282,6 @@ AC_SUBST(MOZ_COMPONENT_NSPR_LIBS) AC_SUBST(MOZ_FIX_LINK_PATHS) -AC_SUBST(USE_DEPENDENT_LIBS) - AC_SUBST(MOZ_BUILD_ROOT) AC_SUBST(MOZ_POST_DSO_LIB_COMMAND) diff --git a/dom/animation/Animation.cpp b/dom/animation/Animation.cpp index b120f35ce0..8a67fa2412 100644 --- a/dom/animation/Animation.cpp +++ b/dom/animation/Animation.cpp @@ -94,14 +94,14 @@ Animation::Constructor(const GlobalObject& aGlobal, nsCOMPtr global = do_QueryInterface(aGlobal.GetAsSupports()); RefPtr animation = new Animation(global); - if (!aTimeline) { - // Bug 1096776: We do not support null timeline yet. - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; - } if (!aEffect) { // Bug 1049975: We do not support null effect yet. - aRv.Throw(NS_ERROR_FAILURE); + aRv.Throw(NS_ERROR_DOM_ANIM_NO_EFFECT_ERR); + return nullptr; + } + if (!aTimeline) { + // Bug 1096776: We do not support null timeline yet. + aRv.Throw(NS_ERROR_DOM_ANIM_NO_TIMELINE_ERR); return nullptr; } diff --git a/dom/base/domerr.msg b/dom/base/domerr.msg index 5c8a63d87a..86758f2e1f 100644 --- a/dom/base/domerr.msg +++ b/dom/base/domerr.msg @@ -119,6 +119,8 @@ DOM4_MSG_DEF(BtAuthRejectedError, "Authentication rejected", NS_ERROR_DOM_BLUET DOM4_MSG_DEF(NotSupportedError, "Animation to or from an underlying value is not yet supported.", NS_ERROR_DOM_ANIM_MISSING_PROPS_ERR) DOM4_MSG_DEF(NotSupportedError, "Animation with no target is not yet supported.", NS_ERROR_DOM_ANIM_NO_TARGET_ERR) +DOM4_MSG_DEF(NotSupportedError, "Animation with no timeline is not yet supported.", NS_ERROR_DOM_ANIM_NO_TIMELINE_ERR) +DOM4_MSG_DEF(NotSupportedError, "Animation with no effect is not yet supported.", NS_ERROR_DOM_ANIM_NO_EFFECT_ERR) /* common global codes (from nsError.h) */ @@ -156,6 +158,8 @@ DOM4_MSG_DEF(InvalidStateError, "Invalid service worker registration.", NS_ERROR 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") diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 85f843ea19..293420d807 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -3198,6 +3198,16 @@ nsDocument::GetUndoManager() return undoManager.forget(); } +bool +nsDocument::IsElementAnimateEnabled(JSContext* /*unused*/, JSObject* /*unused*/) +{ + MOZ_ASSERT(NS_IsMainThread()); + + return nsContentUtils::IsCallerChrome() || + Preferences::GetBool("dom.animations-api.core.enabled") || + Preferences::GetBool("dom.animations-api.element-animate.enabled"); +} + bool nsDocument::IsWebAnimationsEnabled(JSContext* /*unused*/, JSObject* /*unused*/) { diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h index 2d8d27e473..1cb8e363d7 100644 --- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -758,6 +758,7 @@ public: virtual already_AddRefed GetUndoManager() override; + static bool IsElementAnimateEnabled(JSContext* aCx, JSObject* aObject); static bool IsWebAnimationsEnabled(JSContext* aCx, JSObject* aObject); virtual mozilla::dom::DocumentTimeline* Timeline() override; virtual void GetAnimations( diff --git a/dom/interfaces/push/nsIPushService.idl b/dom/interfaces/push/nsIPushService.idl index 27191a0e6b..573639daa0 100644 --- a/dom/interfaces/push/nsIPushService.idl +++ b/dom/interfaces/push/nsIPushService.idl @@ -96,6 +96,16 @@ interface nsIPushService : nsISupports 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|. */ diff --git a/dom/push/Push.js b/dom/push/Push.js index db2fe0d596..62d9505727 100644 --- a/dom/push/Push.js +++ b/dom/push/Push.js @@ -46,27 +46,27 @@ Push.prototype = { Ci.nsISupportsWeakReference, Ci.nsIObserver]), - init: function(aWindow) { + init: function(win) { console.debug("init()"); - this._window = aWindow; + this._window = win; - this.initDOMRequestHelper(aWindow); + this.initDOMRequestHelper(win); - this._principal = aWindow.document.nodePrincipal; + this._principal = win.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" )); }; @@ -89,7 +89,7 @@ Push.prototype = { }); }, - subscribe: function() { + subscribe: function(options) { console.debug("subscribe()", this._scope); let histogram = Services.telemetry.getHistogramById("PUSH_API_USED"); @@ -97,7 +97,22 @@ Push.prototype = { 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); }) ); }, @@ -184,10 +199,7 @@ PushSubscriptionCallback.prototype = { 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; } @@ -196,12 +208,20 @@ PushSubscriptionCallback.prototype = { 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); }, @@ -216,6 +236,32 @@ PushSubscriptionCallback.prototype = { 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]); diff --git a/dom/push/PushManager.cpp b/dom/push/PushManager.cpp index cbeecb9772..f4d7103139 100644 --- a/dom/push/PushManager.cpp +++ b/dom/push/PushManager.cpp @@ -10,6 +10,8 @@ #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" @@ -63,6 +65,81 @@ GetPermissionState(nsIPrincipal* aPrincipal, 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& 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& aRawP256dhKey, + nsTArray& aAuthSecret, + nsTArray& 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: @@ -72,7 +149,8 @@ public: const nsAString& aEndpoint, const nsAString& aScope, nsTArray&& aRawP256dhKey, - nsTArray&& aAuthSecret) + nsTArray&& aAuthSecret, + nsTArray&& aAppServerKey) : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount) , mProxy(Move(aProxy)) , mStatus(aStatus) @@ -80,6 +158,7 @@ public: , mScope(aScope) , mRawP256dhKey(Move(aRawP256dhKey)) , mAuthSecret(Move(aAuthSecret)) + , mAppServerKey(Move(aAppServerKey)) { } bool @@ -92,7 +171,8 @@ public: } else { RefPtr 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 ) { @@ -115,6 +195,7 @@ private: nsString mScope; nsTArray mRawP256dhKey; nsTArray mAuthSecret; + nsTArray mAppServerKey; }; class GetSubscriptionCallback final : public nsIPushSubscriptionCallback @@ -141,10 +222,10 @@ public: } nsAutoString endpoint; - nsTArray rawP256dhKey, authSecret; + nsTArray rawP256dhKey, authSecret, appServerKey; if (NS_SUCCEEDED(aStatus)) { aStatus = GetSubscriptionParams(aSubscription, endpoint, rawP256dhKey, - authSecret); + authSecret, appServerKey); } WorkerPrivate* worker = mProxy->GetWorkerPrivate(); @@ -155,7 +236,8 @@ public: endpoint, mScope, Move(rawP256dhKey), - Move(authSecret)); + Move(authSecret), + Move(appServerKey)); MOZ_ALWAYS_TRUE(r->Dispatch()); return NS_OK; @@ -174,58 +256,6 @@ protected: {} 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& aRawP256dhKey, - nsTArray& 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 mProxy; nsString mScope; }; @@ -237,9 +267,12 @@ class GetSubscriptionRunnable final : public nsRunnable public: GetSubscriptionRunnable(PromiseWorkerProxy* aProxy, const nsAString& aScope, - PushManager::SubscriptionAction aAction) + PushManager::SubscriptionAction aAction, + nsTArray&& aAppServerKey) : mProxy(aProxy) - , mScope(aScope), mAction(aAction) + , mScope(aScope) + , mAction(aAction) + , mAppServerKey(Move(aAppServerKey)) {} NS_IMETHOD @@ -289,7 +322,13 @@ public: } 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); @@ -310,6 +349,7 @@ private: RefPtr mProxy; nsString mScope; PushManager::SubscriptionAction mAction; + nsTArray mAppServerKey; }; class PermissionResultRunnable final : public WorkerRunnable @@ -453,14 +493,15 @@ PushManager::Constructor(GlobalObject& aGlobal, } already_AddRefed -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 @@ -475,11 +516,12 @@ PushManager::GetSubscription(ErrorResult& aRv) } already_AddRefed -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(); @@ -506,8 +548,17 @@ PushManager::PermissionState(ErrorResult& aRv) } already_AddRefed -PushManager::PerformSubscriptionActionFromWorker( - SubscriptionAction aAction, ErrorResult& aRv) +PushManager::PerformSubscriptionActionFromWorker(SubscriptionAction aAction, + ErrorResult& aRv) +{ + PushSubscriptionOptionsInit options; + return PerformSubscriptionActionFromWorker(aAction, options, aRv); +} + +already_AddRefed +PushManager::PerformSubscriptionActionFromWorker(SubscriptionAction aAction, + const PushSubscriptionOptionsInit& aOptions, + ErrorResult& aRv) { WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(worker); @@ -525,8 +576,19 @@ PushManager::PerformSubscriptionActionFromWorker( return p.forget(); } + nsTArray 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 r = - new GetSubscriptionRunnable(proxy, mScope, aAction); + new GetSubscriptionRunnable(proxy, mScope, aAction, Move(appServerKey)); MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r)); return p.forget(); diff --git a/dom/push/PushManager.h b/dom/push/PushManager.h index 8433c5eda2..3b4d3a5a44 100644 --- a/dom/push/PushManager.h +++ b/dom/push/PushManager.h @@ -48,6 +48,7 @@ class WorkerPrivate; class Promise; class PushManagerImpl; +struct PushSubscriptionOptionsInit; class PushManager final : public nsISupports , public nsWrapperCache @@ -85,18 +86,23 @@ public: ErrorResult& aRv); already_AddRefed - Subscribe(ErrorResult& aRv); + PerformSubscriptionActionFromWorker(SubscriptionAction aAction, + const PushSubscriptionOptionsInit& aOptions, + ErrorResult& aRv); + + already_AddRefed + Subscribe(const PushSubscriptionOptionsInit& aOptions, ErrorResult& aRv); already_AddRefed GetSubscription(ErrorResult& aRv); already_AddRefed - PermissionState(ErrorResult& aRv); - -protected: - ~PushManager(); + PermissionState(const PushSubscriptionOptionsInit& aOptions, + ErrorResult& aRv); private: + ~PushManager(); + // The following are only set and accessed on the main thread. nsCOMPtr mGlobal; RefPtr mImpl; diff --git a/dom/push/PushSubscription.cpp b/dom/push/PushSubscription.cpp index d590458eca..0834040df1 100644 --- a/dom/push/PushSubscription.cpp +++ b/dom/push/PushSubscription.cpp @@ -12,6 +12,8 @@ #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" @@ -191,26 +193,14 @@ private: nsString mScope; }; -bool -CopyArrayBufferToArray(const ArrayBuffer& aBuffer, - nsTArray& 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&& aRawP256dhKey, - nsTArray&& aAuthSecret) + nsTArray&& aAuthSecret, + nsTArray&& aAppServerKey) : mEndpoint(aEndpoint) , mScope(aScope) , mRawP256dhKey(Move(aRawP256dhKey)) @@ -227,13 +217,13 @@ PushSubscription::PushSubscription(nsIGlobalObject* aGlobal, 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) @@ -250,28 +240,46 @@ PushSubscription::WrapObject(JSContext* aCx, JS::Handle aGivenProto) // static already_AddRefed PushSubscription::Constructor(GlobalObject& aGlobal, - const nsAString& aEndpoint, - const nsAString& aScope, - const Nullable& aP256dhKey, - const Nullable& aAuthSecret, + const PushSubscriptionInit& aInitDict, ErrorResult& aRv) { nsCOMPtr global = do_QueryInterface(aGlobal.GetAsSupports()); - nsTArray rawKey, authSecret; - if ((!aP256dhKey.IsNull() && !CopyArrayBufferToArray(aP256dhKey.Value(), - rawKey)) || - (!aAuthSecret.IsNull() && !CopyArrayBufferToArray(aAuthSecret.Value(), - authSecret))) { + nsTArray 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 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 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 sub = new PushSubscription(global, - aEndpoint, - aScope, + aInitDict.mEndpoint, + aInitDict.mScope, Move(rawKey), - Move(authSecret)); + Move(authSecret), + Move(appServerKey)); return sub.forget(); } @@ -315,16 +323,13 @@ PushSubscription::Unsubscribe(ErrorResult& aRv) void PushSubscription::GetKey(JSContext* aCx, PushEncryptionKeyName aType, - JS::MutableHandle aKey) + JS::MutableHandle 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); } @@ -358,6 +363,13 @@ PushSubscription::ToJSON(PushSubscriptionJSON& aJSON, ErrorResult& aRv) } } +already_AddRefed +PushSubscription::Options() +{ + RefPtr options = mOptions; + return options.forget(); +} + already_AddRefed PushSubscription::UnsubscribeFromWorker(ErrorResult& aRv) { diff --git a/dom/push/PushSubscription.h b/dom/push/PushSubscription.h index 8ca60b7e20..45f8379243 100644 --- a/dom/push/PushSubscription.h +++ b/dom/push/PushSubscription.h @@ -15,6 +15,7 @@ #include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/PushSubscriptionBinding.h" +#include "mozilla/dom/PushSubscriptionOptionsBinding.h" #include "mozilla/dom/TypedArray.h" class nsIGlobalObject; @@ -39,7 +40,8 @@ public: const nsAString& aEndpoint, const nsAString& aScope, nsTArray&& aP256dhKey, - nsTArray&& aAuthSecret); + nsTArray&& aAuthSecret, + nsTArray&& aAppServerKey); JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; @@ -59,14 +61,12 @@ public: void GetKey(JSContext* cx, PushEncryptionKeyName aType, - JS::MutableHandle aKey); + JS::MutableHandle aKey, + ErrorResult& aRv); static already_AddRefed Constructor(GlobalObject& aGlobal, - const nsAString& aEndpoint, - const nsAString& aScope, - const Nullable& aP256dhKey, - const Nullable& aAuthSecret, + const PushSubscriptionInit& aInitDict, ErrorResult& aRv); already_AddRefed @@ -75,10 +75,12 @@ public: void ToJSON(PushSubscriptionJSON& aJSON, ErrorResult& aRv); -protected: - ~PushSubscription(); + already_AddRefed + Options(); private: + ~PushSubscription(); + already_AddRefed UnsubscribeFromWorker(ErrorResult& aRv); @@ -87,6 +89,7 @@ private: nsTArray mRawP256dhKey; nsTArray mAuthSecret; nsCOMPtr mGlobal; + RefPtr mOptions; }; } // namespace dom diff --git a/dom/push/PushSubscriptionOptions.cpp b/dom/push/PushSubscriptionOptions.cpp new file mode 100644 index 0000000000..62a557e4f9 --- /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&& 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 aGivenProto) +{ + return PushSubscriptionOptionsBinding::Wrap(aCx, this, aGivenProto); +} + +void +PushSubscriptionOptions::GetApplicationServerKey(JSContext* aCx, + JS::MutableHandle aKey, + ErrorResult& aRv) +{ + PushUtil::CopyArrayToArrayBuffer(aCx, mAppServerKey, aKey, aRv); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/push/PushSubscriptionOptions.h b/dom/push/PushSubscriptionOptions.h new file mode 100644 index 0000000000..6665d39e7f --- /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&& aAppServerKey); + + nsIGlobalObject* + GetParentObject() const + { + return mGlobal; + } + + JSObject* + WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + + void + GetApplicationServerKey(JSContext* aCx, + JS::MutableHandle aKey, + ErrorResult& aRv); + +private: + ~PushSubscriptionOptions(); + + nsCOMPtr mGlobal; + nsTArray mAppServerKey; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_PushSubscriptionOptions_h diff --git a/dom/push/PushUtil.cpp b/dom/push/PushUtil.cpp new file mode 100644 index 0000000000..43d233e7a1 --- /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& 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& 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& aArray, + JS::MutableHandle aValue, + ErrorResult& aRv) +{ + if (aArray.IsEmpty()) { + aValue.set(nullptr); + return; + } + JS::Rooted 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 diff --git a/dom/push/PushUtil.h b/dom/push/PushUtil.h new file mode 100644 index 0000000000..76843e1d33 --- /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& aArray); + + static bool + CopyBufferSourceToArray(const OwningArrayBufferViewOrArrayBuffer& aSource, + nsTArray& aArray); + + static void + CopyArrayToArrayBuffer(JSContext* aCx, const nsTArray& aArray, + JS::MutableHandle aValue, ErrorResult& aRv); +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_PushUtil_h diff --git a/dom/push/moz.build b/dom/push/moz.build index 06830e6b72..d61759654e 100644 --- a/dom/push/moz.build +++ b/dom/push/moz.build @@ -40,12 +40,16 @@ 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'] diff --git a/dom/webidl/Animatable.webidl b/dom/webidl/Animatable.webidl index 128051cd05..48d488bb22 100644 --- a/dom/webidl/Animatable.webidl +++ b/dom/webidl/Animatable.webidl @@ -20,7 +20,7 @@ dictionary AnimationFilter { [NoInterfaceObject] interface Animatable { - [Func="nsDocument::IsWebAnimationsEnabled", Throws] + [Func="nsDocument::IsElementAnimateEnabled", Throws] Animation animate(object? frames, optional (unrestricted double or KeyframeAnimationOptions) options); diff --git a/dom/webidl/Animation.webidl b/dom/webidl/Animation.webidl index 7264db1549..f9cd83d6aa 100644 --- a/dom/webidl/Animation.webidl +++ b/dom/webidl/Animation.webidl @@ -12,14 +12,15 @@ enum AnimationPlayState { "idle", "pending", "running", "paused", "finished" }; -[Func="nsDocument::IsWebAnimationsEnabled", +[Func="nsDocument::IsElementAnimateEnabled", Constructor (optional KeyframeEffectReadOnly? effect = null, optional AnimationTimeline? timeline = null)] interface Animation : EventTarget { attribute DOMString id; // Bug 1049975: Make 'effect' writeable - [Pure] + [Func="nsDocument::IsWebAnimationsEnabled", Pure] readonly attribute AnimationEffectReadOnly? effect; + [Func="nsDocument::IsWebAnimationsEnabled"] readonly attribute AnimationTimeline? timeline; [BinaryName="startTimeAsDouble"] attribute double? startTime; @@ -29,9 +30,9 @@ interface Animation : EventTarget { attribute double playbackRate; [BinaryName="playStateFromJS"] readonly attribute AnimationPlayState playState; - [Throws] + [Func="nsDocument::IsWebAnimationsEnabled", Throws] readonly attribute Promise ready; - [Throws] + [Func="nsDocument::IsWebAnimationsEnabled", Throws] readonly attribute Promise finished; attribute EventHandler onfinish; attribute EventHandler oncancel; diff --git a/dom/webidl/PushManager.webidl b/dom/webidl/PushManager.webidl index 7e3404db74..de1e632c7e 100644 --- a/dom/webidl/PushManager.webidl +++ b/dom/webidl/PushManager.webidl @@ -7,25 +7,30 @@ * 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 subscribe(); + Promise subscribe(optional PushSubscriptionOptionsInit options); Promise getSubscription(); - Promise permissionState(); + Promise permissionState(optional PushSubscriptionOptionsInit options); }; [Exposed=(Window,Worker), Func="nsContentUtils::PushEnabled", ChromeConstructor(DOMString scope)] interface PushManager { [Throws, UseCounter] - Promise subscribe(); + Promise subscribe(optional PushSubscriptionOptionsInit options); [Throws] Promise getSubscription(); [Throws] - Promise permissionState(); + Promise permissionState(optional PushSubscriptionOptionsInit options); }; enum PushPermissionState diff --git a/dom/webidl/PushSubscription.webidl b/dom/webidl/PushSubscription.webidl index 3aa8460cb8..eab576d3ce 100644 --- a/dom/webidl/PushSubscription.webidl +++ b/dom/webidl/PushSubscription.webidl @@ -27,17 +27,27 @@ dictionary PushSubscriptionJSON 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 unsubscribe(); + readonly attribute USVString endpoint; + readonly attribute PushSubscriptionOptions options; + [Throws] + ArrayBuffer? getKey(PushEncryptionKeyName name); + [Throws, UseCounter] + Promise 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(); }; diff --git a/dom/webidl/PushSubscriptionOptions.webidl b/dom/webidl/PushSubscriptionOptions.webidl new file mode 100644 index 0000000000..091a05f42f --- /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; +}; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index a15bdfa0ef..ed8069444d 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -725,6 +725,7 @@ else: 'PushManager.webidl', 'PushMessageData.webidl', 'PushSubscription.webidl', + 'PushSubscriptionOptions.webidl', ] if CONFIG['MOZ_NFC']: diff --git a/js/src/configure.in b/js/src/configure.in index 7808f4c5e8..650f938e7e 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -769,8 +769,6 @@ MOZ_USER_DIR=".mozilla" MOZ_FIX_LINK_PATHS="-Wl,-rpath-link,${DIST}/bin -Wl,-rpath-link,${prefix}/lib" -USE_DEPENDENT_LIBS=1 - _PLATFORM_DEFAULT_TOOLKIT=cairo-gtk2 if test -n "$CROSS_COMPILE"; then @@ -3628,8 +3626,6 @@ AC_SUBST(MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS) AC_SUBST(MOZ_FIX_LINK_PATHS) -AC_SUBST(USE_DEPENDENT_LIBS) - AC_SUBST(MOZ_BUILD_ROOT) AC_SUBST(MOZ_POST_DSO_LIB_COMMAND) diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index 0000915c38..0b37a1dfeb 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -3390,7 +3390,6 @@ XPCJSRuntime::Initialize() kStackQuota - kSystemCodeBuffer, kStackQuota - kSystemCodeBuffer - kTrustedScriptBuffer); - JS_SetErrorReporter(runtime, xpc::SystemErrorReporter); JS_SetDestroyCompartmentCallback(runtime, CompartmentDestroyedCallback); JS_SetSizeOfIncludingThisCompartmentCallback(runtime, CompartmentSizeOfIncludingThisCallback); JS_SetCompartmentNameCallback(runtime, CompartmentNameCallback); diff --git a/js/xpconnect/src/XPCWrappedJSClass.cpp b/js/xpconnect/src/XPCWrappedJSClass.cpp index 65110d6341..746656a350 100644 --- a/js/xpconnect/src/XPCWrappedJSClass.cpp +++ b/js/xpconnect/src/XPCWrappedJSClass.cpp @@ -276,10 +276,7 @@ nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(JSContext* cx, } } - // Don't report if reporting was disabled by someone else. - if (!ContextOptionsRef(cx).dontReportUncaught() && - !ContextOptionsRef(cx).autoJSAPIOwnsErrorReporting()) - JS_ReportPendingException(cx); + MOZ_ASSERT(ContextOptionsRef(cx).autoJSAPIOwnsErrorReporting()); } else if (!success) { NS_WARNING("QI hook ran OOMed - this is probably a bug!"); } diff --git a/js/xpconnect/src/xpc.msg b/js/xpconnect/src/xpc.msg index 486ec6507a..30d8a2797c 100644 --- a/js/xpconnect/src/xpc.msg +++ b/js/xpconnect/src/xpc.msg @@ -218,3 +218,7 @@ XPC_MSG_DEF(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY , "Cannot print this docum /* 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.") diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 678ebcf0e0..a26aacfaf8 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -2864,6 +2864,12 @@ pref("dom.animations-api.core.enabled", false); pref("dom.animations-api.core.enabled", true); #endif +// Is support for the Element.animate() function (a subset of the Web Animations +// API) enabled? +// Note that if dom.animations-api.core.enabled is true, this preference is +// ignored. +pref("dom.animations-api.element-animate.enabled", true); + // pref to permit users to make verified SOAP calls by default pref("capability.policy.default.SOAPCall.invokeVerifySourceHeader", "allAccess"); diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp index 13b53da10f..391677616c 100644 --- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -528,8 +528,6 @@ CycleCollectedJSRuntime::Initialize(JSRuntime* aParentRuntime, JS_SetDestroyZoneCallback(mJSRuntime, XPCStringConvert::FreeZoneCache); JS_SetSweepZoneCallback(mJSRuntime, XPCStringConvert::ClearZoneCache); JS::SetBuildIdOp(mJSRuntime, GetBuildId); - // XPCJSRuntime currently overrides this because we don't - // TakeOwnershipOfErrorReporting everwhere on the main thread yet. JS_SetErrorReporter(mJSRuntime, MozCrashErrorReporter); static js::DOMCallbacks DOMcallbacks = { diff --git a/xpcom/base/ErrorList.h b/xpcom/base/ErrorList.h index 0b631842ce..ca2e785bd5 100644 --- a/xpcom/base/ErrorList.h +++ b/xpcom/base/ErrorList.h @@ -956,6 +956,8 @@ #define MODULE NS_ERROR_MODULE_DOM_ANIM ERROR(NS_ERROR_DOM_ANIM_MISSING_PROPS_ERR, FAILURE(1)), ERROR(NS_ERROR_DOM_ANIM_NO_TARGET_ERR, FAILURE(2)), + ERROR(NS_ERROR_DOM_ANIM_NO_TIMELINE_ERR, FAILURE(3)), + ERROR(NS_ERROR_DOM_ANIM_NO_EFFECT_ERR, FAILURE(4)), #undef MODULE /* ======================================================================= */ @@ -963,9 +965,11 @@ /* ======================================================================= */ #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 /* ======================================================================= */ diff --git a/xpcom/base/Logging.cpp b/xpcom/base/Logging.cpp index 2d44d152ee..36eba7589d 100644 --- a/xpcom/base/Logging.cpp +++ b/xpcom/base/Logging.cpp @@ -122,7 +122,11 @@ public: bool shouldAppend = false; bool addTimestamp = false; bool isSync = false; - const char* modules = PR_GetEnv("NSPR_LOG_MODULES"); + const char* modules = PR_GetEnv("MOZ_LOG_MODULES"); + if (!modules || !modules[0]) { + modules = PR_GetEnv("NSPR_LOG_MODULES"); + } + NSPRLogModulesParser(modules, [&shouldAppend, &addTimestamp, &isSync] (const char* aName, LogLevel aLevel) mutable { @@ -140,7 +144,11 @@ public: mAddTimestamp = addTimestamp; mIsSync = isSync; - const char* logFile = PR_GetEnv("NSPR_LOG_FILE"); + const char* logFile = PR_GetEnv("MOZ_LOG_FILE"); + if (!logFile || !logFile[0]) { + logFile = PR_GetEnv("NSPR_LOG_FILE"); + } + if (logFile && logFile[0]) { static const char kPIDToken[] = "%PID"; const char* pidTokenPtr = strstr(logFile, kPIDToken); diff --git a/xpcom/base/nsConsoleService.cpp b/xpcom/base/nsConsoleService.cpp index bbe5673332..58e88e3746 100644 --- a/xpcom/base/nsConsoleService.cpp +++ b/xpcom/base/nsConsoleService.cpp @@ -75,6 +75,7 @@ void nsConsoleService::ClearMessagesForWindowID(const uint64_t innerID) { MOZ_RELEASE_ASSERT(NS_IsMainThread()); + MutexAutoLock lock(mLock); for (MessageElement* e = mMessages.getFirst(); e != nullptr; ) { // Only messages implementing nsIScriptError interface expose the @@ -104,6 +105,8 @@ nsConsoleService::ClearMessagesForWindowID(const uint64_t innerID) void nsConsoleService::ClearMessages() { + // NB: A lock is not required here as it's only called from |Reset| which + // locks for us and from the dtor. while (!mMessages.isEmpty()) { MessageElement* e = mMessages.popFirst(); delete e; diff --git a/xpcom/base/nsError.h b/xpcom/base/nsError.h index a559344210..b192ccd81f 100644 --- a/xpcom/base/nsError.h +++ b/xpcom/base/nsError.h @@ -11,6 +11,7 @@ #error nsError.h no longer supports C sources #endif +#include "mozilla/Attributes.h" #include "mozilla/Likely.h" #include @@ -192,12 +193,12 @@ NS_ErrorAccordingToNSPR(); * @name Standard Macros for retrieving error bits */ -inline uint16_t +inline MOZ_CONSTEXPR uint16_t NS_ERROR_GET_CODE(nsresult aErr) { return uint32_t(aErr) & 0xffff; } -inline uint16_t +inline MOZ_CONSTEXPR uint16_t NS_ERROR_GET_MODULE(nsresult aErr) { return ((uint32_t(aErr) >> 16) - NS_ERROR_MODULE_BASE_OFFSET) & 0x1fff; diff --git a/xpcom/base/nsTraceRefcnt.cpp b/xpcom/base/nsTraceRefcnt.cpp index 6d88323f4f..13ba3f7f78 100644 --- a/xpcom/base/nsTraceRefcnt.cpp +++ b/xpcom/base/nsTraceRefcnt.cpp @@ -61,17 +61,24 @@ // only held for a very short time, and gets grabbed at a very high frequency // (~100000 times per second). On Mac, the overhead of using a regular lock // is very high, see bug 1137963. -static mozilla::Atomic gTraceLogLocked; +static mozilla::Atomic gTraceLogLocked; struct MOZ_STACK_CLASS AutoTraceLogLock final { + bool doRelease; AutoTraceLogLock() + : doRelease(true) { - while (!gTraceLogLocked.compareExchange(false, true)) { - PR_Sleep(PR_INTERVAL_NO_WAIT); /* yield */ + uintptr_t currentThread = reinterpret_cast(PR_GetCurrentThread()); + if (gTraceLogLocked == currentThread) { + doRelease = false; + } else { + while (!gTraceLogLocked.compareExchange(0, currentThread)) { + PR_Sleep(PR_INTERVAL_NO_WAIT); /* yield */ + } } } - ~AutoTraceLogLock() { gTraceLogLocked = false; } + ~AutoTraceLogLock() { if (doRelease) gTraceLogLocked = 0; } }; static PLHashTable* gBloatView; @@ -1119,14 +1126,14 @@ NS_LogAddRef(void* aPtr, nsrefcnt aRefcnt, bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); if (aRefcnt == 1 && gAllocLog && loggingThisType && loggingThisObject) { - fprintf(gAllocLog, "\n<%s> %p %" PRIdPTR " Create\n", aClass, aPtr, serialno); + fprintf(gAllocLog, "\n<%s> %p %" PRIdPTR " Create [thread %p]\n", aClass, aPtr, serialno, PR_GetCurrentThread()); nsTraceRefcnt::WalkTheStackCached(gAllocLog); } if (gRefcntsLog && loggingThisType && loggingThisObject) { // Can't use MOZ_LOG(), b/c it truncates the line - fprintf(gRefcntsLog, "\n<%s> %p %" PRIuPTR " AddRef %" PRIuPTR "\n", - aClass, aPtr, serialno, aRefcnt); + fprintf(gRefcntsLog, "\n<%s> %p %" PRIuPTR " AddRef %" PRIuPTR " [thread %p]\n", + aClass, aPtr, serialno, aRefcnt, PR_GetCurrentThread()); nsTraceRefcnt::WalkTheStackCached(gRefcntsLog); fflush(gRefcntsLog); } @@ -1173,8 +1180,8 @@ NS_LogRelease(void* aPtr, nsrefcnt aRefcnt, const char* aClass) if (gRefcntsLog && loggingThisType && loggingThisObject) { // Can't use MOZ_LOG(), b/c it truncates the line fprintf(gRefcntsLog, - "\n<%s> %p %" PRIuPTR " Release %" PRIuPTR "\n", - aClass, aPtr, serialno, aRefcnt); + "\n<%s> %p %" PRIuPTR " Release %" PRIuPTR " [thread %p]\n", + aClass, aPtr, serialno, aRefcnt, PR_GetCurrentThread()); nsTraceRefcnt::WalkTheStackCached(gRefcntsLog); fflush(gRefcntsLog); } @@ -1183,7 +1190,7 @@ NS_LogRelease(void* aPtr, nsrefcnt aRefcnt, const char* aClass) // yet we still want to see deletion information: if (aRefcnt == 0 && gAllocLog && loggingThisType && loggingThisObject) { - fprintf(gAllocLog, "\n<%s> %p %" PRIdPTR " Destroy\n", aClass, aPtr, serialno); + fprintf(gAllocLog, "\n<%s> %p %" PRIdPTR " Destroy [thread %p]\n", aClass, aPtr, serialno, PR_GetCurrentThread()); nsTraceRefcnt::WalkTheStackCached(gAllocLog); } @@ -1283,17 +1290,17 @@ NS_LogCOMPtrAddRef(void* aCOMPtr, nsISupports* aObject) if (!gTypesToLog || !gSerialNumbers) { return; } - intptr_t serialno = GetSerialNumber(object, false); - if (serialno == 0) { - return; - } - if (!gInitialized) { InitTraceLog(); } if (gLogging == FullLogging) { AutoTraceLogLock lock; + intptr_t serialno = GetSerialNumber(object, false); + if (serialno == 0) { + return; + } + int32_t* count = GetCOMPtrCount(object); if (count) { (*count)++; @@ -1324,17 +1331,17 @@ NS_LogCOMPtrRelease(void* aCOMPtr, nsISupports* aObject) if (!gTypesToLog || !gSerialNumbers) { return; } - intptr_t serialno = GetSerialNumber(object, false); - if (serialno == 0) { - return; - } - if (!gInitialized) { InitTraceLog(); } if (gLogging == FullLogging) { AutoTraceLogLock lock; + intptr_t serialno = GetSerialNumber(object, false); + if (serialno == 0) { + return; + } + int32_t* count = GetCOMPtrCount(object); if (count) { (*count)--;