Bug 1447773 - Time out PaymentResponse after 5 seconds. r=mrbkap
authorHenri Sivonen <hsivonen@hsivonen.fi>
Tue, 29 May 2018 12:31:22 +0300
changeset 478984 4f3f19b029f7bb2989f0cefa4def52da8a6ab32c
parent 478983 378b43fe165858dbf7d43800eaa88f0317dd7180
child 478985 57e7214b6ff82f61d735544abd3a70906a204a1d
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs1447773
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1447773 - Time out PaymentResponse after 5 seconds. r=mrbkap MozReview-Commit-ID: JnoKgLC6yL6
dom/payments/PaymentRequestManager.cpp
dom/payments/PaymentRequestManager.h
dom/payments/PaymentResponse.cpp
dom/payments/PaymentResponse.h
modules/libpref/init/StaticPrefList.h
--- a/dom/payments/PaymentRequestManager.cpp
+++ b/dom/payments/PaymentRequestManager.cpp
@@ -473,23 +473,28 @@ PaymentRequestManager::AbortPayment(Paym
 
   // If aDeferredShow is true, then show was called with a promise that was
   // rejected. In that case, we need to remember that we called show earlier.
   return SendRequestPayment(aRequest, action, 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<uint8_t>(aComplete);
-  if (completeIndex < ArrayLength(PaymentCompleteValues::strings)) {
-    completeStatusString.AssignASCII(
-      PaymentCompleteValues::strings[completeIndex].value);
+  if (aTimedOut) {
+    completeStatusString.AssignLiteral("timeout");
+  } else {
+    uint8_t completeIndex = static_cast<uint8_t>(aComplete);
+    if (completeIndex < ArrayLength(PaymentCompleteValues::strings)) {
+      completeStatusString.AssignASCII(
+        PaymentCompleteValues::strings[completeIndex].value);
+    }
   }
 
   nsAutoString requestId;
   aRequest->GetInternalId(requestId);
   IPCPaymentCompleteActionRequest action(requestId, completeStatusString);
 
   return SendRequestPayment(aRequest, action, false);
 }
--- a/dom/payments/PaymentRequestManager.h
+++ b/dom/payments/PaymentRequestManager.h
@@ -45,17 +45,18 @@ public:
                 const PaymentDetailsInit& aDetails,
                 const PaymentOptions& aOptions,
                 PaymentRequest** aRequest);
 
   nsresult CanMakePayment(PaymentRequest* aRequest);
   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,
                          bool aRequestShipping,
                          bool aDeferredShow);
 
   nsresult RespondPayment(PaymentRequest* aRequest,
                           const IPCPaymentActionResponse& aResponse);
--- a/dom/payments/PaymentResponse.cpp
+++ b/dom/payments/PaymentResponse.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/StaticPrefs.h"
 #include "mozilla/dom/PaymentResponse.h"
 #include "mozilla/dom/BasicCardPaymentBinding.h"
 #include "BasicCardPayment.h"
 #include "PaymentAddress.h"
 #include "PaymentRequestUtils.h"
 
 namespace mozilla {
 namespace dom {
@@ -17,16 +18,17 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Pa
                                       mShippingAddress, mPromise)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(PaymentResponse)
 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,
                                  PaymentRequest* aRequest,
                                  const nsAString& aRequestId,
                                  const nsAString& aMethodName,
                                  const nsAString& aShippingOption,
                                  RefPtr<PaymentAddress> aShippingAddress,
@@ -44,16 +46,21 @@ PaymentResponse::PaymentResponse(nsPIDOM
   , mPayerName(aPayerName)
   , mPayerEmail(aPayerEmail)
   , mPayerPhone(aPayerPhone)
   , mShippingAddress(aShippingAddress)
 {
 
   // 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()
 {
 }
 
 JSObject*
 PaymentResponse::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
@@ -131,44 +138,68 @@ PaymentResponse::GetShippingAddress() co
 already_AddRefed<Promise>
 PaymentResponse::Complete(PaymentComplete result, ErrorResult& aRv)
 {
   if (mCompleteCalled) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
-  nsIGlobalObject* global = mOwner->AsGlobal();
-  ErrorResult errResult;
-  RefPtr<Promise> promise = Promise::Create(global, errResult);
-  if (errResult.Failed()) {
-    aRv.Throw(NS_ERROR_FAILURE);
-    return nullptr;
+  mCompleteCalled = true;
+
+  if (mTimer) {
+    mTimer->Cancel();
+    mTimer = nullptr;
   }
 
-  mCompleteCalled = true;
-
   RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
   if (NS_WARN_IF(!manager)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
   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 = Promise::Create(global, errResult);
+  if (errResult.Failed()) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
   }
 
   mPromise = promise;
   return promise.forget();
 }
 
 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<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
+  if (NS_WARN_IF(!manager)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return manager->CompletePayment(mRequest, PaymentComplete::Unknown, true);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/payments/PaymentResponse.h
+++ b/dom/payments/PaymentResponse.h
@@ -5,31 +5,34 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_PaymentResponse_h
 #define mozilla_dom_PaymentResponse_h
 
 #include "mozilla/dom/PaymentResponseBinding.h" // PaymentComplete
 #include "nsPIDOMWindow.h"
 #include "nsWrapperCache.h"
+#include "nsITimer.h"
 
 namespace mozilla {
 namespace dom {
 
 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,
                   const nsAString& aMethodName,
                   const nsAString& aShippingOption,
                   RefPtr<PaymentAddress> aShippingAddress,
                   const nsAString& aDetails,
                   const nsAString& aPayerName,
@@ -78,14 +81,17 @@ private:
   nsString mDetails;
   nsString mShippingOption;
   nsString mPayerName;
   nsString mPayerEmail;
   nsString mPayerPhone;
   RefPtr<PaymentAddress> mShippingAddress;
   // Promise for "PaymentResponse::Complete"
   RefPtr<Promise> mPromise;
+  // Timer for timing out if the page doesn't call
+  // complete()
+  nsCOMPtr<nsITimer> mTimer;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_PaymentResponse_h
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -111,16 +111,24 @@ VARCACHE_PREF(
   RelaxedAtomicBool, false
 )
 
 // If true. then the service worker interception and the ServiceWorkerManager
 // will live in the parent process.  This only takes effect on browser start.
 // 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
 //---------------------------------------------------------------------------
 
 #ifdef NIGHTLY
 # define PREF_VALUE true
 #else
 # define PREF_VALUE false