diff --git a/dom/payments/PaymentRequestManager.cpp b/dom/payments/PaymentRequestManager.cpp index 0bd26fbbc1a7..05f3f1077bba 100644 --- a/dom/payments/PaymentRequestManager.cpp +++ b/dom/payments/PaymentRequestManager.cpp @@ -478,13 +478,18 @@ PaymentRequestManager::AbortPayment(PaymentRequest* aRequest, bool aDeferredShow nsresult PaymentRequestManager::CompletePayment(PaymentRequest* aRequest, - const PaymentComplete& aComplete) + const PaymentComplete& aComplete, + bool aTimedOut) { nsString completeStatusString(NS_LITERAL_STRING("unknown")); - uint8_t completeIndex = static_cast(aComplete); - if (completeIndex < ArrayLength(PaymentCompleteValues::strings)) { - completeStatusString.AssignASCII( - PaymentCompleteValues::strings[completeIndex].value); + if (aTimedOut) { + completeStatusString.AssignLiteral("timeout"); + } else { + uint8_t completeIndex = static_cast(aComplete); + if (completeIndex < ArrayLength(PaymentCompleteValues::strings)) { + completeStatusString.AssignASCII( + PaymentCompleteValues::strings[completeIndex].value); + } } nsAutoString requestId; diff --git a/dom/payments/PaymentRequestManager.h b/dom/payments/PaymentRequestManager.h index 4225f8a4d8ad..47a20a9a3110 100644 --- a/dom/payments/PaymentRequestManager.h +++ b/dom/payments/PaymentRequestManager.h @@ -50,7 +50,8 @@ public: nsresult ShowPayment(PaymentRequest* aRequest); nsresult AbortPayment(PaymentRequest* aRequest, bool aDeferredShow); nsresult CompletePayment(PaymentRequest* aRequest, - const PaymentComplete& aComplete); + const PaymentComplete& aComplete, + bool aTimedOut = false); nsresult UpdatePayment(JSContext* aCx, PaymentRequest* aRequest, const PaymentDetailsUpdate& aDetails, diff --git a/dom/payments/PaymentResponse.cpp b/dom/payments/PaymentResponse.cpp index 7fc264080302..c01d2b5b2882 100644 --- a/dom/payments/PaymentResponse.cpp +++ b/dom/payments/PaymentResponse.cpp @@ -4,6 +4,7 @@ * 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/StaticPrefs.h" #include "mozilla/dom/PaymentResponse.h" #include "mozilla/dom/BasicCardPaymentBinding.h" #include "BasicCardPayment.h" @@ -22,6 +23,7 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(PaymentResponse) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PaymentResponse) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_ENTRY(nsISupports) + NS_INTERFACE_MAP_ENTRY(nsITimerCallback) NS_INTERFACE_MAP_END PaymentResponse::PaymentResponse(nsPIDOMWindowInner* aWindow, @@ -49,6 +51,11 @@ PaymentResponse::PaymentResponse(nsPIDOMWindowInner* aWindow, // TODO: from https://github.com/w3c/browser-payment-api/issues/480 // Add payerGivenName + payerFamilyName to PaymentAddress + NS_NewTimerWithCallback(getter_AddRefs(mTimer), + this, + StaticPrefs::dom_payments_response_timeout(), + nsITimer::TYPE_ONE_SHOT, + aWindow->EventTargetFor(TaskCategory::Other)); } PaymentResponse::~PaymentResponse() @@ -136,16 +143,13 @@ PaymentResponse::Complete(PaymentComplete result, ErrorResult& aRv) return nullptr; } - nsIGlobalObject* global = mOwner->AsGlobal(); - ErrorResult errResult; - RefPtr promise = Promise::Create(global, errResult); - if (errResult.Failed()) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; - } - mCompleteCalled = true; + if (mTimer) { + mTimer->Cancel(); + mTimer = nullptr; + } + RefPtr manager = PaymentRequestManager::GetSingleton(); if (NS_WARN_IF(!manager)) { aRv.Throw(NS_ERROR_FAILURE); @@ -153,8 +157,16 @@ PaymentResponse::Complete(PaymentComplete result, ErrorResult& aRv) } nsresult rv = manager->CompletePayment(mRequest, result); if (NS_WARN_IF(NS_FAILED(rv))) { - promise->MaybeReject(NS_ERROR_FAILURE); - return promise.forget(); + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsIGlobalObject* global = mOwner->AsGlobal(); + ErrorResult errResult; + RefPtr promise = Promise::Create(global, errResult); + if (errResult.Failed()) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; } mPromise = promise; @@ -164,10 +176,29 @@ PaymentResponse::Complete(PaymentComplete result, ErrorResult& aRv) void PaymentResponse::RespondComplete() { - MOZ_ASSERT(mPromise); + // mPromise may be null when timing out + if (mPromise) { + mPromise->MaybeResolve(JS::UndefinedHandleValue); + mPromise = nullptr; + } +} - mPromise->MaybeResolve(JS::UndefinedHandleValue); - mPromise = nullptr; +NS_IMETHODIMP +PaymentResponse::Notify(nsITimer *timer) +{ + mTimer = nullptr; + if (mCompleteCalled) { + return NS_OK; + } + + mCompleteCalled = true; + + RefPtr manager = PaymentRequestManager::GetSingleton(); + if (NS_WARN_IF(!manager)) { + return NS_ERROR_FAILURE; + } + + return manager->CompletePayment(mRequest, PaymentComplete::Unknown, true); } } // namespace dom diff --git a/dom/payments/PaymentResponse.h b/dom/payments/PaymentResponse.h index abee42963ad7..9bba1d80c8a5 100644 --- a/dom/payments/PaymentResponse.h +++ b/dom/payments/PaymentResponse.h @@ -10,6 +10,7 @@ #include "mozilla/dom/PaymentResponseBinding.h" // PaymentComplete #include "nsPIDOMWindow.h" #include "nsWrapperCache.h" +#include "nsITimer.h" namespace mozilla { namespace dom { @@ -18,13 +19,15 @@ class PaymentAddress; class PaymentRequest; class Promise; -class PaymentResponse final : public nsISupports, +class PaymentResponse final : public nsITimerCallback, public nsWrapperCache { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PaymentResponse) + NS_IMETHOD Notify(nsITimer* aTimer) override; + PaymentResponse(nsPIDOMWindowInner* aWindow, PaymentRequest* aRequest, const nsAString& aRequestId, @@ -83,6 +86,9 @@ private: RefPtr mShippingAddress; // Promise for "PaymentResponse::Complete" RefPtr mPromise; + // Timer for timing out if the page doesn't call + // complete() + nsCOMPtr mTimer; }; } // namespace dom diff --git a/modules/libpref/init/StaticPrefList.h b/modules/libpref/init/StaticPrefList.h index e0ab3ec72db7..98f93ac1d109 100644 --- a/modules/libpref/init/StaticPrefList.h +++ b/modules/libpref/init/StaticPrefList.h @@ -116,6 +116,14 @@ VARCACHE_PREF( // Note, this is not currently safe to use for normal browsing yet. PREF("dom.serviceWorkers.parent_intercept", bool, false) +// Time in milliseconds for PaymentResponse to wait for +// the Web page to call complete(). +VARCACHE_PREF( + "dom.payments.response.timeout", + dom_payments_response_timeout, + uint32_t, 5000 +) + //--------------------------------------------------------------------------- // Clear-Site-Data prefs //---------------------------------------------------------------------------