Bug 1379892 - Reject PaymentRequest.show() with AbortError DOMException if a request is showing. r=baku
authorEden Chuang <echuang@mozilla.com>
Tue, 25 Jul 2017 15:39:39 +0800
changeset 419721 dd757326f72bac40ecc8b387a4ea8ed1dd53b873
parent 419720 1d14aaceb2f6e3afb490ef4f4af54fd32265b1e8
child 419722 d46324978a6db2a584a17c2ddfaba0caba8dec3b
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1379892
milestone56.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 1379892 - Reject PaymentRequest.show() with AbortError DOMException if a request is showing. r=baku
dom/payments/PaymentRequest.cpp
dom/payments/PaymentRequestManager.cpp
dom/payments/PaymentRequestManager.h
dom/payments/PaymentRequestService.cpp
dom/payments/PaymentRequestService.h
--- a/dom/payments/PaymentRequest.cpp
+++ b/dom/payments/PaymentRequest.cpp
@@ -379,17 +379,21 @@ PaymentRequest::Show(ErrorResult& aRv)
   RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
   if (NS_WARN_IF(!manager)) {
     mState = eClosed;
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
   nsresult rv = manager->ShowPayment(mInternalId);
   if (NS_WARN_IF(NS_FAILED(rv))) {
-    promise->MaybeReject(NS_ERROR_FAILURE);
+    if (rv == NS_ERROR_ABORT) {
+      promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
+    } else {
+      promise->MaybeReject(NS_ERROR_DOM_NOT_ALLOWED_ERR);
+    }
     mState = eClosed;
     return promise.forget();
   }
 
   mAcceptPromise = promise;
   mState = eInteractive;
   return promise.forget();
 }
--- a/dom/payments/PaymentRequestManager.cpp
+++ b/dom/payments/PaymentRequestManager.cpp
@@ -485,25 +485,29 @@ PaymentRequestManager::CanMakePayment(co
   IPCPaymentCanMakeActionRequest action(requestId);
 
   return SendRequestPayment(request, action);
 }
 
 nsresult
 PaymentRequestManager::ShowPayment(const nsAString& aRequestId)
 {
+  if (mShowingRequest) {
+    return NS_ERROR_ABORT;
+  }
   RefPtr<PaymentRequest> request = GetPaymentRequestById(aRequestId);
   if (!request) {
     return NS_ERROR_FAILURE;
   }
 
   nsAutoString requestId(aRequestId);
   IPCPaymentShowActionRequest action(requestId);
-
-  return SendRequestPayment(request, action);
+  nsresult rv = SendRequestPayment(request, action);
+  mShowingRequest = request;
+  return rv;
 }
 
 nsresult
 PaymentRequestManager::AbortPayment(const nsAString& aRequestId)
 {
   RefPtr<PaymentRequest> request = GetPaymentRequestById(aRequestId);
   if (!request) {
     return NS_ERROR_FAILURE;
@@ -588,47 +592,53 @@ PaymentRequestManager::RespondPayment(co
       }
       request->RespondShowPayment(response.isAccepted(),
                                   response.methodName(),
                                   response.data(),
                                   response.payerName(),
                                   response.payerEmail(),
                                   response.payerPhone());
       if (!response.isAccepted()) {
+        MOZ_ASSERT(mShowingRequest == request);
+        mShowingRequest = nullptr;
         mRequestQueue.RemoveElement(request);
         nsresult rv = ReleasePaymentChild(request);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
       }
       break;
     }
     case IPCPaymentActionResponse::TIPCPaymentAbortActionResponse: {
       const IPCPaymentAbortActionResponse& response = aResponse;
       RefPtr<PaymentRequest> request = GetPaymentRequestById(response.requestId());
       if (NS_WARN_IF(!request)) {
         return NS_ERROR_FAILURE;
       }
       request->RespondAbortPayment(response.isSucceeded());
       if (response.isSucceeded()) {
+        MOZ_ASSERT(mShowingRequest == request);
+        mShowingRequest = nullptr;
         mRequestQueue.RemoveElement(request);
         nsresult rv = ReleasePaymentChild(request);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
       }
       break;
     }
     case IPCPaymentActionResponse::TIPCPaymentCompleteActionResponse: {
       const IPCPaymentCompleteActionResponse& response = aResponse;
       RefPtr<PaymentRequest> request = GetPaymentRequestById(response.requestId());
       if (NS_WARN_IF(!request)) {
         return NS_ERROR_FAILURE;
       }
       request->RespondComplete();
+      MOZ_ASSERT(mShowingRequest == request);
+      mShowingRequest = nullptr;
       mRequestQueue.RemoveElement(request);
       nsresult rv = ReleasePaymentChild(request);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       break;
     }
     default: {
--- a/dom/payments/PaymentRequestManager.h
+++ b/dom/payments/PaymentRequestManager.h
@@ -74,14 +74,15 @@ private:
 
   nsresult SendRequestPayment(PaymentRequest* aRequest,
                               const IPCPaymentActionRequest& action,
                               bool aReleaseAfterSend = false);
 
   // The container for the created PaymentRequests
   nsTArray<RefPtr<PaymentRequest>> mRequestQueue;
   nsRefPtrHashtable<nsRefPtrHashKey<PaymentRequest>, PaymentRequestChild> mPaymentChildHash;
+  RefPtr<PaymentRequest> mShowingRequest;
 };
 
 } // end of namespace dom
 } // end of namespace mozilla
 
 #endif
--- a/dom/payments/PaymentRequestService.cpp
+++ b/dom/payments/PaymentRequestService.cpp
@@ -301,21 +301,56 @@ PaymentRequestService::RequestPayment(ns
     }
     /*
      *  TODO: 1. Check basic card support once the Basic Card Payment spec is
      *           implemented.
      *           https://www.w3.org/TR/payment-method-basic-card/
      *        2. Check third party payment app support by traversing all
      *           registered third party payment apps.
      */
-    case nsIPaymentActionRequest::CANMAKE_ACTION:
+    case nsIPaymentActionRequest::CANMAKE_ACTION: {
+      rv = CallTestingUIAction(requestId, type);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return NS_ERROR_FAILURE;
+      }
+      break;
+    }
     /*
      *  TODO: Launch/inform payment UI here once the UI module is implemented.
      */
-    case nsIPaymentActionRequest::SHOW_ACTION:
+    case nsIPaymentActionRequest::SHOW_ACTION: {
+      if (mShowingRequest) {
+        nsCOMPtr<nsIPaymentShowActionResponse> showResponse =
+          do_CreateInstance(NS_PAYMENT_SHOW_ACTION_RESPONSE_CONTRACT_ID);
+        MOZ_ASSERT(showResponse);
+        rv = showResponse->Init(requestId,
+                                nsIPaymentActionResponse::PAYMENT_REJECTED,
+                                EmptyString(),
+                                EmptyString(),
+                                EmptyString(),
+                                EmptyString(),
+                                EmptyString());
+        nsCOMPtr<nsIPaymentActionResponse> response = do_QueryInterface(showResponse);
+        MOZ_ASSERT(response);
+        rv = RespondPayment(response);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
+      } else {
+        rv = GetPaymentRequestById(requestId, getter_AddRefs(mShowingRequest));
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return NS_ERROR_FAILURE;
+        }
+        rv = CallTestingUIAction(requestId, type);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return NS_ERROR_FAILURE;
+        }
+      }
+      break;
+    }
     case nsIPaymentActionRequest::ABORT_ACTION:
     case nsIPaymentActionRequest::COMPLETE_ACTION: {
       rv = CallTestingUIAction(requestId, type);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return NS_ERROR_FAILURE;
       }
       break;
     }
@@ -386,21 +421,36 @@ PaymentRequestService::RespondPayment(ns
     case nsIPaymentActionResponse::ABORT_ACTION: {
       nsCOMPtr<nsIPaymentAbortActionResponse> response =
         do_QueryInterface(aResponse);
       MOZ_ASSERT(response);
       bool isSucceeded;
       rv = response->IsSucceeded(&isSucceeded);
       NS_ENSURE_SUCCESS(rv, rv);
       if (isSucceeded) {
+        mShowingRequest = nullptr;
+        mRequestQueue.RemoveElement(request);
+      }
+      break;
+    }
+    case nsIPaymentActionResponse::SHOW_ACTION: {
+      nsCOMPtr<nsIPaymentShowActionResponse> response =
+        do_QueryInterface(aResponse);
+      MOZ_ASSERT(response);
+      bool isAccepted;
+      rv = response->IsAccepted(&isAccepted);
+      NS_ENSURE_SUCCESS(rv, rv);
+      if (!isAccepted) {
+        mShowingRequest = nullptr;
         mRequestQueue.RemoveElement(request);
       }
       break;
     }
     case nsIPaymentActionResponse::COMPLETE_ACTION: {
+      mShowingRequest = nullptr;
       mRequestQueue.RemoveElement(request);
       break;
     }
     default: {
       break;
     }
   }
   return NS_OK;
--- a/dom/payments/PaymentRequestService.h
+++ b/dom/payments/PaymentRequestService.h
@@ -46,14 +46,16 @@ private:
   nsresult
   CallTestingUIAction(const nsAString& aRequestId, uint32_t aActionType);
 
   FallibleTArray<nsCOMPtr<nsIPaymentRequest>> mRequestQueue;
 
   nsInterfaceHashtable<nsStringHashKey, nsIPaymentActionCallback> mCallbackHashtable;
 
   nsCOMPtr<nsIPaymentUIService> mTestingUIService;
+
+  nsCOMPtr<nsIPaymentRequest> mShowingRequest;
 };
 
 } // end of namespace dom
 } // end of namespace mozilla
 
 #endif