Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/ipc/InputStreamUtils.h"
#include "nsArrayUtils.h"
#include "nsCOMPtr.h"
#include "nsIPaymentRequestService.h"
#include "nsISupportsPrimitives.h"
#include "nsServiceManagerUtils.h"
#include "PaymentRequestData.h"
#include "PaymentRequestParent.h"
#include "PaymentRequestService.h"
namespace mozilla::dom {
PaymentRequestParent::PaymentRequestParent()
: mActorAlive(true), mRequestId(u""_ns) {}
mozilla::ipc::IPCResult PaymentRequestParent::RecvRequestPayment(
const IPCPaymentActionRequest& aRequest) {
if (!mActorAlive) {
return IPC_FAIL_NO_REASON(this);
}
switch (aRequest.type()) {
case IPCPaymentActionRequest::TIPCPaymentCreateActionRequest: {
const IPCPaymentCreateActionRequest& request = aRequest;
mRequestId = request.requestId();
break;
}
case IPCPaymentActionRequest::TIPCPaymentCanMakeActionRequest: {
const IPCPaymentCanMakeActionRequest& request = aRequest;
mRequestId = request.requestId();
break;
}
case IPCPaymentActionRequest::TIPCPaymentShowActionRequest: {
const IPCPaymentShowActionRequest& request = aRequest;
mRequestId = request.requestId();
break;
}
case IPCPaymentActionRequest::TIPCPaymentAbortActionRequest: {
const IPCPaymentAbortActionRequest& request = aRequest;
mRequestId = request.requestId();
break;
}
case IPCPaymentActionRequest::TIPCPaymentCompleteActionRequest: {
const IPCPaymentCompleteActionRequest& request = aRequest;
mRequestId = request.requestId();
break;
}
case IPCPaymentActionRequest::TIPCPaymentUpdateActionRequest: {
const IPCPaymentUpdateActionRequest& request = aRequest;
mRequestId = request.requestId();
break;
}
case IPCPaymentActionRequest::TIPCPaymentCloseActionRequest: {
const IPCPaymentCloseActionRequest& request = aRequest;
mRequestId = request.requestId();
break;
}
case IPCPaymentActionRequest::TIPCPaymentRetryActionRequest: {
const IPCPaymentRetryActionRequest& request = aRequest;
mRequestId = request.requestId();
break;
}
default: {
return IPC_FAIL(this, "Unknown PaymentRequest action type");
}
}
nsCOMPtr<nsIPaymentRequestService> service =
do_GetService(NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID);
MOZ_ASSERT(service);
PaymentRequestService* rowService =
static_cast<PaymentRequestService*>(service.get());
MOZ_ASSERT(rowService);
nsresult rv = rowService->RequestPayment(mRequestId, aRequest, this);
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_FAIL(this, "nsIPaymentRequestService::RequestPayment failed");
}
return IPC_OK();
}
nsresult PaymentRequestParent::RespondPayment(
nsIPaymentActionResponse* aResponse) {
if (!NS_IsMainThread()) {
RefPtr<PaymentRequestParent> self = this;
nsCOMPtr<nsIPaymentActionResponse> response = aResponse;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
"PaymentRequestParent::RespondPayment",
[self, response]() { self->RespondPayment(response); });
return NS_DispatchToMainThread(r);
}
if (!mActorAlive) {
return NS_ERROR_FAILURE;
}
uint32_t type;
nsresult rv = aResponse->GetType(&type);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString requestId;
rv = aResponse->GetRequestId(requestId);
NS_ENSURE_SUCCESS(rv, rv);
switch (type) {
case nsIPaymentActionResponse::CANMAKE_ACTION: {
nsCOMPtr<nsIPaymentCanMakeActionResponse> response =
do_QueryInterface(aResponse);
MOZ_ASSERT(response);
bool result;
rv = response->GetResult(&result);
NS_ENSURE_SUCCESS(rv, rv);
IPCPaymentCanMakeActionResponse actionResponse(requestId, result);
if (!SendRespondPayment(actionResponse)) {
return NS_ERROR_FAILURE;
}
break;
}
case nsIPaymentActionResponse::SHOW_ACTION: {
nsCOMPtr<nsIPaymentShowActionResponse> response =
do_QueryInterface(aResponse);
MOZ_ASSERT(response);
uint32_t acceptStatus;
NS_ENSURE_SUCCESS(response->GetAcceptStatus(&acceptStatus),
NS_ERROR_FAILURE);
nsAutoString methodName;
NS_ENSURE_SUCCESS(response->GetMethodName(methodName), 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;
NS_ENSURE_SUCCESS(response->GetPayerEmail(payerEmail), NS_ERROR_FAILURE);
nsAutoString payerPhone;
NS_ENSURE_SUCCESS(response->GetPayerPhone(payerPhone), NS_ERROR_FAILURE);
IPCPaymentShowActionResponse actionResponse(
requestId, acceptStatus, methodName, ipcData, payerName, payerEmail,
payerPhone);
if (!SendRespondPayment(actionResponse)) {
return NS_ERROR_FAILURE;
}
break;
}
case nsIPaymentActionResponse::ABORT_ACTION: {
nsCOMPtr<nsIPaymentAbortActionResponse> response =
do_QueryInterface(aResponse);
MOZ_ASSERT(response);
bool isSucceeded;
rv = response->IsSucceeded(&isSucceeded);
NS_ENSURE_SUCCESS(rv, rv);
IPCPaymentAbortActionResponse actionResponse(requestId, isSucceeded);
if (!SendRespondPayment(actionResponse)) {
return NS_ERROR_FAILURE;
}
break;
}
case nsIPaymentActionResponse::COMPLETE_ACTION: {
nsCOMPtr<nsIPaymentCompleteActionResponse> response =
do_QueryInterface(aResponse);
MOZ_ASSERT(response);
bool isCompleted;
rv = response->IsCompleted(&isCompleted);
NS_ENSURE_SUCCESS(rv, rv);
IPCPaymentCompleteActionResponse actionResponse(requestId, isCompleted);
if (!SendRespondPayment(actionResponse)) {
return NS_ERROR_FAILURE;
}
break;
}
default: {
return NS_ERROR_FAILURE;
}
}
return NS_OK;
}
nsresult PaymentRequestParent::ChangeShippingAddress(
const nsAString& aRequestId, nsIPaymentAddress* aAddress) {
if (!NS_IsMainThread()) {
RefPtr<PaymentRequestParent> self = this;
nsCOMPtr<nsIPaymentAddress> address = aAddress;
nsAutoString requestId(aRequestId);
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
"dom::PaymentRequestParent::ChangeShippingAddress",
[self, requestId, address]() {
self->ChangeShippingAddress(requestId, address);
});
return NS_DispatchToMainThread(r);
}
if (!mActorAlive) {
return NS_ERROR_FAILURE;
}
IPCPaymentAddress ipcAddress;
nsresult rv = SerializeAddress(ipcAddress, aAddress);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString requestId(aRequestId);
if (!SendChangeShippingAddress(requestId, ipcAddress)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult PaymentRequestParent::ChangeShippingOption(const nsAString& aRequestId,
const nsAString& aOption) {
if (!NS_IsMainThread()) {
RefPtr<PaymentRequestParent> self = this;
nsAutoString requestId(aRequestId);
nsAutoString option(aOption);
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
"dom::PaymentRequestParent::ChangeShippingOption",
[self, requestId, option]() {
self->ChangeShippingOption(requestId, option);
});
return NS_DispatchToMainThread(r);
}
if (!mActorAlive) {
return NS_ERROR_FAILURE;
}
nsAutoString requestId(aRequestId);
nsAutoString option(aOption);
if (!SendChangeShippingOption(requestId, option)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult PaymentRequestParent::ChangePayerDetail(const nsAString& aRequestId,
const nsAString& aPayerName,
const nsAString& aPayerEmail,
const nsAString& aPayerPhone) {
nsAutoString requestId(aRequestId);
nsAutoString payerName(aPayerName);
nsAutoString payerEmail(aPayerEmail);
nsAutoString payerPhone(aPayerPhone);
if (!NS_IsMainThread()) {
RefPtr<PaymentRequestParent> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
"dom::PaymentRequestParent::ChangePayerDetail",
[self, requestId, payerName, payerEmail, payerPhone]() {
self->ChangePayerDetail(requestId, payerName, payerEmail, payerPhone);
});
return NS_DispatchToMainThread(r);
}
if (!mActorAlive) {
return NS_ERROR_FAILURE;
}
if (!SendChangePayerDetail(requestId, payerName, payerEmail, payerPhone)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult PaymentRequestParent::ChangePaymentMethod(
const nsAString& aRequestId, const nsAString& aMethodName,
nsIMethodChangeDetails* aMethodDetails) {
nsAutoString requestId(aRequestId);
nsAutoString methodName(aMethodName);
nsCOMPtr<nsIMethodChangeDetails> methodDetails(aMethodDetails);
if (!NS_IsMainThread()) {
RefPtr<PaymentRequestParent> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
"dom::PaymentRequestParent::ChangePaymentMethod",
[self, requestId, methodName, methodDetails]() {
self->ChangePaymentMethod(requestId, methodName, methodDetails);
});
return NS_DispatchToMainThread(r);
}
if (!mActorAlive) {
return NS_ERROR_FAILURE;
}
// Convert nsIMethodChangeDetails to IPCMethodChangeDetails
// aMethodChangeDetails can be null
IPCMethodChangeDetails ipcChangeDetails;
if (aMethodDetails) {
uint32_t dataType;
NS_ENSURE_SUCCESS(aMethodDetails->GetType(&dataType), NS_ERROR_FAILURE);
switch (dataType) {
case nsIMethodChangeDetails::GENERAL_DETAILS: {
nsCOMPtr<nsIGeneralChangeDetails> details =
do_QueryInterface(methodDetails);
MOZ_ASSERT(details);
IPCGeneralChangeDetails ipcGeneralDetails;
NS_ENSURE_SUCCESS(details->GetDetails(ipcGeneralDetails.details()),
NS_ERROR_FAILURE);
ipcChangeDetails = ipcGeneralDetails;
break;
}
case nsIMethodChangeDetails::BASICCARD_DETAILS: {
nsCOMPtr<nsIBasicCardChangeDetails> details =
do_QueryInterface(methodDetails);
MOZ_ASSERT(details);
IPCBasicCardChangeDetails ipcBasicCardDetails;
nsCOMPtr<nsIPaymentAddress> address;
NS_ENSURE_SUCCESS(details->GetBillingAddress(getter_AddRefs(address)),
NS_ERROR_FAILURE);
IPCPaymentAddress ipcAddress;
NS_ENSURE_SUCCESS(SerializeAddress(ipcAddress, address),
NS_ERROR_FAILURE);
ipcBasicCardDetails.billingAddress() = ipcAddress;
ipcChangeDetails = ipcBasicCardDetails;
break;
}
default: {
return NS_ERROR_FAILURE;
}
}
}
if (!SendChangePaymentMethod(requestId, methodName, ipcChangeDetails)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
mozilla::ipc::IPCResult PaymentRequestParent::Recv__delete__() {
mActorAlive = false;
return IPC_OK();
}
void PaymentRequestParent::ActorDestroy(ActorDestroyReason aWhy) {
mActorAlive = false;
nsCOMPtr<nsIPaymentRequestService> service =
do_GetService(NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID);
MOZ_ASSERT(service);
if (!mRequestId.Equals(u""_ns)) {
nsCOMPtr<nsIPaymentRequest> request;
nsresult rv =
service->GetPaymentRequestById(mRequestId, getter_AddRefs(request));
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
if (!request) {
return;
}
payments::PaymentRequest* rowRequest =
static_cast<payments::PaymentRequest*>(request.get());
MOZ_ASSERT(rowRequest);
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;
}
} // namespace mozilla::dom