Bug 1375345 - Basic card payment method implementation. r?baku
authorEden Chuang <echuang@mozilla.com>
Sun, 16 Jul 2017 22:20:13 +0800
changeset 1186621 e37f3e5e026d71e4e79aba9a6ad49403864b9f17
parent 1185718 7d92f47379da55adf4da6d0b16398f5c629cf949
child 1186622 a74cda5423fe7369cc37e310eac44ce513364969
push id205358
push userechuang@mozilla.com
push dateSun, 16 Jul 2017 14:24:58 +0000
treeherdertry@daee8196c877 [default view] [failures only]
reviewersbaku
bugs1375345
milestone56.0a1
Bug 1375345 - Basic card payment method implementation. r?baku
dom/interfaces/payments/nsIPaymentActionResponse.idl
dom/interfaces/payments/nsIPaymentRequest.idl
dom/payments/BasicCardPayment.cpp
dom/payments/BasicCardPayment.h
dom/payments/PaymentActionResponse.cpp
dom/payments/PaymentActionResponse.h
dom/payments/PaymentRequest.cpp
dom/payments/PaymentRequestData.cpp
dom/payments/PaymentRequestModule.cpp
dom/payments/PaymentRequestService.cpp
dom/payments/PaymentRequestService.h
dom/payments/PaymentRequestUtils.cpp
dom/payments/PaymentRequestUtils.h
dom/payments/PaymentResponse.cpp
dom/payments/moz.build
dom/webidl/BasicCardPayment.webidl
dom/webidl/moz.build
--- a/dom/interfaces/payments/nsIPaymentActionResponse.idl
+++ b/dom/interfaces/payments/nsIPaymentActionResponse.idl
@@ -1,15 +1,57 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "nsISupports.idl"
 #include "nsIVariant.idl"
+#include "nsIPaymentAddress.idl"
+
+[builtinclass, scriptable, uuid(2a338575-c688-40ee-a157-7488ab292ef2)]
+interface nsIPaymentResponseData: nsISupports
+{
+  const uint32_t GENERAL_RESPONSE = 0;
+  const uint32_t BASICCARD_RESPONSE = 1;
+
+  readonly attribute uint32_t type;
+  void init(in uint32_t aType);
+};
+
+[builtinclass, scriptable, uuid(b986773e-2b30-4ed2-b8fe-6a96631c8000)]
+interface nsIGeneralResponseData : nsIPaymentResponseData
+{
+  readonly attribute AString data;
+
+  [implicit_jscontext]
+  void initData(in jsval aData);
+};
+
+/*
+  Since PaymentAddress is an no constructor interface type, UI code can not
+  easy create PaymentAddress by calling new PaymentAddress().
+  Unfortunately, BasicCardResponse has a PaymentAddress attribute, billingAddress
+  , it means UI can not create BsaicCardResponse by calling the init() with a
+  given JSObject directly, because PaymentAddress creation in JS code is hard.
+  To let UI code can create BasicCardResponse easier, nsIBasicCardResponse is
+  provided for UI by passing the raw data of BasicCardResponse,
+*/
+[builtinclass, scriptable, uuid(0d55a5e6-d185-44f0-b992-a8e1321e4bce)]
+interface nsIBasicCardResponseData : nsIPaymentResponseData
+{
+  readonly attribute AString data;
+
+  void initData(in AString aCardholderName,
+                in AString aCardNumber,
+                in AString aExpiryMonth,
+                in AString aExpiryYear,
+                in AString aCardSecurityCode,
+                in nsIPaymentAddress billingAddress);
+};
 
 [builtinclass, scriptable, uuid(a607c095-ef60-4a9b-a3d0-0506c60728b3)]
 interface nsIPaymentActionResponse : nsISupports
 {
   /*
    *  Align type to nsIPaymentActionRequest types,
    *  where 1 is for payment request creation.
    *  the action expects no response from UI module.
@@ -89,17 +131,17 @@ interface nsIPaymentShowActionResponse :
   readonly attribute AString payerPhone;
 
   /*
    *  Initialize function for this response.
    */
   void init(in AString aRequestId,
             in uint32_t aAcceptStatus,
             in AString aMethodName,
-            in AString aData,
+            in nsIPaymentResponseData aData,
             in AString aPayerName,
             in AString aPayerEmail,
             in AString aPayerPhone);
 
   /*
    *  Check if the payment is accpeted
    */
   bool isAccepted();
@@ -137,16 +179,26 @@ interface nsIPaymentCompleteActionRespon
 
   /*
    *  Check if the UI is finished.
    */
   bool isCompleted();
 };
 
 %{C++
+#define NS_GENERAL_RESPONSE_DATA_CID \
+  { 0xb986773e, 0x2b30, 0x4ed2, { 0xb8, 0xfe, 0x6a, 0x96, 0x63, 0x1c, 0x80, 0x00 } }
+#define NS_GENERAL_RESPONSE_DATA_CONTRACT_ID \
+  "@mozilla.org/dom/payments/general-response-data;1"
+
+#define NS_BASICCARD_RESPONSE_DATA_CID \
+  { 0x0d55a5e6, 0xd185, 0x44f0, { 0xb9, 0x92, 0xa8, 0xe1, 0x32, 0x1e, 0x4b, 0xce } }
+#define NS_BASICCARD_RESPONSE_DATA_CONTRACT_ID \
+  "@mozilla.org/dom/payments/basiccard-response-data;1"
+
 #define NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CID \
   { 0x52fc3f9f, 0xc0cb, 0x4874, { 0xb3, 0xd4, 0xee, 0x4b, 0x6e, 0x9c, 0xbe, 0x9c } }
 #define NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CONTRACT_ID \
   "@mozilla.org/dom/payments/payment-canmake-action-response;1"
 
 #define NS_PAYMENT_SHOW_ACTION_RESPONSE_CID \
   { 0x184385cb, 0x2d35, 0x4b99, { 0xa9, 0xa3, 0x7c, 0x78, 0x0b, 0xf6, 0x6b, 0x9b } }
 #define NS_PAYMENT_SHOW_ACTION_RESPONSE_CONTRACT_ID \
--- a/dom/interfaces/payments/nsIPaymentRequest.idl
+++ b/dom/interfaces/payments/nsIPaymentRequest.idl
@@ -7,17 +7,18 @@
 #include "nsIVariant.idl"
 
 interface nsIArray;
 
 [scriptable, builtinclass, uuid(2fe296cc-d917-4820-b492-aa42df23f9b4)]
 interface nsIPaymentMethodData : nsISupports
 {
   readonly attribute AString supportedMethods;
-  readonly attribute AString data;
+  [implicit_jscontext]
+  readonly attribute jsval data;
 };
 
 [scriptable, builtinclass, uuid(d22a6f5f-767b-4fea-bf92-68b0b8003eba)]
 interface nsIPaymentCurrencyAmount : nsISupports
 {
   readonly attribute AString currency;
   readonly attribute AString value;
 };
@@ -31,17 +32,18 @@ interface nsIPaymentItem : nsISupports
 };
 
 [scriptable, builtinclass, uuid(74259861-c318-40e8-b3d5-518e701bed80)]
 interface nsIPaymentDetailsModifier : nsISupports
 {
   readonly attribute AString supportedMethods;
   readonly attribute nsIPaymentItem total;
   readonly attribute nsIArray additionalDisplayItems;
-  readonly attribute AString data;
+  [implicit_jscontext]
+  readonly attribute jsval data;
 };
 
 [scriptable, builtinclass, uuid(68341551-3605-4381-b936-41e830aa88fb)]
 interface nsIPaymentShippingOption : nsISupports
 {
   readonly attribute AString id;
   readonly attribute AString label;
   readonly attribute nsIPaymentCurrencyAmount amount;
new file mode 100644
--- /dev/null
+++ b/dom/payments/BasicCardPayment.cpp
@@ -0,0 +1,414 @@
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "BasicCardPayment.h"
+#include "PaymentAddress.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "nsArrayUtils.h"
+#include "nsISupportsPrimitives.h"
+#include "nsCharSeparatedTokenizer.h"
+#include "nsDataHashtable.h"
+
+namespace mozilla {
+namespace dom {
+
+StaticRefPtr<BasicCardService> gBasicCardService;
+
+already_AddRefed<BasicCardService>
+BasicCardService::GetService()
+{
+  if (!gBasicCardService) {
+    gBasicCardService = new BasicCardService();
+    ClearOnShutdown(&gBasicCardService);
+  }
+  RefPtr<BasicCardService> service = gBasicCardService;
+  return service.forget();
+}
+
+BasicCardService::BasicCardService()
+  : cardholderNameKey(NS_LITERAL_STRING("cardholderName"))
+  , cardNumberKey(NS_LITERAL_STRING("cardNumber"))
+  , expiryMonthKey(NS_LITERAL_STRING("expiryMonth"))
+  , expiryYearKey(NS_LITERAL_STRING("expiryYear"))
+  , cardSecurityCodeKey(NS_LITERAL_STRING("cardSecurityCode"))
+  , countryKey(NS_LITERAL_STRING("country"))
+  , addressLineKey(NS_LITERAL_STRING("addressLine"))
+  , regionKey(NS_LITERAL_STRING("region"))
+  , cityKey(NS_LITERAL_STRING("city"))
+  , dependentLocalityKey(NS_LITERAL_STRING("dependentLocality"))
+  , postalCodeKey(NS_LITERAL_STRING("postalCode"))
+  , sortingCodeKey(NS_LITERAL_STRING("sortingCode"))
+  , languageCodeKey(NS_LITERAL_STRING("languageCode"))
+  , organizationKey(NS_LITERAL_STRING("organization"))
+  , recipientKey(NS_LITERAL_STRING("recipient"))
+  , phoneKey(NS_LITERAL_STRING("phone"))
+  , propertySpliter(NS_LITERAL_STRING(";"))
+  , keyValueSpliter(NS_LITERAL_STRING(":"))
+  , addressLineSpliter(NS_LITERAL_STRING("%"))
+{
+  mAddressKeys.AppendElement(countryKey);
+  mAddressKeys.AppendElement(addressLineKey);
+  mAddressKeys.AppendElement(regionKey);
+  mAddressKeys.AppendElement(cityKey);
+  mAddressKeys.AppendElement(dependentLocalityKey);
+  mAddressKeys.AppendElement(postalCodeKey);
+  mAddressKeys.AppendElement(sortingCodeKey);
+  mAddressKeys.AppendElement(languageCodeKey);
+  mAddressKeys.AppendElement(organizationKey);
+  mAddressKeys.AppendElement(recipientKey);
+  mAddressKeys.AppendElement(phoneKey);
+
+  mValidNetworks.AppendElement(NS_LITERAL_STRING("amex"));
+  mValidNetworks.AppendElement(NS_LITERAL_STRING("cartebancaire"));
+  mValidNetworks.AppendElement(NS_LITERAL_STRING("diners"));
+  mValidNetworks.AppendElement(NS_LITERAL_STRING("discover"));
+  mValidNetworks.AppendElement(NS_LITERAL_STRING("jcb"));
+  mValidNetworks.AppendElement(NS_LITERAL_STRING("mastercard"));
+  mValidNetworks.AppendElement(NS_LITERAL_STRING("mir"));
+  mValidNetworks.AppendElement(NS_LITERAL_STRING("unionpay"));
+  mValidNetworks.AppendElement(NS_LITERAL_STRING("visa"));
+}
+
+bool
+BasicCardService::IsBasicCardPayment(const nsAString& aSupportedMethods)
+{
+  return aSupportedMethods.Equals(NS_LITERAL_STRING("basic-card"));
+}
+
+bool
+BasicCardService::IsValidBasicCardRequest(JSContext* aCx,
+                                          JSObject* aData,
+                                          nsAString& aErrorMsg)
+{
+  if (!aData) {
+    return true;
+  }
+  JS::RootedValue data(aCx, JS::ObjectValue(*aData));
+  JS::HandleValue dataHandle(&data);
+
+  BasicCardRequest request;
+  if (!request.Init(aCx, dataHandle)) {
+    aErrorMsg.AssignLiteral("Fail to convert methodData.data to BasicCardRequest.");
+    return false;
+  }
+
+  if (request.mSupportedNetworks.WasPassed()) {
+    for (const nsString& network : request.mSupportedNetworks.Value()) {
+      if (!mValidNetworks.Contains(network)) {
+        aErrorMsg.Assign(network + NS_LITERAL_STRING(" is not an valid network."));
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+bool
+BasicCardService::IsValidExpiryMonth(const nsAString& aExpiryMonth)
+{
+  // ExpiryMonth can only be
+  //   1. empty string
+  //   2. 01 ~ 12
+  if (!aExpiryMonth.IsEmpty()) {
+    if (aExpiryMonth.Length() != 2) {
+      return false;
+    }
+    // can only be 0X or 1X
+    if (aExpiryMonth.CharAt(0) != '0' && aExpiryMonth.CharAt(0) != '1') {
+      return false;
+    }
+    // can only be 00 ~ 09
+    if (aExpiryMonth.CharAt(0) == '0') {
+      if (aExpiryMonth.CharAt(1) < '0' || aExpiryMonth.CharAt(1) > '9') {
+        return false;
+      }
+    }
+    // can only be 11 or 12
+    if (aExpiryMonth.CharAt(0) == '1') {
+      if (aExpiryMonth.CharAt(1) != '1' && aExpiryMonth.CharAt(1) != '2') {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+bool
+BasicCardService::IsValidExpiryYear(const nsAString& aExpiryYear)
+{
+  // ExpiryYear can only be
+  //   1. empty string
+  //   2. 0000 ~ 9999
+  if (!aExpiryYear.IsEmpty()) {
+    if (aExpiryYear.Length() != 4) {
+      return false;
+    }
+    for (uint32_t index = 0; index < 4; ++index) {
+      if (aExpiryYear.CharAt(index) < '0' ||
+          aExpiryYear.CharAt(index) > '9') {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+
+nsresult
+BasicCardService::EncodeBasicCardData(const nsAString& aCardholderName,
+                                      const nsAString& aCardNumber,
+                                      const nsAString& aExpiryMonth,
+                                      const nsAString& aExpiryYear,
+                                      const nsAString& aCardSecurityCode,
+                                      nsIPaymentAddress* aBillingAddress,
+                                      nsAString& aResult)
+{
+  // aBillingAddress can be nullptr
+  nsString data;
+  nsDataHashtable<nsStringHashKey, nsString> propertiesHash;
+
+  if (!aCardholderName.IsEmpty()) {
+    data = aCardholderName;
+    if (!propertiesHash.Put(cardholderNameKey, data, mozilla::fallible)) {
+      return NS_ERROR_FAILURE;
+    }
+  }
+  MOZ_ASSERT(!aCardNumber.IsEmpty());
+  data = aCardNumber;
+  if (!propertiesHash.Put(cardNumberKey, data, mozilla::fallible)) {
+    return NS_ERROR_FAILURE;
+  }
+  if (!aExpiryMonth.IsEmpty()) {
+    data = aExpiryMonth;
+    if (!propertiesHash.Put(expiryMonthKey, data, mozilla::fallible)) {
+      return NS_ERROR_FAILURE;
+    }
+  }
+  if (!aExpiryYear.IsEmpty()) {
+    data = aExpiryYear;
+    if (!propertiesHash.Put(expiryYearKey, data, mozilla::fallible)) {
+      return NS_ERROR_FAILURE;
+    }
+  }
+  if (!aCardSecurityCode.IsEmpty()) {
+    data = aCardSecurityCode;
+    if (!propertiesHash.Put(cardSecurityCodeKey, data, mozilla::fallible)) {
+      return NS_ERROR_FAILURE;
+    }
+  }
+
+  if (aBillingAddress) {
+    NS_ENSURE_SUCCESS(aBillingAddress->GetCountry(data), NS_ERROR_FAILURE);
+    if (!data.IsEmpty()) {
+      if (!propertiesHash.Put(countryKey, data, mozilla::fallible)) {
+        return NS_ERROR_FAILURE;
+      }
+    }
+    nsCOMPtr<nsIArray> addressLine;
+    NS_ENSURE_SUCCESS(aBillingAddress->GetAddressLine(getter_AddRefs(addressLine)),
+                      NS_ERROR_FAILURE);
+    uint32_t length;
+    nsString addressLineString;
+    NS_ENSURE_SUCCESS(addressLine->GetLength(&length), NS_ERROR_FAILURE);
+    for (uint32_t index = 0; index < length; ++index) {
+      nsCOMPtr<nsISupportsString> address = do_QueryElementAt(addressLine, index);
+      MOZ_ASSERT(address);
+      nsString addressString;
+      NS_ENSURE_SUCCESS(address->GetData(addressString), NS_ERROR_FAILURE);
+      addressLineString += addressString + addressLineSpliter;
+    }
+    if (!addressLineString.IsEmpty()) {
+      if (!propertiesHash.Put(addressLineKey, addressLineString, mozilla::fallible)) {
+        return NS_ERROR_FAILURE;
+      }
+    }
+
+    NS_ENSURE_SUCCESS(aBillingAddress->GetRegion(data), NS_ERROR_FAILURE);
+    if (!data.IsEmpty()) {
+      if (!propertiesHash.Put(regionKey, data, mozilla::fallible)) {
+        return NS_ERROR_FAILURE;
+      }
+    }
+    NS_ENSURE_SUCCESS(aBillingAddress->GetCity(data), NS_ERROR_FAILURE);
+    if (!data.IsEmpty()) {
+      if (!propertiesHash.Put(cityKey, data, mozilla::fallible)) {
+        return NS_ERROR_FAILURE;
+      }
+    }
+    NS_ENSURE_SUCCESS(aBillingAddress->GetDependentLocality(data), NS_ERROR_FAILURE);
+    if (!data.IsEmpty()) {
+      if (!propertiesHash.Put(dependentLocalityKey, data, mozilla::fallible)) {
+        return NS_ERROR_FAILURE;
+      }
+    }
+    NS_ENSURE_SUCCESS(aBillingAddress->GetPostalCode(data), NS_ERROR_FAILURE);
+    if (!data.IsEmpty()) {
+      if (!propertiesHash.Put(postalCodeKey, data, mozilla::fallible)) {
+        return NS_ERROR_FAILURE;
+      }
+    }
+    NS_ENSURE_SUCCESS(aBillingAddress->GetSortingCode(data), NS_ERROR_FAILURE);
+    if (!data.IsEmpty()) {
+      if (!propertiesHash.Put(sortingCodeKey, data, mozilla::fallible)) {
+        return NS_ERROR_FAILURE;
+      }
+    }
+    NS_ENSURE_SUCCESS(aBillingAddress->GetLanguageCode(data), NS_ERROR_FAILURE);
+    if (!data.IsEmpty()) {
+      if (!propertiesHash.Put(languageCodeKey, data, mozilla::fallible)) {
+        return NS_ERROR_FAILURE;
+      }
+    }
+    NS_ENSURE_SUCCESS(aBillingAddress->GetOrganization(data), NS_ERROR_FAILURE);
+    if (!data.IsEmpty()) {
+      if (!propertiesHash.Put(organizationKey, data, mozilla::fallible)) {
+        return NS_ERROR_FAILURE;
+      }
+    }
+    NS_ENSURE_SUCCESS(aBillingAddress->GetRecipient(data), NS_ERROR_FAILURE);
+    if (!data.IsEmpty()) {
+      if (!propertiesHash.Put(recipientKey, data, mozilla::fallible)) {
+        return NS_ERROR_FAILURE;
+      }
+    }
+    NS_ENSURE_SUCCESS(aBillingAddress->GetPhone(data), NS_ERROR_FAILURE);
+    if (!data.IsEmpty()) {
+      if (!propertiesHash.Put(phoneKey, data, mozilla::fallible)) {
+        return NS_ERROR_FAILURE;
+      }
+    }
+  }
+
+  for (auto iter = propertiesHash.ConstIter(); !iter.Done(); iter.Next()) {
+    aResult += iter.Key() + keyValueSpliter + iter.Data() + propertySpliter;
+  }
+  return NS_OK;
+}
+
+nsresult
+BasicCardService::DecodeBasicCardData(const nsAString& aData,
+                                      nsPIDOMWindowInner* aWindow,
+                                      BasicCardResponse& aResponse)
+{
+  // aWindow can be nullptr
+  bool isBillingAddressPassed = false;
+  nsAutoString country;
+  nsTArray<nsString> addressLine;
+  nsAutoString region;
+  nsAutoString city;
+  nsAutoString dependentLocality;
+  nsAutoString postalCode;
+  nsAutoString sortingCode;
+  nsAutoString languageCode;
+  nsAutoString organization;
+  nsAutoString recipient;
+  nsAutoString phone;
+
+  nsCharSeparatedTokenizer propertyTokenizer(aData, propertySpliter.CharAt(0));
+  while (propertyTokenizer.hasMoreTokens()) {
+    nsDependentSubstring propertyToken = propertyTokenizer.nextToken();
+    nsCharSeparatedTokenizer keyValueTokenizer(propertyToken, keyValueSpliter.CharAt(0));
+    MOZ_ASSERT(keyValueTokenizer.hasMoreTokens());
+    nsDependentSubstring propertyKey = keyValueTokenizer.nextToken();
+    if (mAddressKeys.Contains(propertyKey) && !isBillingAddressPassed) {
+      isBillingAddressPassed = true;
+    }
+
+    if (propertyKey.Equals(cardholderNameKey)) {
+      aResponse.mCardholderName.Construct();
+      aResponse.mCardholderName.Value() = keyValueTokenizer.nextToken();
+      continue;
+    }
+    if (propertyKey.Equals(cardNumberKey)) {
+      aResponse.mCardNumber = keyValueTokenizer.nextToken();
+      continue;
+    }
+    if (propertyKey.Equals(expiryMonthKey)) {
+      aResponse.mExpiryMonth.Construct();
+      aResponse.mExpiryMonth.Value() = keyValueTokenizer.nextToken();
+      continue;
+    }
+    if (propertyKey.Equals(expiryYearKey)) {
+      aResponse.mExpiryYear.Construct();
+      aResponse.mExpiryYear.Value() = keyValueTokenizer.nextToken();
+      continue;
+    }
+    if (propertyKey.Equals(cardSecurityCodeKey)) {
+      aResponse.mCardSecurityCode.Construct();
+      aResponse.mCardSecurityCode.Value() = keyValueTokenizer.nextToken();
+      continue;
+    }
+    if (propertyKey.Equals(countryKey)) {
+      country = keyValueTokenizer.nextToken();
+      continue;
+    }
+    if (propertyKey.Equals(addressLineKey)) {
+      nsDependentSubstring addressLineString = keyValueTokenizer.nextToken();
+      nsCharSeparatedTokenizer addressLineTokenizer(addressLineString,
+                                                    addressLineSpliter.CharAt(0));
+      while (addressLineTokenizer.hasMoreTokens()) {
+        addressLine.AppendElement(addressLineTokenizer.nextToken());
+      }
+      continue;
+    }
+    if (propertyKey.Equals(regionKey)) {
+      region = keyValueTokenizer.nextToken();
+      continue;
+    }
+    if (propertyKey.Equals(cityKey)) {
+      city = keyValueTokenizer.nextToken();
+      continue;
+    }
+    if (propertyKey.Equals(dependentLocalityKey)) {
+      dependentLocality = keyValueTokenizer.nextToken();
+      continue;
+    }
+    if (propertyKey.Equals(postalCodeKey)) {
+      postalCode = keyValueTokenizer.nextToken();
+      continue;
+    }
+    if (propertyKey.Equals(sortingCodeKey)) {
+      sortingCode = keyValueTokenizer.nextToken();
+      continue;
+    }
+    if (propertyKey.Equals(languageCodeKey)) {
+      languageCode = keyValueTokenizer.nextToken();
+      continue;
+    }
+    if (propertyKey.Equals(organizationKey)) {
+      organization = keyValueTokenizer.nextToken();
+      continue;
+    }
+    if (propertyKey.Equals(recipientKey)) {
+      recipient = keyValueTokenizer.nextToken();
+      continue;
+    }
+    if (propertyKey.Equals(phoneKey)) {
+      phone = keyValueTokenizer.nextToken();
+      continue;
+    }
+    return NS_ERROR_FAILURE;
+  }
+  if (isBillingAddressPassed) {
+    aResponse.mBillingAddress.Construct();
+    aResponse.mBillingAddress.Value() = new PaymentAddress(aWindow,
+                                                           country,
+                                                           addressLine,
+                                                           region,
+                                                           city,
+                                                           dependentLocality,
+                                                           postalCode,
+                                                           sortingCode,
+                                                           languageCode,
+                                                           organization,
+                                                           recipient,
+                                                           phone);
+  }
+  return NS_OK;
+}
+
+
+} // end of namespace dom
+} // end of namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/payments/BasicCardPayment.h
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/. */
+
+#ifndef mozilla_dom_BasicCardPayment_h
+#define mozilla_dom_BasicCardPayment_h
+
+#include "mozilla/dom/BasicCardPaymentBinding.h"
+#include "nsPIDOMWindow.h"
+#include "nsIPaymentAddress.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace dom {
+
+class BasicCardService final
+{
+public:
+  NS_INLINE_DECL_REFCOUNTING(BasicCardService)
+
+  static already_AddRefed<BasicCardService> GetService();
+
+  bool IsBasicCardPayment(const nsAString& aSupportedMethods);
+  bool IsValidBasicCardRequest(JSContext* aCx, JSObject* aData, nsAString& aErrorMsg);
+  bool IsValidExpiryMonth(const nsAString& aExpiryMonth);
+  bool IsValidExpiryYear(const nsAString& aExpiryYear);
+
+/*
+  To let BasicCardResponse using the same data type with non-BasicCard response
+  in IPC transferring, following two methods is used to Encode/Decode the raw
+  data of BasicCardResponse.
+*/
+  nsresult EncodeBasicCardData(const nsAString& aCardholderName,
+                               const nsAString& aCardNumber,
+                               const nsAString& aExpiryMonth,
+                               const nsAString& aExpiryYear,
+                               const nsAString& aCardSecurityCode,
+                               nsIPaymentAddress* aBillingAddress,
+                               nsAString& aResult);
+
+  nsresult DecodeBasicCardData(const nsAString& aData,
+                               nsPIDOMWindowInner* aWindow,
+                               BasicCardResponse& aResponse);
+private:
+  BasicCardService();
+  ~BasicCardService() = default;
+
+  // key for basic card data
+  const nsString cardholderNameKey;
+  const nsString cardNumberKey;
+  const nsString expiryMonthKey;
+  const nsString expiryYearKey;
+
+  // key for billing address data
+  const nsString cardSecurityCodeKey;
+  const nsString countryKey;
+  const nsString addressLineKey;
+  const nsString regionKey;
+  const nsString cityKey;
+  const nsString dependentLocalityKey;
+  const nsString postalCodeKey;
+  const nsString sortingCodeKey;
+  const nsString languageCodeKey;
+  const nsString organizationKey;
+  const nsString recipientKey;
+  const nsString phoneKey;
+
+  const nsString propertySpliter;
+  const nsString keyValueSpliter;
+  const nsString addressLineSpliter;
+
+  nsTArray<nsString> mAddressKeys;
+  nsTArray<nsString> mValidNetworks;
+};
+
+} // end of namespace dom
+} // end of namespace mozilla
+
+#endif
--- a/dom/payments/PaymentActionResponse.cpp
+++ b/dom/payments/PaymentActionResponse.cpp
@@ -1,20 +1,129 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "PaymentActionResponse.h"
-#include "nsIRunnable.h"
+#include "PaymentRequestUtils.h"
+#include "BasicCardPayment.h"
 
 namespace mozilla {
 namespace dom {
 
+/* PaymentResponseData */
+
+NS_IMPL_ISUPPORTS(PaymentResponseData, nsIPaymentResponseData)
+
+NS_IMETHODIMP
+PaymentResponseData::GetType(uint32_t* aType)
+{
+  NS_ENSURE_ARG_POINTER(aType);
+  *aType = mType;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentResponseData::Init(const uint32_t aType)
+{
+  if (aType != nsIPaymentResponseData::GENERAL_RESPONSE &&
+      aType != nsIPaymentResponseData::BASICCARD_RESPONSE) {
+    return NS_ERROR_FAILURE;
+  }
+  mType = aType;
+  return NS_OK;
+}
+
+/* GeneralResponseData */
+
+NS_IMPL_ISUPPORTS_INHERITED(GeneralResponseData,
+                            PaymentResponseData,
+                            nsIGeneralResponseData)
+
+GeneralResponseData::GeneralResponseData()
+{
+  Init(nsIPaymentResponseData::GENERAL_RESPONSE);
+}
+
+NS_IMETHODIMP
+GeneralResponseData::GetData(nsAString& aData)
+{
+  aData = mData;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+GeneralResponseData::InitData(JS::HandleValue aValue, JSContext* aCx)
+{
+  if (aValue.isNullOrUndefined()) {
+    return NS_ERROR_FAILURE;
+  }
+  nsresult rv = SerializeFromJSVal(aCx, aValue, mData);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
+}
+
+/* BasicCardResponseData */
+
+NS_IMPL_ISUPPORTS_INHERITED(BasicCardResponseData,
+                            PaymentResponseData,
+                            nsIBasicCardResponseData)
+
+BasicCardResponseData::BasicCardResponseData()
+{
+  Init(nsIPaymentResponseData::BASICCARD_RESPONSE);
+}
+
+NS_IMETHODIMP
+BasicCardResponseData::GetData(nsAString& aData)
+{
+  aData = mData;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BasicCardResponseData::InitData(const nsAString& aCardholderName,
+                                const nsAString& aCardNumber,
+                                const nsAString& aExpiryMonth,
+                                const nsAString& aExpiryYear,
+                                const nsAString& aCardSecurityCode,
+                                nsIPaymentAddress* aBillingAddress)
+{
+  // cardNumber is a required attribute, cannot be empty;
+  if (aCardNumber.IsEmpty()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  RefPtr<BasicCardService> service = BasicCardService::GetService();
+  MOZ_ASSERT(service);
+
+  if (!service->IsValidExpiryMonth(aExpiryMonth)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  if (!service->IsValidExpiryYear(aExpiryYear)) {
+    return NS_ERROR_FAILURE;
+  }
+  nsresult rv = service->EncodeBasicCardData(aCardholderName,
+                                             aCardNumber,
+                                             aExpiryMonth,
+                                             aExpiryYear,
+                                             aCardSecurityCode,
+                                             aBillingAddress,
+                                             mData);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
+}
+
 /* PaymentActionResponse */
 
 NS_IMPL_ISUPPORTS(PaymentActionResponse,
                   nsIPaymentActionResponse)
 
 PaymentActionResponse::PaymentActionResponse()
   : mRequestId(EmptyString())
   , mType(nsIPaymentActionResponse::NO_TYPE)
@@ -116,25 +225,59 @@ PaymentShowActionResponse::GetPayerPhone
   aPayerPhone = mPayerPhone;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PaymentShowActionResponse::Init(const nsAString& aRequestId,
                                 const uint32_t aAcceptStatus,
                                 const nsAString& aMethodName,
-                                const nsAString& aData,
+                                nsIPaymentResponseData* aData,
                                 const nsAString& aPayerName,
                                 const nsAString& aPayerEmail,
                                 const nsAString& aPayerPhone)
 {
+  NS_ENSURE_ARG_POINTER(aData);
   mRequestId = aRequestId;
   mAcceptStatus = aAcceptStatus;
   mMethodName = aMethodName;
-  mData = aData;
+
+  RefPtr<BasicCardService> service = BasicCardService::GetService();
+  MOZ_ASSERT(service);
+  bool isBasicCardPayment = service->IsBasicCardPayment(mMethodName);
+
+  uint32_t responseType;
+  NS_ENSURE_SUCCESS(aData->GetType(&responseType), NS_ERROR_FAILURE);
+  switch (responseType) {
+    case nsIPaymentResponseData::GENERAL_RESPONSE: {
+      if (isBasicCardPayment) {
+        return NS_ERROR_FAILURE;
+      }
+      nsCOMPtr<nsIGeneralResponseData> data = do_QueryInterface(aData);
+      MOZ_ASSERT(data);
+      NS_ENSURE_SUCCESS(data->GetData(mData), NS_ERROR_FAILURE);
+      break;
+    }
+    case nsIPaymentResponseData::BASICCARD_RESPONSE: {
+      if (!isBasicCardPayment) {
+        return NS_ERROR_FAILURE;
+      }
+      nsCOMPtr<nsIBasicCardResponseData> data = do_QueryInterface(aData);
+      MOZ_ASSERT(data);
+      NS_ENSURE_SUCCESS(data->GetData(mData), NS_ERROR_FAILURE);
+      break;
+    }
+    default: {
+      return NS_ERROR_FAILURE;
+    }
+  }
+  if (mData.IsEmpty()) {
+    return NS_ERROR_FAILURE;
+  }
+
   mPayerName = aPayerName;
   mPayerEmail = aPayerEmail;
   mPayerPhone = aPayerPhone;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PaymentShowActionResponse::IsAccepted(bool* aIsAccepted)
--- a/dom/payments/PaymentActionResponse.h
+++ b/dom/payments/PaymentActionResponse.h
@@ -9,16 +9,63 @@
 
 #include "nsIPaymentActionResponse.h"
 
 namespace mozilla {
 namespace dom {
 
 class PaymentRequestParent;
 
+class PaymentResponseData : public nsIPaymentResponseData
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTRESPONSEDATA
+
+  PaymentResponseData() = default;
+
+protected:
+  virtual ~PaymentResponseData() = default;
+
+  uint32_t mType;
+};
+
+class GeneralResponseData final : public PaymentResponseData
+                                , public nsIGeneralResponseData
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_FORWARD_NSIPAYMENTRESPONSEDATA(PaymentResponseData::)
+  NS_DECL_NSIGENERALRESPONSEDATA
+
+  GeneralResponseData();
+
+private:
+  ~GeneralResponseData() = default;
+
+  nsString mData;
+};
+
+class BasicCardResponseData final : public nsIBasicCardResponseData
+                                  , public PaymentResponseData
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_FORWARD_NSIPAYMENTRESPONSEDATA(PaymentResponseData::)
+  NS_DECL_NSIBASICCARDRESPONSEDATA
+
+  BasicCardResponseData();
+
+private:
+  ~BasicCardResponseData() = default;
+
+  nsString mData;
+  nsCOMPtr<nsIPaymentAddress> mBillingAddress;
+};
+
 class PaymentActionResponse : public nsIPaymentActionResponse
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIPAYMENTACTIONRESPONSE
 
   PaymentActionResponse();
 
--- a/dom/payments/PaymentRequest.cpp
+++ b/dom/payments/PaymentRequest.cpp
@@ -2,16 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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/dom/PaymentRequest.h"
 #include "mozilla/dom/PaymentResponse.h"
 #include "nsContentUtils.h"
+#include "BasicCardPayment.h"
 #include "PaymentRequestManager.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(PaymentRequest)
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PaymentRequest,
@@ -55,21 +56,33 @@ PaymentRequest::IsValidMethodData(const 
                                   nsAString& aErrorMsg)
 {
   if (!aMethodData.Length()) {
     aErrorMsg.AssignLiteral("At least one payment method is required.");
     return false;
   }
 
   for (const PaymentMethodData& methodData : aMethodData) {
-    if (!methodData.mSupportedMethods.Length()) {
+    if (methodData.mSupportedMethods.IsEmpty()) {
       aErrorMsg.AssignLiteral(
-        "At least one payment method identifier is required.");
+        "Payment method identifier is required.");
       return false;
     }
+    RefPtr<BasicCardService> service = BasicCardService::GetService();
+    MOZ_ASSERT(service);
+    if (service->IsBasicCardPayment(methodData.mSupportedMethods)) {
+      if (!methodData.mData.WasPassed()) {
+        continue;
+      }
+      if (!service->IsValidBasicCardRequest(nsContentUtils::GetCurrentJSContext(),
+                                            methodData.mData.Value(),
+                                            aErrorMsg)) {
+        return false;
+      }
+    }
   }
 
   return true;
 }
 
 bool
 PaymentRequest::IsValidNumber(const nsAString& aItem,
                               const nsAString& aStr,
--- a/dom/payments/PaymentRequestData.cpp
+++ b/dom/payments/PaymentRequestData.cpp
@@ -39,19 +39,26 @@ PaymentMethodData::Create(const IPCPayme
 NS_IMETHODIMP
 PaymentMethodData::GetSupportedMethods(nsAString& aSupportedMethods)
 {
   aSupportedMethods = mSupportedMethods;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-PaymentMethodData::GetData(nsAString& aData)
+PaymentMethodData::GetData(JSContext* aCx, JS::MutableHandleValue aData)
 {
-  aData = mData;
+  if (mData.IsEmpty()) {
+    aData.set(JS::NullValue());
+    return NS_OK;
+  }
+  nsresult rv = DeserializeToJSValue(mData, aCx ,aData);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
   return NS_OK;
 }
 
 /* PaymentCurrencyAmount */
 
 NS_IMPL_ISUPPORTS(PaymentCurrencyAmount,
                   nsIPaymentCurrencyAmount)
 
@@ -217,19 +224,26 @@ PaymentDetailsModifier::GetAdditionalDis
 {
   NS_ENSURE_ARG_POINTER(aAdditionalDisplayItems);
   nsCOMPtr<nsIArray> additionalItems = mAdditionalDisplayItems;
   additionalItems.forget(aAdditionalDisplayItems);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-PaymentDetailsModifier::GetData(nsAString& aData)
+PaymentDetailsModifier::GetData(JSContext* aCx, JS::MutableHandleValue aData)
 {
-  aData = mData;
+  if (mData.IsEmpty()) {
+    aData.set(JS::NullValue());
+    return NS_OK;
+  }
+  nsresult rv = DeserializeToJSValue(mData, aCx ,aData);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
   return NS_OK;
 }
 
 /* PaymentShippingOption */
 
 NS_IMPL_ISUPPORTS(PaymentShippingOption,
                   nsIPaymentShippingOption)
 
--- a/dom/payments/PaymentRequestModule.cpp
+++ b/dom/payments/PaymentRequestModule.cpp
@@ -5,79 +5,91 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ModuleUtils.h"
 #include "PaymentActionRequest.h"
 #include "PaymentActionResponse.h"
 #include "PaymentRequestData.h"
 #include "PaymentRequestService.h"
 
+using mozilla::dom::GeneralResponseData;
+using mozilla::dom::BasicCardResponseData;
 using mozilla::dom::PaymentActionRequest;
 using mozilla::dom::PaymentCreateActionRequest;
 using mozilla::dom::PaymentCompleteActionRequest;
 using mozilla::dom::PaymentUpdateActionRequest;
 using mozilla::dom::PaymentCanMakeActionResponse;
 using mozilla::dom::PaymentAbortActionResponse;
 using mozilla::dom::PaymentShowActionResponse;
 using mozilla::dom::PaymentCompleteActionResponse;
 using mozilla::dom::payments::PaymentAddress;
 using mozilla::dom::PaymentRequestService;
 
+NS_GENERIC_FACTORY_CONSTRUCTOR(GeneralResponseData)
+NS_GENERIC_FACTORY_CONSTRUCTOR(BasicCardResponseData)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentActionRequest)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCreateActionRequest)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCompleteActionRequest)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentUpdateActionRequest)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCanMakeActionResponse)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentAbortActionResponse)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentShowActionResponse)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCompleteActionResponse)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentAddress)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(PaymentRequestService,
                                          PaymentRequestService::GetSingleton)
 
+NS_DEFINE_NAMED_CID(NS_GENERAL_RESPONSE_DATA_CID);
+NS_DEFINE_NAMED_CID(NS_BASICCARD_RESPONSE_DATA_CID);
 NS_DEFINE_NAMED_CID(NS_PAYMENT_ACTION_REQUEST_CID);
 NS_DEFINE_NAMED_CID(NS_PAYMENT_CREATE_ACTION_REQUEST_CID);
 NS_DEFINE_NAMED_CID(NS_PAYMENT_COMPLETE_ACTION_REQUEST_CID);
 NS_DEFINE_NAMED_CID(NS_PAYMENT_UPDATE_ACTION_REQUEST_CID);
 NS_DEFINE_NAMED_CID(NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CID);
 NS_DEFINE_NAMED_CID(NS_PAYMENT_ABORT_ACTION_RESPONSE_CID);
 NS_DEFINE_NAMED_CID(NS_PAYMENT_SHOW_ACTION_RESPONSE_CID);
 NS_DEFINE_NAMED_CID(NS_PAYMENT_COMPLETE_ACTION_RESPONSE_CID);
 NS_DEFINE_NAMED_CID(NS_PAYMENT_ADDRESS_CID);
 NS_DEFINE_NAMED_CID(NS_PAYMENT_REQUEST_SERVICE_CID);
 
 static const mozilla::Module::CIDEntry kPaymentRequestCIDs[] = {
+  { &kNS_GENERAL_RESPONSE_DATA_CID, false, nullptr, GeneralResponseDataConstructor},
+  { &kNS_BASICCARD_RESPONSE_DATA_CID, false, nullptr, BasicCardResponseDataConstructor},
   { &kNS_PAYMENT_ACTION_REQUEST_CID, false, nullptr, PaymentActionRequestConstructor},
   { &kNS_PAYMENT_CREATE_ACTION_REQUEST_CID, false, nullptr, PaymentCreateActionRequestConstructor},
   { &kNS_PAYMENT_COMPLETE_ACTION_REQUEST_CID, false, nullptr, PaymentCompleteActionRequestConstructor},
   { &kNS_PAYMENT_UPDATE_ACTION_REQUEST_CID, false, nullptr, PaymentUpdateActionRequestConstructor},
   { &kNS_PAYMENT_CANMAKE_ACTION_RESPONSE_CID, false, nullptr, PaymentCanMakeActionResponseConstructor},
   { &kNS_PAYMENT_ABORT_ACTION_RESPONSE_CID, false, nullptr, PaymentAbortActionResponseConstructor},
   { &kNS_PAYMENT_SHOW_ACTION_RESPONSE_CID, false, nullptr, PaymentShowActionResponseConstructor},
   { &kNS_PAYMENT_COMPLETE_ACTION_RESPONSE_CID, false, nullptr, PaymentCompleteActionResponseConstructor},
   { &kNS_PAYMENT_ADDRESS_CID, false, nullptr, PaymentAddressConstructor},
   { &kNS_PAYMENT_REQUEST_SERVICE_CID, true, nullptr, PaymentRequestServiceConstructor },
   { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kPaymentRequestContracts[] = {
+  { NS_GENERAL_RESPONSE_DATA_CONTRACT_ID, &kNS_GENERAL_RESPONSE_DATA_CID },
+  { NS_BASICCARD_RESPONSE_DATA_CONTRACT_ID, &kNS_BASICCARD_RESPONSE_DATA_CID },
   { NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_ACTION_REQUEST_CID },
   { NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_CREATE_ACTION_REQUEST_CID },
   { NS_PAYMENT_COMPLETE_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_COMPLETE_ACTION_REQUEST_CID },
   { NS_PAYMENT_UPDATE_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_UPDATE_ACTION_REQUEST_CID },
   { NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CONTRACT_ID, &kNS_PAYMENT_CANMAKE_ACTION_RESPONSE_CID },
   { NS_PAYMENT_ABORT_ACTION_RESPONSE_CONTRACT_ID, &kNS_PAYMENT_ABORT_ACTION_RESPONSE_CID },
   { NS_PAYMENT_SHOW_ACTION_RESPONSE_CONTRACT_ID, &kNS_PAYMENT_SHOW_ACTION_RESPONSE_CID },
   { NS_PAYMENT_COMPLETE_ACTION_RESPONSE_CONTRACT_ID, &kNS_PAYMENT_COMPLETE_ACTION_RESPONSE_CID },
   { NS_PAYMENT_ADDRESS_CONTRACT_ID, &kNS_PAYMENT_ADDRESS_CID },
   { NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID, &kNS_PAYMENT_REQUEST_SERVICE_CID },
   { nullptr }
 };
 
 static const mozilla::Module::CategoryEntry kPaymentRequestCategories[] = {
+  { "payment-request", "GeneralResponseData", NS_GENERAL_RESPONSE_DATA_CONTRACT_ID },
+  { "payment-request", "BasicCardResponseData", NS_BASICCARD_RESPONSE_DATA_CONTRACT_ID },
   { "payment-request", "PaymentActionRequest", NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID },
   { "payment-request", "PaymentCreateActionRequest", NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID },
   { "payment-request", "PaymentCompleteActionRequest", NS_PAYMENT_COMPLETE_ACTION_REQUEST_CONTRACT_ID },
   { "payment-request", "PaymentUpdateActionRequest", NS_PAYMENT_UPDATE_ACTION_REQUEST_CONTRACT_ID },
   { "payment-request", "PaymentCanMakeActionResponse", NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CONTRACT_ID },
   { "payment-request", "PaymentAbortActionResponse", NS_PAYMENT_ABORT_ACTION_RESPONSE_CONTRACT_ID },
   { "payment-request", "PaymentShowActionResponse", NS_PAYMENT_SHOW_ACTION_RESPONSE_CONTRACT_ID },
   { "payment-request", "PaymentCompleteActionResponse", NS_PAYMENT_COMPLETE_ACTION_RESPONSE_CONTRACT_ID },
--- a/dom/payments/PaymentRequestService.cpp
+++ b/dom/payments/PaymentRequestService.cpp
@@ -2,16 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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/ClearOnShutdown.h"
 #include "PaymentRequestData.h"
 #include "PaymentRequestService.h"
+#include "BasicCardPayment.h"
 
 namespace mozilla {
 namespace dom {
 
 StaticRefPtr<PaymentRequestService> gPaymentService;
 
 namespace {
 
@@ -295,23 +296,42 @@ PaymentRequestService::RequestPayment(ns
         new payments::PaymentRequest(tabId, requestId, methodData, details, options);
 
       if (!mRequestQueue.AppendElement(payment, mozilla::fallible)) {
         return NS_ERROR_OUT_OF_MEMORY;
       }
       break;
     }
     /*
-     *  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
+     *  TODO: 1. Check third party payment app support by traversing all
      *           registered third party payment apps.
      */
-    case nsIPaymentActionRequest::CANMAKE_ACTION:
+    case nsIPaymentActionRequest::CANMAKE_ACTION: {
+      if (IsBasicCardPayment(requestId)) {
+        nsCOMPtr<nsIPaymentCanMakeActionResponse> canMakeResponse =
+          do_CreateInstance(NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CONTRACT_ID);
+        MOZ_ASSERT(canMakeResponse);
+        rv = canMakeResponse->Init(requestId, true);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
+        nsCOMPtr<nsIPaymentActionResponse> response = do_QueryInterface(canMakeResponse);
+        MOZ_ASSERT(response);
+        rv = RespondPayment(response);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
+      } else {
+        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::ABORT_ACTION:
     case nsIPaymentActionRequest::COMPLETE_ACTION: {
       rv = CallTestingUIAction(requestId, type);
       if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -464,10 +484,36 @@ PaymentRequestService::RemoveActionCallb
   nsCOMPtr<nsIPaymentActionCallback> callback;
   if (!mCallbackHashtable.Get(aRequestId, getter_AddRefs(callback))) {
     return NS_ERROR_FAILURE;
   }
   mCallbackHashtable.Remove(aRequestId);
   return NS_OK;
 }
 
+bool
+PaymentRequestService::IsBasicCardPayment(const nsAString& aRequestId)
+{
+  nsCOMPtr<nsIPaymentRequest> payment;
+  nsresult rv = GetPaymentRequestById(aRequestId, getter_AddRefs(payment));
+  NS_ENSURE_SUCCESS(rv, false);
+  nsCOMPtr<nsIArray> methods;
+  rv = payment->GetPaymentMethods(getter_AddRefs(methods));
+  uint32_t length;
+  rv = methods->GetLength(&length);
+  NS_ENSURE_SUCCESS(rv, false);
+  for (uint32_t index = 0; index < length; ++index) {
+    nsCOMPtr<nsIPaymentMethodData> method = do_QueryElementAt(methods, index);
+    MOZ_ASSERT(method);
+    nsAutoString supportedMethods;
+    rv = method->GetSupportedMethods(supportedMethods);
+    NS_ENSURE_SUCCESS(rv, false);
+    RefPtr<BasicCardService> service = BasicCardService::GetService();
+    MOZ_ASSERT(service);
+    if (service->IsBasicCardPayment(supportedMethods)) {
+      return true;
+    }
+  }
+  return false;
+}
+
 } // end of namespace dom
 } // end of namespace mozilla
--- a/dom/payments/PaymentRequestService.h
+++ b/dom/payments/PaymentRequestService.h
@@ -41,16 +41,19 @@ private:
                     nsIPaymentActionCallback* aCallback);
   nsresult
   RemoveActionCallback(const nsAString& aRequestId);
 
   // this method is only used for testing
   nsresult
   CallTestingUIAction(const nsAString& aRequestId, uint32_t aActionType);
 
+  bool
+  IsBasicCardPayment(const nsAString& aRequestId);
+
   FallibleTArray<nsCOMPtr<nsIPaymentRequest>> mRequestQueue;
 
   nsInterfaceHashtable<nsStringHashKey, nsIPaymentActionCallback> mCallbackHashtable;
 
   nsCOMPtr<nsIPaymentUIService> mTestingUIService;
 };
 
 } // end of namespace dom
--- a/dom/payments/PaymentRequestUtils.cpp
+++ b/dom/payments/PaymentRequestUtils.cpp
@@ -19,16 +19,27 @@ SerializeFromJSObject(JSContext* aCx, JS
   if (NS_WARN_IF(!serializer)) {
     return NS_ERROR_FAILURE;
   }
   JS::RootedValue value(aCx, JS::ObjectValue(*aObject));
   return serializer->EncodeFromJSVal(value.address(), aCx, aSerializedObject);
 }
 
 nsresult
+SerializeFromJSVal(JSContext* aCx, JS::HandleValue aValue, nsAString& aSerializedValue)
+{
+  nsCOMPtr<nsIJSON> serializer = do_CreateInstance("@mozilla.org/dom/json;1");
+  if (NS_WARN_IF(!serializer)) {
+    return NS_ERROR_FAILURE;
+  }
+  JS::RootedValue value(aCx, aValue.get());
+  return serializer->EncodeFromJSVal(value.address(), aCx, aSerializedValue);
+}
+
+nsresult
 DeserializeToJSObject(const nsAString& aSerializedObject, JSContext* aCx, JS::MutableHandleObject aObject) {
   nsCOMPtr<nsIJSON> deserializer = do_CreateInstance("@mozilla.org/dom/json;1");
   if (NS_WARN_IF(!deserializer)) {
     return NS_ERROR_FAILURE;
   }
   JS::RootedValue value(aCx);
   JS::MutableHandleValue handleVal(&value);
   nsresult rv = deserializer->DecodeToJSVal(aSerializedObject, aCx, handleVal);
@@ -38,10 +49,23 @@ DeserializeToJSObject(const nsAString& a
   if (value.isObject()) {
     aObject.set(&value.toObject());
   } else {
     aObject.set(nullptr);
   }
   return NS_OK;
 }
 
+nsresult
+DeserializeToJSValue(const nsAString& aSerializedObject, JSContext* aCx, JS::MutableHandleValue aValue) {
+  nsCOMPtr<nsIJSON> deserializer = do_CreateInstance("@mozilla.org/dom/json;1");
+  if (NS_WARN_IF(!deserializer)) {
+    return NS_ERROR_FAILURE;
+  }
+  nsresult rv = deserializer->DecodeToJSVal(aSerializedObject, aCx, aValue);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
+}
+
 } // end of namespace dom
 } // end of namespace mozilla
--- a/dom/payments/PaymentRequestUtils.h
+++ b/dom/payments/PaymentRequestUtils.h
@@ -14,16 +14,26 @@ namespace mozilla {
 namespace dom {
 
 nsresult
 SerializeFromJSObject(JSContext* aCx,
                       JS::HandleObject aObject,
                       nsAString& aSerializedObject);
 
 nsresult
+SerializeFromJSVal(JSContext* aCx,
+                   JS::HandleValue aValue,
+                   nsAString& aSerializedValue);
+
+nsresult
 DeserializeToJSObject(const nsAString& aSerializedObject,
                       JSContext* aCx,
                       JS::MutableHandleObject aObject);
 
+nsresult
+DeserializeToJSValue(const nsAString& aSerializedObject,
+                     JSContext* aCx,
+                     JS::MutableHandleValue aValue);
+
 } // end of namespace dom
 } // end of namespace mozilla
 
 #endif
--- a/dom/payments/PaymentResponse.cpp
+++ b/dom/payments/PaymentResponse.cpp
@@ -1,15 +1,18 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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/dom/PaymentResponse.h"
+#include "mozilla/dom/BasicCardPaymentBinding.h"
+#include "BasicCardPayment.h"
+#include "PaymentAddress.h"
 #include "PaymentRequestUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PaymentResponse, mOwner,
                                       mShippingAddress, mPromise)
 
@@ -68,17 +71,35 @@ void
 PaymentResponse::GetMethodName(nsString& aRetVal) const
 {
   aRetVal = mMethodName;
 }
 
 void
 PaymentResponse::GetDetails(JSContext* aCx, JS::MutableHandle<JSObject*> aRetVal) const
 {
-  DeserializeToJSObject(mDetails, aCx, aRetVal);
+  RefPtr<BasicCardService> service = BasicCardService::GetService();
+  MOZ_ASSERT(service);
+  if (!service->IsBasicCardPayment(mMethodName)) {
+    DeserializeToJSObject(mDetails, aCx, aRetVal);
+  } else {
+    BasicCardResponse response;
+    nsresult rv = service->DecodeBasicCardData(mDetails, mOwner, response);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return;
+    }
+
+    MOZ_ASSERT(aCx);
+    JS::RootedValue value(aCx);
+    JS::MutableHandleValue handleValue(&value);
+    if (NS_WARN_IF(!response.ToObjectInternal(aCx, handleValue))) {
+      return;
+    }
+    aRetVal.set(&handleValue.toObject());
+  }
 }
 
 void
 PaymentResponse::GetShippingOption(nsString& aRetVal) const
 {
   aRetVal = mShippingOption;
 }
 
--- a/dom/payments/moz.build
+++ b/dom/payments/moz.build
@@ -17,16 +17,17 @@ EXPORTS.mozilla.dom += [
     'PaymentAddress.h',
     'PaymentRequest.h',
     'PaymentRequestManager.h',
     'PaymentRequestUpdateEvent.h',
     'PaymentResponse.h',
 ]
 
 UNIFIED_SOURCES += [
+    'BasicCardPayment.cpp',
     'PaymentActionRequest.cpp',
     'PaymentActionResponse.cpp',
     'PaymentAddress.cpp',
     'PaymentRequest.cpp',
     'PaymentRequestData.cpp',
     'PaymentRequestManager.cpp',
     'PaymentRequestModule.cpp',
     'PaymentRequestService.cpp',
new file mode 100644
--- /dev/null
+++ b/dom/webidl/BasicCardPayment.webidl
@@ -0,0 +1,27 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ *
+ * The origin of this WebIDL file is
+ *   https://www.w3.org/TR/payment-request/#paymentrequest-interface
+ */
+enum BasicCardType {
+  "credit",
+  "debit",
+  "prepaid"
+};
+
+dictionary BasicCardRequest {
+  sequence<DOMString> supportedNetworks;
+  sequence<BasicCardType> supportedTypes;
+};
+
+dictionary BasicCardResponse {
+           DOMString cardholderName;
+  required DOMString cardNumber;
+           DOMString expiryMonth;
+           DOMString expiryYear;
+           DOMString cardSecurityCode;
+           PaymentAddress? billingAddress;
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -406,16 +406,17 @@ WEBIDL_FILES = [
     'AudioStreamTrack.webidl',
     'AudioTrack.webidl',
     'AudioTrackList.webidl',
     'AudioWorkletGlobalScope.webidl',
     'AutocompleteInfo.webidl',
     'BarProp.webidl',
     'BaseAudioContext.webidl',
     'BaseKeyframeTypes.webidl',
+    'BasicCardPayment.webidl',
     'BatteryManager.webidl',
     'BeforeUnloadEvent.webidl',
     'BiquadFilterNode.webidl',
     'Blob.webidl',
     'BoxObject.webidl',
     'BroadcastChannel.webidl',
     'BrowserElement.webidl',
     'BrowserElementDictionaries.webidl',