From 8d097c92d3b1c8afa0e2f2a8b8184cc789415f3d Mon Sep 17 00:00:00 2001 From: Eden Chuang Date: Wed, 5 Dec 2018 15:01:45 -0500 Subject: [PATCH] Bug 1497219 - Rejecting PaymentRequest::API calls when the PaymentRequest is not in fully active document. r=baku PaymentRequest API is not supported when the PaymentRequest is not in the fully active document. Adding bool a PaymentRequest::InFullyActiveDocument() method to check if the PaymentRequest is in fully active document. This method should be called at the start of any PaymentRequest APIs. If the PaymentRequest is not in fully active document, ignoring the API call and throw the NS_ERROR_DOM_ABORT_ERR if needed. --HG-- extra : histedit_source : 3e8e4a73f69c639f9cc528afa586af22597ff320 --- dom/payments/PaymentRequest.cpp | 79 ++++++++++++++++++++-- dom/payments/PaymentRequest.h | 2 + dom/payments/PaymentRequestUpdateEvent.cpp | 9 +++ dom/payments/PaymentResponse.cpp | 28 +++++--- 4 files changed, 100 insertions(+), 18 deletions(-) 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; }