Bug 1497215 - Refactor the IPC structure for PaymentResponse.details r=baku

In original design, payment method response data is passed between processes
    through a simple nsString. It means a special encoder/decoder is needed for
    special response data, ex. BasicCardResponse, to serialize/deserialize
    into/from the nsString. However, when a token spliter, ':', ';' and '@', is
    used in response data, it makes the encoder/decoder can not work normally.
    It is hard to define a suitable token spliter set for encoder/decoder.
    So instead of using an error-prone encoder/decoder, this patch defining a new
    IPC structure for response data.
This commit is contained in:
Eden Chuang 2018-10-22 11:08:04 +02:00
Родитель 6d6827aa74
Коммит 5bf95b80c7
15 изменённых файлов: 493 добавлений и 419 удалений

Просмотреть файл

@ -69,9 +69,34 @@ interface nsIGeneralResponseData : nsIPaymentResponseData
interface nsIBasicCardResponseData : nsIPaymentResponseData
{
/**
* The stringified response data.
* The cardholder name.
*/
readonly attribute AString data;
readonly attribute AString cardholderName;
/**
* The card number.
*/
readonly attribute AString cardNumber;
/**
* The expiry month.
*/
readonly attribute AString expiryMonth;
/**
* The expiry year.
*/
readonly attribute AString expiryYear;
/**
* The card security number.
*/
readonly attribute AString cardSecurityCode;
/**
* The billing address.
*/
readonly attribute nsIPaymentAddress billingAddress;
/**
* The initial method for nsIBasicCardResponseData.
@ -183,7 +208,7 @@ interface nsIPaymentShowActionResponse : nsIPaymentActionResponse
/**
* The data needed by the payment method. (it must be serializable)
*/
readonly attribute AString data;
readonly attribute nsIPaymentResponseData data;
/**
* The payer name information.

Просмотреть файл

@ -14,117 +14,19 @@
namespace mozilla {
namespace dom {
#ifndef PaymentBasicCardMacros
#define PaymentBasicCardMacros
#define AMEX NS_LITERAL_STRING("amex")
#define CARTEBANCAIRE NS_LITERAL_STRING("cartebancaire")
#define DINERS NS_LITERAL_STRING("diners")
#define DISCOVER NS_LITERAL_STRING("discover")
#define JCB NS_LITERAL_STRING("jcb")
#define MASTERCARD NS_LITERAL_STRING("mastercard")
#define MIR NS_LITERAL_STRING("mir")
#define UNIONPAY NS_LITERAL_STRING("unionpay")
#define VISA NS_LITERAL_STRING("visa")
#define CardholderName NS_LITERAL_STRING("cardholderName")
#define CardNumber NS_LITERAL_STRING("cardNumber")
#define ExpiryMonth NS_LITERAL_STRING("expiryMonth")
#define ExpiryYear NS_LITERAL_STRING("expiryYear")
#define CardSecurityCode NS_LITERAL_STRING("cardSecurityCode")
#define Country NS_LITERAL_STRING("country")
#define AddressLine NS_LITERAL_STRING("addressLine")
#define Region NS_LITERAL_STRING("region")
#define RegionCode NS_LITERAL_STRING("regionCode")
#define City NS_LITERAL_STRING("city")
#define DependentLocality NS_LITERAL_STRING("dependentLocality")
#define PostalCode NS_LITERAL_STRING("postalCode")
#define SortingCode NS_LITERAL_STRING("sortingCode")
#define Organization NS_LITERAL_STRING("organization")
#define Recipient NS_LITERAL_STRING("recipient")
#define Phone NS_LITERAL_STRING("phone")
#define PropertySpliter NS_LITERAL_STRING(";")
#define KeyValueSpliter NS_LITERAL_STRING(":")
#define AddressLineSpliter NS_LITERAL_STRING("%")
#define EncodeBasicCardProperty(aPropertyName, aPropertyValue, aResult) \
do { \
if (!(aPropertyValue).IsEmpty()) { \
(aResult) += (aPropertyName) \
+ KeyValueSpliter \
+ (aPropertyValue) \
+ PropertySpliter; \
} \
} while(0)
#define EncodeAddressProperty(aAddress, aPropertyName, aResult) \
do { \
nsAutoString propertyValue; \
NS_ENSURE_SUCCESS((aAddress)->Get##aPropertyName(propertyValue), \
NS_ERROR_FAILURE); \
EncodeBasicCardProperty((aPropertyName) ,propertyValue , (aResult)); \
} while(0)
#define DecodeBasicCardProperty(aPropertyName, aPropertyValue, \
aMatchPropertyName, aResponse) \
do { \
if ((aPropertyName).Equals((aMatchPropertyName))) { \
(aResponse).m##aMatchPropertyName.Construct(); \
(aResponse).m##aMatchPropertyName.Value() = (aPropertyValue); \
} \
} while(0)
#define DecodeAddressProperty(aPropertyName, aPropertyValue, \
aMatchPropertyName, aMatchPropertyValue) \
do { \
if ((aPropertyName).Equals((aMatchPropertyName))) { \
(aMatchPropertyValue) = (aPropertyValue); \
} \
} while(0)
#endif
namespace {
bool IsValidNetwork(const nsAString& aNetwork)
{
return AMEX.Equals(aNetwork) ||
CARTEBANCAIRE.Equals(aNetwork) ||
DINERS.Equals(aNetwork) ||
DISCOVER.Equals(aNetwork) ||
JCB.Equals(aNetwork) ||
MASTERCARD.Equals(aNetwork) ||
MIR.Equals(aNetwork) ||
UNIONPAY.Equals(aNetwork) ||
VISA.Equals(aNetwork);
return aNetwork.Equals(NS_LITERAL_STRING("amex")) ||
aNetwork.Equals(NS_LITERAL_STRING("cartebancaire")) ||
aNetwork.Equals(NS_LITERAL_STRING("diners")) ||
aNetwork.Equals(NS_LITERAL_STRING("discover")) ||
aNetwork.Equals(NS_LITERAL_STRING("jcb")) ||
aNetwork.Equals(NS_LITERAL_STRING("mastercard")) ||
aNetwork.Equals(NS_LITERAL_STRING("mir")) ||
aNetwork.Equals(NS_LITERAL_STRING("unionpay")) ||
aNetwork.Equals(NS_LITERAL_STRING("visa"));
}
bool IsBasicCardKey(const nsAString& aKey)
{
return CardholderName.Equals(aKey) ||
CardNumber.Equals(aKey) ||
ExpiryMonth.Equals(aKey) ||
ExpiryYear.Equals(aKey) ||
CardSecurityCode.Equals(aKey);
}
bool IsAddressKey(const nsAString& aKey)
{
return Country.Equals(aKey) ||
AddressLine.Equals(aKey) ||
Region.Equals(aKey) ||
RegionCode.Equals(aKey) ||
City.Equals(aKey) ||
DependentLocality.Equals(aKey) ||
PostalCode.Equals(aKey) ||
SortingCode.Equals(aKey) ||
Organization.Equals(aKey) ||
Recipient.Equals(aKey) ||
Phone.Equals(aKey);
}
} // end of namespace
@ -223,132 +125,6 @@ BasicCardService::IsValidExpiryYear(const nsAString& aExpiryYear)
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
if (aCardNumber.IsEmpty()) {
return NS_ERROR_FAILURE;
}
EncodeBasicCardProperty(CardholderName, aCardholderName, aResult);
EncodeBasicCardProperty(CardNumber, aCardNumber, aResult);
EncodeBasicCardProperty(ExpiryMonth, aExpiryMonth, aResult);
EncodeBasicCardProperty(ExpiryYear, aExpiryYear, aResult);
EncodeBasicCardProperty(CardSecurityCode, aCardSecurityCode, aResult);
if (!aBillingAddress) {
return NS_OK;
}
EncodeAddressProperty(aBillingAddress, Country, aResult);
nsCOMPtr<nsIArray> addressLine;
NS_ENSURE_SUCCESS(aBillingAddress->GetAddressLine(getter_AddRefs(addressLine)),
NS_ERROR_FAILURE);
uint32_t length;
nsAutoString 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);
nsAutoString addressString;
NS_ENSURE_SUCCESS(address->GetData(addressString), NS_ERROR_FAILURE);
addressLineString += addressString + AddressLineSpliter;
}
EncodeBasicCardProperty(AddressLine ,addressLineString , aResult);
EncodeAddressProperty(aBillingAddress, Region, aResult);
EncodeAddressProperty(aBillingAddress, RegionCode, aResult);
EncodeAddressProperty(aBillingAddress, City, aResult);
EncodeAddressProperty(aBillingAddress, DependentLocality, aResult);
EncodeAddressProperty(aBillingAddress, PostalCode, aResult);
EncodeAddressProperty(aBillingAddress, SortingCode, aResult);
EncodeAddressProperty(aBillingAddress, Organization, aResult);
EncodeAddressProperty(aBillingAddress, Recipient, aResult);
EncodeAddressProperty(aBillingAddress, Phone, aResult);
return NS_OK;
}
nsresult
BasicCardService::DecodeBasicCardData(const nsAString& aData,
nsPIDOMWindowInner* aWindow,
BasicCardResponse& aResponse)
{
// aWindow can be nullptr
bool isBillingAddressPassed = false;
nsTArray<nsString> addressLine;
nsAutoString country;
nsAutoString region;
nsAutoString regionCode;
nsAutoString city;
nsAutoString dependentLocality;
nsAutoString postalCode;
nsAutoString sortingCode;
nsAutoString organization;
nsAutoString recipient;
nsAutoString phone;
nsCharSeparatedTokenizer propertyTokenizer(aData, PropertySpliter.CharAt(0));
while (propertyTokenizer.hasMoreTokens()) {
nsDependentSubstring property = propertyTokenizer.nextToken();
nsCharSeparatedTokenizer keyValueTokenizer(property, KeyValueSpliter.CharAt(0));
MOZ_ASSERT(keyValueTokenizer.hasMoreTokens());
nsDependentSubstring key = keyValueTokenizer.nextToken();
nsDependentSubstring value = keyValueTokenizer.nextToken();
if (IsAddressKey(key) && !isBillingAddressPassed) {
isBillingAddressPassed = true;
}
if (!IsAddressKey(key) && !IsBasicCardKey(key)) {
return NS_ERROR_FAILURE;
}
if (key.Equals(CardNumber)) {
aResponse.mCardNumber = (value);
}
DecodeBasicCardProperty(key, value, CardholderName, aResponse);
DecodeBasicCardProperty(key, value, ExpiryMonth, aResponse);
DecodeBasicCardProperty(key, value, ExpiryYear, aResponse);
DecodeBasicCardProperty(key, value, CardSecurityCode, aResponse);
DecodeAddressProperty(key, value, Country, country);
DecodeAddressProperty(key, value, Region, region);
DecodeAddressProperty(key, value, RegionCode, regionCode);
DecodeAddressProperty(key, value, City, city);
DecodeAddressProperty(key, value, DependentLocality, dependentLocality);
DecodeAddressProperty(key, value, PostalCode, postalCode);
DecodeAddressProperty(key, value, SortingCode, sortingCode);
DecodeAddressProperty(key, value, Organization, organization);
DecodeAddressProperty(key, value, Recipient, recipient);
DecodeAddressProperty(key, value, Phone, phone);
if ((key).Equals(AddressLine)) {
nsCharSeparatedTokenizer addressTokenizer(value, AddressLineSpliter.CharAt(0));
while (addressTokenizer.hasMoreTokens()) {
addressLine.AppendElement(addressTokenizer.nextToken());
}
}
}
if (isBillingAddressPassed) {
aResponse.mBillingAddress.Construct();
aResponse.mBillingAddress.Value() = new PaymentAddress(aWindow,
country,
addressLine,
region,
regionCode,
city,
dependentLocality,
postalCode,
sortingCode,
organization,
recipient,
phone);
}
return NS_OK;
}
bool
BasicCardService::IsValidBasicCardErrors(JSContext* aCx,
JSObject* aData)
@ -361,42 +137,5 @@ BasicCardService::IsValidBasicCardErrors(JSContext* aCx,
BasicCardErrors bcError;
return !bcError.Init(aCx, data);
}
#ifdef PaymentBasicCardMacros
#undef PaymentBasicCardMacros
#undef EncodeBasicCardProperty
#undef EncodeAddressProperty
#undef DecodeBasicCardProperty
#undef DecodeAddressProperty
#undef AMEX
#undef CARTEBANCAIRE
#undef DINERS
#undef DISCOVER
#undef JCB
#undef MASTERCARD
#undef MIR
#undef UNIONPAY
#undef VISA
#undef CardholderName
#undef CardNumber
#undef ExpiryMonth
#undef ExpiryYear
#undef CardSecurityCode
#undef Country
#undef AddressLine
#undef Region
#undef RegionCode
#undef City
#undef DependentLocality
#undef PostalCode
#undef SortingCode
#undef Organization
#undef Recipient
#undef Phone
#undef PropertySpliter
#undef KeyValueSpliter
#undef AddressLineSpliter
#endif
} // end of namespace dom
} // end of namespace mozilla

Просмотреть файл

@ -27,22 +27,6 @@ public:
bool IsValidBasicCardErrors(JSContext* aCx, JSObject* aData);
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() = default;
~BasicCardService() = default;

Просмотреть файл

@ -6,7 +6,6 @@
#include "PaymentActionResponse.h"
#include "PaymentRequestUtils.h"
#include "BasicCardPayment.h"
namespace mozilla {
namespace dom {
@ -78,9 +77,47 @@ BasicCardResponseData::BasicCardResponseData()
}
NS_IMETHODIMP
BasicCardResponseData::GetData(nsAString& aData)
BasicCardResponseData::GetCardholderName(nsAString& aCardholderName)
{
aData = mData;
aCardholderName = mCardholderName;
return NS_OK;
}
NS_IMETHODIMP
BasicCardResponseData::GetCardNumber(nsAString& aCardNumber)
{
aCardNumber = mCardNumber;
return NS_OK;
}
NS_IMETHODIMP
BasicCardResponseData::GetExpiryMonth(nsAString& aExpiryMonth)
{
aExpiryMonth = mExpiryMonth;
return NS_OK;
}
NS_IMETHODIMP
BasicCardResponseData::GetExpiryYear(nsAString& aExpiryYear)
{
aExpiryYear = mExpiryYear;
return NS_OK;
}
NS_IMETHODIMP
BasicCardResponseData::GetCardSecurityCode(nsAString& aCardSecurityCode)
{
aCardSecurityCode = mCardSecurityCode;
return NS_OK;
}
NS_IMETHODIMP
BasicCardResponseData::GetBillingAddress(nsIPaymentAddress** aBillingAddress)
{
NS_ENSURE_ARG_POINTER(aBillingAddress);
nsCOMPtr<nsIPaymentAddress> address;
address = mBillingAddress;
address.forget(aBillingAddress);
return NS_OK;
}
@ -107,16 +144,14 @@ BasicCardResponseData::InitData(const nsAString& aCardholderName,
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;
}
mCardholderName = aCardholderName;
mCardNumber = aCardNumber;
mExpiryMonth = aExpiryMonth;
mExpiryYear = aExpiryYear;
mCardSecurityCode = aCardSecurityCode;
mBillingAddress = aBillingAddress;
return NS_OK;
}
@ -202,9 +237,11 @@ PaymentShowActionResponse::GetMethodName(nsAString& aMethodName)
}
NS_IMETHODIMP
PaymentShowActionResponse::GetData(nsAString& aData)
PaymentShowActionResponse::GetData(nsIPaymentResponseData** aData)
{
aData = mData;
NS_ENSURE_ARG_POINTER(aData);
nsCOMPtr<nsIPaymentResponseData> data = mData;
data.forget(aData);
return NS_OK;
}
@ -258,28 +295,20 @@ PaymentShowActionResponse::Init(const nsAString& aRequestId,
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;
}
}
mData = aData;
mPayerName = aPayerName;
mPayerEmail = aPayerEmail;
mPayerPhone = aPayerPhone;

Просмотреть файл

@ -57,7 +57,11 @@ public:
private:
~BasicCardResponseData() = default;
nsString mData;
nsString mCardholderName;
nsString mCardNumber;
nsString mExpiryMonth;
nsString mExpiryYear;
nsString mCardSecurityCode;
nsCOMPtr<nsIPaymentAddress> mBillingAddress;
};
@ -107,7 +111,7 @@ private:
uint32_t mAcceptStatus;
nsString mMethodName;
nsString mData;
nsCOMPtr<nsIPaymentResponseData> mData;
nsString mPayerName;
nsString mPayerEmail;
nsString mPayerPhone;

Просмотреть файл

@ -797,7 +797,7 @@ PaymentRequest::RejectShowPayment(nsresult aRejectReason)
void
PaymentRequest::RespondShowPayment(const nsAString& aMethodName,
const nsAString& aDetails,
const ResponseData& aDetails,
const nsAString& aPayerName,
const nsAString& aPayerEmail,
const nsAString& aPayerPhone,
@ -888,7 +888,7 @@ PaymentRequest::RespondAbortPayment(bool aSuccess)
if (NS_FAILED(mUpdateError)) {
// Respond show with mUpdateError, set mUpdating to false.
mUpdating = false;
RespondShowPayment(EmptyString(), EmptyString(), EmptyString(),
RespondShowPayment(EmptyString(), ResponseData(), EmptyString(),
EmptyString(), EmptyString(), mUpdateError);
mUpdateError = NS_OK;
return;

Просмотреть файл

@ -23,6 +23,7 @@ class EventHandlerNonNull;
class PaymentAddress;
class PaymentRequestChild;
class PaymentResponse;
class ResponseData;
class PaymentRequest final
: public DOMEventTargetHelper
@ -96,7 +97,7 @@ public:
const Optional<OwningNonNull<Promise>>& detailsPromise,
ErrorResult& aRv);
void RespondShowPayment(const nsAString& aMethodName,
const nsAString& aDetails,
const ResponseData& aDetails,
const nsAString& aPayerName,
const nsAString& aPayerEmail,
const nsAString& aPayerPhone,

Просмотреть файл

@ -249,6 +249,74 @@ ConvertOptions(const PaymentOptions& aOptions,
aOptions.mRequestShipping,
shippingType);
}
nsresult
ConvertResponseData(nsPIDOMWindowInner* aWindow,
const IPCPaymentResponseData& aIPCResponseData,
ResponseData& aResponseData)
{
NS_ENSURE_ARG_POINTER(aWindow);
switch(aIPCResponseData.type()) {
case IPCPaymentResponseData::TIPCGeneralResponse: {
const IPCGeneralResponse& rawData = aIPCResponseData;
aResponseData.Init(rawData.data());
break;
}
case IPCPaymentResponseData::TIPCBasicCardResponse: {
const IPCBasicCardResponse& rawData = aIPCResponseData;
BasicCardResponse basicCardResponse;
if (!rawData.cardholderName().IsEmpty()) {
basicCardResponse.mCardholderName.Construct();
basicCardResponse.mCardholderName.Value() = rawData.cardholderName();
}
basicCardResponse.mCardNumber = rawData.cardNumber();
if (!rawData.expiryMonth().IsEmpty()) {
basicCardResponse.mExpiryMonth.Construct();
basicCardResponse.mExpiryMonth.Value() = rawData.expiryMonth();
}
if (!rawData.expiryYear().IsEmpty()) {
basicCardResponse.mExpiryYear.Construct();
basicCardResponse.mExpiryYear.Value() = rawData.expiryYear();
}
if (!rawData.cardSecurityCode().IsEmpty()) {
basicCardResponse.mCardSecurityCode.Construct();
basicCardResponse.mCardSecurityCode.Value() = rawData.cardSecurityCode();
}
if (!rawData.billingAddress().country().IsEmpty() ||
!rawData.billingAddress().addressLine().IsEmpty() ||
!rawData.billingAddress().region().IsEmpty() ||
!rawData.billingAddress().regionCode().IsEmpty() ||
!rawData.billingAddress().city().IsEmpty() ||
!rawData.billingAddress().dependentLocality().IsEmpty() ||
!rawData.billingAddress().postalCode().IsEmpty() ||
!rawData.billingAddress().sortingCode().IsEmpty() ||
!rawData.billingAddress().organization().IsEmpty() ||
!rawData.billingAddress().recipient().IsEmpty() ||
!rawData.billingAddress().phone().IsEmpty()) {
basicCardResponse.mBillingAddress.Construct();
basicCardResponse.mBillingAddress.Value() =
new PaymentAddress(aWindow,
rawData.billingAddress().country(),
rawData.billingAddress().addressLine(),
rawData.billingAddress().region(),
rawData.billingAddress().regionCode(),
rawData.billingAddress().city(),
rawData.billingAddress().dependentLocality(),
rawData.billingAddress().postalCode(),
rawData.billingAddress().sortingCode(),
rawData.billingAddress().organization(),
rawData.billingAddress().recipient(),
rawData.billingAddress().phone());
}
aResponseData.Init(basicCardResponse);
break;
}
default: {
return NS_ERROR_FAILURE;
}
}
return NS_OK;
}
} // end of namespace
/* PaymentRequestManager */
@ -589,9 +657,14 @@ PaymentRequestManager::RespondPayment(PaymentRequest* aRequest,
case IPCPaymentActionResponse::TIPCPaymentShowActionResponse: {
const IPCPaymentShowActionResponse& response = aResponse;
nsresult rejectedReason = NS_ERROR_DOM_ABORT_ERR;
ResponseData responseData;
switch (response.status()) {
case nsIPaymentActionResponse::PAYMENT_ACCEPTED: {
rejectedReason = NS_OK;
NS_ENSURE_SUCCESS(ConvertResponseData(aRequest->GetOwner(),
response.data(),
responseData),
NS_ERROR_FAILURE);
break;
}
case nsIPaymentActionResponse::PAYMENT_REJECTED: {
@ -608,7 +681,7 @@ PaymentRequestManager::RespondPayment(PaymentRequest* aRequest,
}
}
aRequest->RespondShowPayment(response.methodName(),
response.data(),
responseData,
response.payerName(),
response.payerEmail(),
response.payerPhone(),

Просмотреть файл

@ -16,6 +16,50 @@
namespace mozilla {
namespace dom {
ResponseData::ResponseData()
: mType(ResponseData::UNKNOWN)
{
}
void
ResponseData::GetData(JSContext* aCx, JS::MutableHandle<JSObject*> aRetVal) const
{
switch (mType) {
case ResponseData::GENERAL_RESPONSE : {
DeserializeToJSObject(mGeneralResponse, aCx, aRetVal);
break;
}
case ResponseData::BASICCARD_RESPONSE : {
MOZ_ASSERT(aCx);
JS::RootedValue value(aCx);
if (NS_WARN_IF(!mBasicCardResponse.ToObjectInternal(aCx, &value))) {
return;
}
aRetVal.set(&value.toObject());
break;
}
default : {
break;
}
}
}
void
ResponseData::Init(const nsString& aGeneralResponse)
{
mType = ResponseData::GENERAL_RESPONSE;
mGeneralResponse = aGeneralResponse;
mBasicCardResponse = BasicCardResponse();
}
void
ResponseData::Init(const BasicCardResponse& aBasicCardResponse)
{
mType = ResponseData::BASICCARD_RESPONSE;
mBasicCardResponse = aBasicCardResponse;
mGeneralResponse = EmptyString();
}
NS_IMPL_CYCLE_COLLECTION_CLASS(PaymentResponse)
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PaymentResponse,
@ -51,7 +95,7 @@ PaymentResponse::PaymentResponse(nsPIDOMWindowInner* aWindow,
const nsAString& aMethodName,
const nsAString& aShippingOption,
PaymentAddress* aShippingAddress,
const nsAString& aDetails,
const ResponseData& aDetails,
const nsAString& aPayerName,
const nsAString& aPayerEmail,
const nsAString& aPayerPhone)
@ -101,24 +145,7 @@ void
PaymentResponse::GetDetails(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetVal) const
{
RefPtr<BasicCardService> service = BasicCardService::GetService();
MOZ_ASSERT(service);
if (!service->IsBasicCardPayment(mMethodName)) {
DeserializeToJSObject(mDetails, aCx, aRetVal);
} else {
BasicCardResponse response;
nsresult rv = service->DecodeBasicCardData(mDetails, GetOwner(), response);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
MOZ_ASSERT(aCx);
JS::RootedValue value(aCx);
if (NS_WARN_IF(!response.ToObjectInternal(aCx, &value))) {
return;
}
aRetVal.set(&value.toObject());
}
mDetails.GetData(aCx, aRetVal);
}
void
@ -275,7 +302,7 @@ void
PaymentResponse::RespondRetry(const nsAString& aMethodName,
const nsAString& aShippingOption,
PaymentAddress* aShippingAddress,
const nsAString& aDetails,
const ResponseData& aDetails,
const nsAString& aPayerName,
const nsAString& aPayerEmail,
const nsAString& aPayerPhone)

Просмотреть файл

@ -8,6 +8,7 @@
#define mozilla_dom_PaymentResponse_h
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/dom/BasicCardPaymentBinding.h"
#include "mozilla/dom/PaymentResponseBinding.h" // PaymentComplete
#include "nsPIDOMWindow.h"
#include "nsITimer.h"
@ -19,6 +20,30 @@ class PaymentAddress;
class PaymentRequest;
class Promise;
class ResponseData final
{
public:
enum TYPE {
UNKNOWN = 0,
GENERAL_RESPONSE,
BASICCARD_RESPONSE,
};
ResponseData();
~ResponseData() = default;
const TYPE& GetType() const { return mType; }
void GetData(JSContext* aCx, JS::MutableHandle<JSObject*> aRetVal) const;
void Init(const nsString& aGeneralResponse);
void Init(const BasicCardResponse& aBasicCardResponse);
private:
TYPE mType;
nsString mGeneralResponse;
BasicCardResponse mBasicCardResponse;
};
class PaymentResponse final
: public DOMEventTargetHelper
, public nsITimerCallback
@ -37,7 +62,7 @@ public:
const nsAString& aMethodName,
const nsAString& aShippingOption,
PaymentAddress* aShippingAddress,
const nsAString& aDetails,
const ResponseData& aDetails,
const nsAString& aPayerName,
const nsAString& aPayerEmail,
const nsAString& aPayerPhone);
@ -80,7 +105,7 @@ public:
void RespondRetry(const nsAString& aMethodName,
const nsAString& aShippingOption,
PaymentAddress* aShippingAddress,
const nsAString& aDetails,
const ResponseData& aDetails,
const nsAString& aPayerName,
const nsAString& aPayerEmail,
const nsAString& aPayerPhone);
@ -103,7 +128,7 @@ private:
PaymentRequest* mRequest;
nsString mRequestId;
nsString mMethodName;
nsString mDetails;
ResponseData mDetails;
nsString mShippingOption;
nsString mPayerName;
nsString mPayerEmail;

Просмотреть файл

@ -138,12 +138,48 @@ struct IPCPaymentCanMakeActionResponse
bool result;
};
struct IPCPaymentAddress
{
nsString country;
nsString[] addressLine;
nsString region;
nsString regionCode;
nsString city;
nsString dependentLocality;
nsString postalCode;
nsString sortingCode;
nsString organization;
nsString recipient;
nsString phone;
};
struct IPCGeneralResponse
{
nsString data;
};
struct IPCBasicCardResponse
{
nsString cardholderName;
nsString cardNumber;
nsString expiryMonth;
nsString expiryYear;
nsString cardSecurityCode;
IPCPaymentAddress billingAddress;
};
union IPCPaymentResponseData
{
IPCGeneralResponse;
IPCBasicCardResponse;
};
struct IPCPaymentShowActionResponse
{
nsString requestId;
uint32_t status;
nsString methodName;
nsString data;
IPCPaymentResponseData data;
nsString payerName;
nsString payerEmail;
nsString payerPhone;
@ -169,21 +205,6 @@ union IPCPaymentActionResponse
IPCPaymentCompleteActionResponse;
};
struct IPCPaymentAddress
{
nsString country;
nsString[] addressLine;
nsString region;
nsString regionCode;
nsString city;
nsString dependentLocality;
nsString postalCode;
nsString sortingCode;
nsString organization;
nsString recipient;
nsString phone;
};
sync protocol PPaymentRequest
{
manager PBrowser;

Просмотреть файл

@ -138,8 +138,17 @@ PaymentRequestParent::RespondPayment(nsIPaymentActionResponse* aResponse)
NS_ENSURE_SUCCESS(response->GetAcceptStatus(&acceptStatus), NS_ERROR_FAILURE);
nsAutoString methodName;
NS_ENSURE_SUCCESS(response->GetMethodName(methodName), NS_ERROR_FAILURE);
nsAutoString data;
NS_ENSURE_SUCCESS(response->GetData(data), NS_ERROR_FAILURE);
IPCPaymentResponseData ipcData;
if (acceptStatus == nsIPaymentActionResponse::PAYMENT_ACCEPTED) {
nsCOMPtr<nsIPaymentResponseData> data;
NS_ENSURE_SUCCESS(response->GetData(getter_AddRefs(data)),
NS_ERROR_FAILURE);
MOZ_ASSERT(data);
NS_ENSURE_SUCCESS(SerializeResponseData(ipcData, data), NS_ERROR_FAILURE);
} else {
ipcData = IPCGeneralResponse();
}
nsAutoString payerName;
NS_ENSURE_SUCCESS(response->GetPayerName(payerName), NS_ERROR_FAILURE);
nsAutoString payerEmail;
@ -149,7 +158,7 @@ PaymentRequestParent::RespondPayment(nsIPaymentActionResponse* aResponse)
IPCPaymentShowActionResponse actionResponse(requestId,
acceptStatus,
methodName,
data,
ipcData,
payerName,
payerEmail,
payerPhone);
@ -209,67 +218,11 @@ PaymentRequestParent::ChangeShippingAddress(const nsAString& aRequestId,
if (!mActorAlive) {
return NS_ERROR_FAILURE;
}
nsAutoString country;
nsresult rv = aAddress->GetCountry(country);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIArray> iaddressLine;
rv = aAddress->GetAddressLine(getter_AddRefs(iaddressLine));
IPCPaymentAddress ipcAddress;
nsresult rv = SerializeAddress(ipcAddress, aAddress);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString region;
rv = aAddress->GetRegion(region);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString regionCode;
rv = aAddress->GetRegionCode(regionCode);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString city;
rv = aAddress->GetCity(city);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString dependentLocality;
rv = aAddress->GetDependentLocality(dependentLocality);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString postalCode;
rv = aAddress->GetPostalCode(postalCode);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString sortingCode;
rv = aAddress->GetSortingCode(sortingCode);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString organization;
rv = aAddress->GetOrganization(organization);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString recipient;
rv = aAddress->GetRecipient(recipient);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString phone;
rv = aAddress->GetPhone(phone);
NS_ENSURE_SUCCESS(rv, rv);
nsTArray<nsString> addressLine;
uint32_t length;
rv = iaddressLine->GetLength(&length);
NS_ENSURE_SUCCESS(rv, rv);
for (uint32_t index = 0; index < length; ++index) {
nsCOMPtr<nsISupportsString> iaddress = do_QueryElementAt(iaddressLine, index);
MOZ_ASSERT(iaddress);
nsAutoString address;
rv = iaddress->GetData(address);
NS_ENSURE_SUCCESS(rv, rv);
addressLine.AppendElement(address);
}
IPCPaymentAddress ipcAddress(country, addressLine, region, regionCode, city,
dependentLocality, postalCode, sortingCode,
organization, recipient, phone);
nsAutoString requestId(aRequestId);
if (!SendChangeShippingAddress(requestId, ipcAddress)) {
return NS_ERROR_FAILURE;
@ -360,5 +313,122 @@ PaymentRequestParent::ActorDestroy(ActorDestroyReason aWhy)
rowRequest->SetIPC(nullptr);
}
}
nsresult
PaymentRequestParent::SerializeAddress(IPCPaymentAddress& aIPCAddress,
nsIPaymentAddress* aAddress)
{
// address can be nullptr
if (!aAddress) {
return NS_OK;
}
nsAutoString country;
nsresult rv = aAddress->GetCountry(country);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIArray> iaddressLine;
rv = aAddress->GetAddressLine(getter_AddRefs(iaddressLine));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString region;
rv = aAddress->GetRegion(region);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString regionCode;
rv = aAddress->GetRegionCode(regionCode);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString city;
rv = aAddress->GetCity(city);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString dependentLocality;
rv = aAddress->GetDependentLocality(dependentLocality);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString postalCode;
rv = aAddress->GetPostalCode(postalCode);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString sortingCode;
rv = aAddress->GetSortingCode(sortingCode);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString organization;
rv = aAddress->GetOrganization(organization);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString recipient;
rv = aAddress->GetRecipient(recipient);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString phone;
rv = aAddress->GetPhone(phone);
NS_ENSURE_SUCCESS(rv, rv);
nsTArray<nsString> addressLine;
uint32_t length;
rv = iaddressLine->GetLength(&length);
NS_ENSURE_SUCCESS(rv, rv);
for (uint32_t index = 0; index < length; ++index) {
nsCOMPtr<nsISupportsString> iaddress = do_QueryElementAt(iaddressLine, index);
MOZ_ASSERT(iaddress);
nsAutoString address;
rv = iaddress->GetData(address);
NS_ENSURE_SUCCESS(rv, rv);
addressLine.AppendElement(address);
}
aIPCAddress = IPCPaymentAddress(country, addressLine, region, regionCode, city,
dependentLocality, postalCode, sortingCode,
organization, recipient, phone);
return NS_OK;
}
nsresult
PaymentRequestParent::SerializeResponseData(IPCPaymentResponseData& aIPCData,
nsIPaymentResponseData* aData)
{
NS_ENSURE_ARG_POINTER(aData);
uint32_t dataType;
NS_ENSURE_SUCCESS(aData->GetType(&dataType), NS_ERROR_FAILURE);
switch(dataType) {
case nsIPaymentResponseData::GENERAL_RESPONSE: {
nsCOMPtr<nsIGeneralResponseData> response = do_QueryInterface(aData);
MOZ_ASSERT(response);
IPCGeneralResponse data;
NS_ENSURE_SUCCESS(response->GetData(data.data()), NS_ERROR_FAILURE);
aIPCData = data;
break;
}
case nsIPaymentResponseData::BASICCARD_RESPONSE: {
nsCOMPtr<nsIBasicCardResponseData> response = do_QueryInterface(aData);
MOZ_ASSERT(response);
IPCBasicCardResponse data;
NS_ENSURE_SUCCESS(response->GetCardholderName(data.cardholderName()),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(response->GetCardNumber(data.cardNumber()),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(response->GetExpiryMonth(data.expiryMonth()),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(response->GetExpiryYear(data.expiryYear()),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(response->GetCardSecurityCode(data.cardSecurityCode()),
NS_ERROR_FAILURE);
nsCOMPtr<nsIPaymentAddress> address;
NS_ENSURE_SUCCESS(response->GetBillingAddress(getter_AddRefs(address)),
NS_ERROR_FAILURE);
IPCPaymentAddress ipcAddress;
NS_ENSURE_SUCCESS(SerializeAddress(ipcAddress, address), NS_ERROR_FAILURE);
data.billingAddress() = ipcAddress;
aIPCData = data;
break;
}
default: {
return NS_ERROR_FAILURE;
}
}
return NS_OK;
}
} // end of namespace dom
} // end of namespace mozilla

Просмотреть файл

@ -41,6 +41,11 @@ protected:
private:
~PaymentRequestParent() = default;
nsresult SerializeAddress(IPCPaymentAddress& ipcAddress,
nsIPaymentAddress* aAddress);
nsresult SerializeResponseData(IPCPaymentResponseData& ipcData,
nsIPaymentResponseData* aData);
bool mActorAlive;
uint64_t mTabId;
nsString mRequestId;

Просмотреть файл

@ -29,6 +29,24 @@ billingAddress.init("USA", // country
"Bill A. Pacheco", // recipient
"+14344413879"); // phone
const specialAddress = Cc["@mozilla.org/dom/payments/payment-address;1"].
createInstance(Ci.nsIPaymentAddress);
const specialAddressLine = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
const specialData = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
specialData.data = ":$%@&*";
specialAddressLine.appendElement(specialData);
specialAddress.init("USA", // country
specialAddressLine, // address line
"CA", // region
"CA", // region code
"San Bruno", // city
"", // dependent locality
"94066", // postal code
"123456", // sorting code
"", // organization
"Bill A. Pacheco", // recipient
"+14344413879"); // phone
const basiccardResponseData = Cc["@mozilla.org/dom/payments/basiccard-response-data;1"].
createInstance(Ci.nsIBasicCardResponseData);
@ -109,6 +127,36 @@ const simpleResponseUI = {
QueryInterface: ChromeUtils.generateQI([Ci.nsIPaymentUIService]),
};
const specialAddressUI = {
showPayment: function(requestId) {
try {
basiccardResponseData.initData("Bill A. Pacheco", // cardholderName
"4916855166538720", // cardNumber
"01", // expiryMonth
"2024", // expiryYear
"180", // cardSecurityCode
specialAddress); // billingAddress
} catch (e) {
emitTestFail("Fail to initialize basic card response data.");
}
showResponse.init(requestId,
Ci.nsIPaymentActionResponse.PAYMENT_ACCEPTED,
"basic-card", // payment method
basiccardResponseData,// payment method data
"Bill A. Pacheco", // payer name
"", // payer email
""); // payer phone
paymentSrv.respondPayment(showResponse.QueryInterface(Ci.nsIPaymentActionResponse));
},
abortPayment: abortPaymentResponse,
completePayment: completePaymentResponse,
updatePayment: function(requestId) {
},
closePayment: function (requestId) {
},
QueryInterface: ChromeUtils.generateQI([Ci.nsIPaymentUIService]),
};
addMessageListener("set-detailed-ui-service", function() {
paymentSrv.setTestingUIService(detailedResponseUI.QueryInterface(Ci.nsIPaymentUIService));
});
@ -117,6 +165,10 @@ addMessageListener("set-simple-ui-service", function() {
paymentSrv.setTestingUIService(simpleResponseUI.QueryInterface(Ci.nsIPaymentUIService));
});
addMessageListener("set-special-address-ui-service", function() {
paymentSrv.setTestingUIService(specialAddressUI.QueryInterface(Ci.nsIPaymentUIService));
});
addMessageListener("error-response-test", function() {
// test empty cardNumber
try {

Просмотреть файл

@ -241,6 +241,24 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1375345
});
}
function testSpecialAddressResponse() {
const handler = SpecialPowers.getDOMWindowUtils(window).setHandlingUserInput(true);
gScript.sendAsyncMessage("set-special-address-ui-service");
return new Promise((resolve, reject) => {
const payRequest = new PaymentRequest(defaultMethods, defaultDetails, defaultOptions);
payRequest.show().then(response => {
ok(response.details, "BasiccardResponse should exist.");
ok(response.details.billingAddress,
"BasiccardResponse.billingAddress should exist.");
is(response.details.billingAddress.addressLine[0], ":$%@&*",
"AddressLine should be ':$%@&*'");
response.complete("success").then(()=>{
resolve();
});
}).finally(handler.destruct);
});
}
function testBasicCardErrorResponse() {
return new Promise((resolve, reject) => {
gScript.addMessageListener("error-response-complete",
@ -272,6 +290,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1375345
.then(testCanMakePaymentWithBasicCardRequest)
.then(testBasicCardSimpleResponse)
.then(testBasicCardDetailedResponse)
.then(testSpecialAddressResponse)
.then(testBasicCardErrorResponse)
.then(teardown)
.catch( e => {