diff --git a/dom/payments/PaymentRequest.cpp b/dom/payments/PaymentRequest.cpp index 00f49c242b9f..f67759af227d 100644 --- a/dom/payments/PaymentRequest.cpp +++ b/dom/payments/PaymentRequest.cpp @@ -645,6 +645,11 @@ PaymentRequest::PaymentRequest(nsPIDOMWindowInner* aWindow, } already_AddRefed PaymentRequest::CanMakePayment(ErrorResult& aRv) { + if (!InFullyActiveDocument()) { + aRv.Throw(NS_ERROR_DOM_ABORT_ERR); + return nullptr; + } + if (mState != eCreated) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; @@ -683,9 +688,13 @@ void PaymentRequest::RespondCanMakePayment(bool aResult) { already_AddRefed PaymentRequest::Show( const Optional>& aDetailsPromise, ErrorResult& aRv) { + if (!InFullyActiveDocument()) { + aRv.Throw(NS_ERROR_DOM_ABORT_ERR); + return nullptr; + } + nsIGlobalObject* global = GetOwnerGlobal(); nsCOMPtr win = do_QueryInterface(global); - MOZ_ASSERT(win); nsIDocument* doc = win->GetExtantDoc(); if (!EventStateManager::IsHandlingUserInput()) { @@ -699,11 +708,6 @@ already_AddRefed PaymentRequest::Show( } } - if (!doc || !doc->IsCurrentActiveDocument()) { - aRv.Throw(NS_ERROR_DOM_ABORT_ERR); - return nullptr; - } - if (mState != eCreated) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; @@ -792,6 +796,11 @@ void PaymentRequest::RespondComplete() { } already_AddRefed PaymentRequest::Abort(ErrorResult& aRv) { + if (!InFullyActiveDocument()) { + aRv.Throw(NS_ERROR_DOM_ABORT_ERR); + return nullptr; + } + if (mState != eInteractive) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; @@ -872,6 +881,11 @@ nsresult PaymentRequest::UpdatePayment(JSContext* aCx, } void PaymentRequest::AbortUpdate(nsresult aRv) { + // perfect ignoring when the document is not fully active. + if (!InFullyActiveDocument()) { + return; + } + MOZ_ASSERT(NS_FAILED(aRv)); if (mState != eInteractive) { @@ -1055,6 +1069,10 @@ void PaymentRequest::SetOptions(const PaymentOptions& aOptions) { void PaymentRequest::ResolvedCallback(JSContext* aCx, JS::Handle aValue) { + if (!InFullyActiveDocument()) { + return; + } + MOZ_ASSERT(aCx); mUpdating = false; if (NS_WARN_IF(!aValue.isObject())) { @@ -1084,10 +1102,38 @@ void PaymentRequest::ResolvedCallback(JSContext* aCx, void PaymentRequest::RejectedCallback(JSContext* aCx, JS::Handle aValue) { + if (!InFullyActiveDocument()) { + return; + } + mUpdating = false; AbortUpdate(NS_ERROR_DOM_ABORT_ERR); } +bool PaymentRequest::InFullyActiveDocument() { + nsIGlobalObject* global = GetOwnerGlobal(); + if (!global) { + return false; + } + + nsCOMPtr win = do_QueryInterface(global); + nsIDocument* doc = win->GetExtantDoc(); + if (!doc || !doc->IsCurrentActiveDocument()) { + return false; + } + + // According to the definition of the fully active document, recursive + // checking the parent document are all IsCurrentActiveDocument + nsIDocument* parentDoc = doc->GetParentDocument(); + while (parentDoc) { + if (parentDoc && !parentDoc->IsCurrentActiveDocument()) { + return false; + } + parentDoc = parentDoc->GetParentDocument(); + } + return true; +} + void PaymentRequest::RegisterActivityObserver() { if (nsPIDOMWindowInner* window = GetOwner()) { nsCOMPtr doc = window->GetExtantDoc(); @@ -1114,7 +1160,26 @@ void PaymentRequest::NotifyOwnerDocumentActivityChanged() { nsIDocument* doc = window->GetExtantDoc(); NS_ENSURE_TRUE_VOID(doc); - if (!doc->IsCurrentActiveDocument()) { + if (!InFullyActiveDocument()) { + if (mState == eInteractive) { + if (mAcceptPromise) { + mAcceptPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); + mAcceptPromise = nullptr; + } + if (mResponse) { + mResponse->RejectRetry(NS_ERROR_DOM_ABORT_ERR); + } + if (mAbortPromise) { + mAbortPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); + mAbortPromise = nullptr; + } + } + if (mState == eCreated) { + if (mResultPromise) { + mResultPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); + mResultPromise = nullptr; + } + } RefPtr mgr = PaymentRequestManager::GetSingleton(); mgr->ClosePayment(this); } diff --git a/dom/payments/PaymentRequest.h b/dom/payments/PaymentRequest.h index 53e31c8ca80e..95e46b07e7d1 100644 --- a/dom/payments/PaymentRequest.h +++ b/dom/payments/PaymentRequest.h @@ -203,6 +203,8 @@ class PaymentRequest final : public DOMEventTargetHelper, void ResolvedCallback(JSContext* aCx, JS::Handle aValue) override; void RejectedCallback(JSContext* aCx, JS::Handle aValue) override; + bool InFullyActiveDocument(); + IMPL_EVENT_HANDLER(merchantvalidation); IMPL_EVENT_HANDLER(shippingaddresschange); IMPL_EVENT_HANDLER(shippingoptionchange); diff --git a/dom/payments/PaymentRequestUpdateEvent.cpp b/dom/payments/PaymentRequestUpdateEvent.cpp index 867e8cd026ae..8bc9fddc6ee5 100644 --- a/dom/payments/PaymentRequestUpdateEvent.cpp +++ b/dom/payments/PaymentRequestUpdateEvent.cpp @@ -52,6 +52,9 @@ void PaymentRequestUpdateEvent::ResolvedCallback(JSContext* aCx, JS::Handle aValue) { MOZ_ASSERT(aCx); MOZ_ASSERT(mRequest); + if (!mRequest->InFullyActiveDocument()) { + return; + } if (NS_WARN_IF(!aValue.isObject()) || !mWaitForUpdate) { return; @@ -89,6 +92,9 @@ void PaymentRequestUpdateEvent::ResolvedCallback(JSContext* aCx, void PaymentRequestUpdateEvent::RejectedCallback(JSContext* aCx, JS::Handle aValue) { MOZ_ASSERT(mRequest); + if (!mRequest->InFullyActiveDocument()) { + return; + } mRequest->AbortUpdate(NS_ERROR_DOM_ABORT_ERR); mWaitForUpdate = false; @@ -103,6 +109,9 @@ void PaymentRequestUpdateEvent::UpdateWith(Promise& aPromise, } MOZ_ASSERT(mRequest); + if (!mRequest->InFullyActiveDocument()) { + return; + } if (mWaitForUpdate || !mRequest->ReadyForUpdate()) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); diff --git a/dom/payments/PaymentResponse.cpp b/dom/payments/PaymentResponse.cpp index 806e56febc39..5691b51de194 100644 --- a/dom/payments/PaymentResponse.cpp +++ b/dom/payments/PaymentResponse.cpp @@ -176,6 +176,12 @@ already_AddRefed PaymentResponse::GetShippingAddress() const { already_AddRefed PaymentResponse::Complete(PaymentComplete result, ErrorResult& aRv) { + MOZ_ASSERT(mRequest); + if (!mRequest->InFullyActiveDocument()) { + aRv.Throw(NS_ERROR_DOM_ABORT_ERR); + return nullptr; + } + if (mCompleteCalled) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; @@ -226,6 +232,12 @@ void PaymentResponse::RespondComplete() { already_AddRefed PaymentResponse::Retry( JSContext* aCx, const PaymentValidationErrors& aErrors, ErrorResult& aRv) { + MOZ_ASSERT(mRequest); + if (!mRequest->InFullyActiveDocument()) { + aRv.Throw(NS_ERROR_DOM_ABORT_ERR); + return nullptr; + } + nsIGlobalObject* global = GetOwner()->AsGlobal(); ErrorResult errResult; RefPtr promise = Promise::Create(global, errResult); @@ -239,17 +251,6 @@ already_AddRefed PaymentResponse::Retry( mTimer = nullptr; } - if (NS_WARN_IF(!GetOwner())) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; - } - - nsIDocument* doc = GetOwner()->GetExtantDoc(); - if (!doc || !doc->IsCurrentActiveDocument()) { - promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); - return promise.forget(); - } - if (mCompleteCalled || mRetryPromise) { promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); return promise.forget(); @@ -413,6 +414,11 @@ nsresult PaymentResponse::ValidatePaymentValidationErrors( NS_IMETHODIMP PaymentResponse::Notify(nsITimer* timer) { mTimer = nullptr; + + if (!mRequest->InFullyActiveDocument()) { + return NS_OK; + } + if (mCompleteCalled) { return NS_OK; }