/* -*- 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/ClearOnShutdown.h" #include "mozilla/dom/PaymentRequestChild.h" #include "mozilla/dom/BrowserChild.h" #include "mozilla/Preferences.h" #include "nsContentUtils.h" #include "nsString.h" #include "nsIPrincipal.h" #include "nsIPaymentActionResponse.h" #include "PaymentRequestManager.h" #include "PaymentRequestUtils.h" #include "PaymentResponse.h" namespace mozilla::dom { namespace { /* * Following Convert* functions are used for convert PaymentRequest structs * to transferable structs for IPC. */ void ConvertMethodData(JSContext* aCx, const PaymentMethodData& aMethodData, IPCPaymentMethodData& aIPCMethodData, ErrorResult& aRv) { MOZ_ASSERT(aCx); // Convert JSObject to a serialized string nsAutoString serializedData; if (aMethodData.mData.WasPassed()) { JS::Rooted object(aCx, aMethodData.mData.Value()); if (NS_WARN_IF( NS_FAILED(SerializeFromJSObject(aCx, object, serializedData)))) { aRv.ThrowTypeError( "The PaymentMethodData.data must be a serializable object"); return; } } aIPCMethodData = IPCPaymentMethodData(aMethodData.mSupportedMethods, serializedData); } void ConvertCurrencyAmount(const PaymentCurrencyAmount& aAmount, IPCPaymentCurrencyAmount& aIPCCurrencyAmount) { aIPCCurrencyAmount = IPCPaymentCurrencyAmount(aAmount.mCurrency, aAmount.mValue); } void ConvertItem(const PaymentItem& aItem, IPCPaymentItem& aIPCItem) { IPCPaymentCurrencyAmount amount; ConvertCurrencyAmount(aItem.mAmount, amount); aIPCItem = IPCPaymentItem(aItem.mLabel, amount, aItem.mPending); } void ConvertModifier(JSContext* aCx, const PaymentDetailsModifier& aModifier, IPCPaymentDetailsModifier& aIPCModifier, ErrorResult& aRv) { MOZ_ASSERT(aCx); // Convert JSObject to a serialized string nsAutoString serializedData; if (aModifier.mData.WasPassed()) { JS::Rooted object(aCx, aModifier.mData.Value()); if (NS_WARN_IF( NS_FAILED(SerializeFromJSObject(aCx, object, serializedData)))) { aRv.ThrowTypeError("The Modifier.data must be a serializable object"); return; } } IPCPaymentItem total; if (aModifier.mTotal.WasPassed()) { ConvertItem(aModifier.mTotal.Value(), total); } nsTArray additionalDisplayItems; if (aModifier.mAdditionalDisplayItems.WasPassed()) { for (const PaymentItem& item : aModifier.mAdditionalDisplayItems.Value()) { IPCPaymentItem displayItem; ConvertItem(item, displayItem); additionalDisplayItems.AppendElement(displayItem); } } aIPCModifier = IPCPaymentDetailsModifier( aModifier.mSupportedMethods, total, additionalDisplayItems, serializedData, aModifier.mAdditionalDisplayItems.WasPassed()); } void ConvertShippingOption(const PaymentShippingOption& aOption, IPCPaymentShippingOption& aIPCOption) { IPCPaymentCurrencyAmount amount; ConvertCurrencyAmount(aOption.mAmount, amount); aIPCOption = IPCPaymentShippingOption(aOption.mId, aOption.mLabel, amount, aOption.mSelected); } void ConvertDetailsBase(JSContext* aCx, const PaymentDetailsBase& aDetails, nsTArray& aDisplayItems, nsTArray& aShippingOptions, nsTArray& aModifiers, bool aRequestShipping, ErrorResult& aRv) { MOZ_ASSERT(aCx); if (aDetails.mDisplayItems.WasPassed()) { for (const PaymentItem& item : aDetails.mDisplayItems.Value()) { IPCPaymentItem displayItem; ConvertItem(item, displayItem); aDisplayItems.AppendElement(displayItem); } } if (aRequestShipping && aDetails.mShippingOptions.WasPassed()) { for (const PaymentShippingOption& option : aDetails.mShippingOptions.Value()) { IPCPaymentShippingOption shippingOption; ConvertShippingOption(option, shippingOption); aShippingOptions.AppendElement(shippingOption); } } if (aDetails.mModifiers.WasPassed()) { for (const PaymentDetailsModifier& modifier : aDetails.mModifiers.Value()) { IPCPaymentDetailsModifier detailsModifier; ConvertModifier(aCx, modifier, detailsModifier, aRv); if (aRv.Failed()) { return; } aModifiers.AppendElement(detailsModifier); } } } void ConvertDetailsInit(JSContext* aCx, const PaymentDetailsInit& aDetails, IPCPaymentDetails& aIPCDetails, bool aRequestShipping, ErrorResult& aRv) { MOZ_ASSERT(aCx); // Convert PaymentDetailsBase members nsTArray displayItems; nsTArray shippingOptions; nsTArray modifiers; ConvertDetailsBase(aCx, aDetails, displayItems, shippingOptions, modifiers, aRequestShipping, aRv); if (aRv.Failed()) { return; } // Convert |id| nsAutoString id; if (aDetails.mId.WasPassed()) { id = aDetails.mId.Value(); } // Convert required |total| IPCPaymentItem total; ConvertItem(aDetails.mTotal, total); aIPCDetails = IPCPaymentDetails(id, total, displayItems, shippingOptions, modifiers, u""_ns, // error message u""_ns, // shippingAddressErrors u""_ns, // payerErrors u""_ns); // paymentMethodErrors } void ConvertDetailsUpdate(JSContext* aCx, const PaymentDetailsUpdate& aDetails, IPCPaymentDetails& aIPCDetails, bool aRequestShipping, ErrorResult& aRv) { MOZ_ASSERT(aCx); // Convert PaymentDetailsBase members nsTArray displayItems; nsTArray shippingOptions; nsTArray modifiers; ConvertDetailsBase(aCx, aDetails, displayItems, shippingOptions, modifiers, aRequestShipping, aRv); if (aRv.Failed()) { return; } // Convert required |total| IPCPaymentItem total; if (aDetails.mTotal.WasPassed()) { ConvertItem(aDetails.mTotal.Value(), total); } // Convert |error| nsAutoString error; if (aDetails.mError.WasPassed()) { error = aDetails.mError.Value(); } nsAutoString shippingAddressErrors; if (aDetails.mShippingAddressErrors.WasPassed()) { if (!aDetails.mShippingAddressErrors.Value().ToJSON( shippingAddressErrors)) { aRv.ThrowTypeError("The ShippingAddressErrors can not be serailized"); return; } } nsAutoString payerErrors; if (aDetails.mPayerErrors.WasPassed()) { if (!aDetails.mPayerErrors.Value().ToJSON(payerErrors)) { aRv.ThrowTypeError("The PayerErrors can not be serialized"); return; } } nsAutoString paymentMethodErrors; if (aDetails.mPaymentMethodErrors.WasPassed()) { JS::Rooted object(aCx, aDetails.mPaymentMethodErrors.Value()); if (NS_WARN_IF(NS_FAILED( SerializeFromJSObject(aCx, object, paymentMethodErrors)))) { aRv.ThrowTypeError("The PaymentMethodErrors can not be serialized"); return; } } aIPCDetails = IPCPaymentDetails(u""_ns, // id total, displayItems, shippingOptions, modifiers, error, shippingAddressErrors, payerErrors, paymentMethodErrors); } void ConvertOptions(const PaymentOptions& aOptions, IPCPaymentOptions& aIPCOption) { NS_ConvertASCIItoUTF16 shippingType( PaymentShippingTypeValues::GetString(aOptions.mShippingType)); aIPCOption = IPCPaymentOptions(aOptions.mRequestPayerName, aOptions.mRequestPayerEmail, aOptions.mRequestPayerPhone, aOptions.mRequestShipping, aOptions.mRequestBillingAddress, shippingType); } void ConvertResponseData(const IPCPaymentResponseData& aIPCData, ResponseData& aData) { switch (aIPCData.type()) { case IPCPaymentResponseData::TIPCGeneralResponse: { const IPCGeneralResponse& data = aIPCData; GeneralData gData; gData.data = data.data(); aData = gData; break; } case IPCPaymentResponseData::TIPCBasicCardResponse: { const IPCBasicCardResponse& data = aIPCData; BasicCardData bData; bData.cardholderName = data.cardholderName(); bData.cardNumber = data.cardNumber(); bData.expiryMonth = data.expiryMonth(); bData.expiryYear = data.expiryYear(); bData.cardSecurityCode = data.cardSecurityCode(); bData.billingAddress.country = data.billingAddress().country(); bData.billingAddress.addressLine = data.billingAddress().addressLine().Clone(); bData.billingAddress.region = data.billingAddress().region(); bData.billingAddress.regionCode = data.billingAddress().regionCode(); bData.billingAddress.city = data.billingAddress().city(); bData.billingAddress.dependentLocality = data.billingAddress().dependentLocality(); bData.billingAddress.postalCode = data.billingAddress().postalCode(); bData.billingAddress.sortingCode = data.billingAddress().sortingCode(); bData.billingAddress.organization = data.billingAddress().organization(); bData.billingAddress.recipient = data.billingAddress().recipient(); bData.billingAddress.phone = data.billingAddress().phone(); aData = bData; break; } default: { break; } } } void ConvertMethodChangeDetails(const IPCMethodChangeDetails& aIPCDetails, ChangeDetails& aDetails) { switch (aIPCDetails.type()) { case IPCMethodChangeDetails::TIPCGeneralChangeDetails: { const IPCGeneralChangeDetails& details = aIPCDetails; GeneralDetails gDetails; gDetails.details = details.details(); aDetails = gDetails; break; } case IPCMethodChangeDetails::TIPCBasicCardChangeDetails: { const IPCBasicCardChangeDetails& details = aIPCDetails; BasicCardDetails bDetails; bDetails.billingAddress.country = details.billingAddress().country(); bDetails.billingAddress.addressLine = details.billingAddress().addressLine(); bDetails.billingAddress.region = details.billingAddress().region(); bDetails.billingAddress.regionCode = details.billingAddress().regionCode(); bDetails.billingAddress.city = details.billingAddress().city(); bDetails.billingAddress.dependentLocality = details.billingAddress().dependentLocality(); bDetails.billingAddress.postalCode = details.billingAddress().postalCode(); bDetails.billingAddress.sortingCode = details.billingAddress().sortingCode(); bDetails.billingAddress.organization = details.billingAddress().organization(); bDetails.billingAddress.recipient = details.billingAddress().recipient(); bDetails.billingAddress.phone = details.billingAddress().phone(); aDetails = bDetails; break; } default: { break; } } } } // end of namespace /* PaymentRequestManager */ StaticRefPtr gPaymentManager; const char kSupportedRegionsPref[] = "dom.payments.request.supportedRegions"; void SupportedRegionsPrefChangedCallback(const char* aPrefName, void* aRetval) { auto retval = static_cast*>(aRetval); MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(!strcmp(aPrefName, kSupportedRegionsPref)); nsAutoString supportedRegions; Preferences::GetString(aPrefName, supportedRegions); retval->Clear(); for (const nsAString& each : supportedRegions.Split(',')) { retval->AppendElement(each); } } PaymentRequestManager::PaymentRequestManager() { Preferences::RegisterCallbackAndCall(SupportedRegionsPrefChangedCallback, kSupportedRegionsPref, &this->mSupportedRegions); } PaymentRequestManager::~PaymentRequestManager() { MOZ_ASSERT(mActivePayments.Count() == 0); Preferences::UnregisterCallback(SupportedRegionsPrefChangedCallback, kSupportedRegionsPref, &this->mSupportedRegions); mSupportedRegions.Clear(); } bool PaymentRequestManager::IsRegionSupported(const nsAString& region) const { return mSupportedRegions.Contains(region); } PaymentRequestChild* PaymentRequestManager::GetPaymentChild( PaymentRequest* aRequest) { MOZ_ASSERT(aRequest); if (PaymentRequestChild* child = aRequest->GetIPC()) { return child; } nsPIDOMWindowInner* win = aRequest->GetOwner(); NS_ENSURE_TRUE(win, nullptr); BrowserChild* browserChild = BrowserChild::GetFrom(win->GetDocShell()); NS_ENSURE_TRUE(browserChild, nullptr); nsAutoString requestId; aRequest->GetInternalId(requestId); PaymentRequestChild* paymentChild = new PaymentRequestChild(aRequest); browserChild->SendPPaymentRequestConstructor(paymentChild); return paymentChild; } nsresult PaymentRequestManager::SendRequestPayment( PaymentRequest* aRequest, const IPCPaymentActionRequest& aAction, bool aResponseExpected) { PaymentRequestChild* requestChild = GetPaymentChild(aRequest); // bug 1580496, ignoring the case that requestChild is nullptr. It could be // nullptr while the corresponding nsPIDOMWindowInner is nullptr. if (NS_WARN_IF(!requestChild)) { return NS_ERROR_FAILURE; } nsresult rv = requestChild->RequestPayment(aAction); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } if (aResponseExpected) { ++mActivePayments.LookupOrInsert(aRequest, 0); } return NS_OK; } void PaymentRequestManager::NotifyRequestDone(PaymentRequest* aRequest) { auto entry = mActivePayments.Lookup(aRequest); MOZ_ASSERT(entry); MOZ_ASSERT(entry.Data() > 0); uint32_t count = --entry.Data(); if (count == 0) { entry.Remove(); } } void PaymentRequestManager::RequestIPCOver(PaymentRequest* aRequest) { // This must only be called from ActorDestroy or if we're sure we won't // receive any more IPC for aRequest. mActivePayments.Remove(aRequest); } already_AddRefed PaymentRequestManager::GetSingleton() { if (!gPaymentManager) { gPaymentManager = new PaymentRequestManager(); ClearOnShutdown(&gPaymentManager); } RefPtr manager = gPaymentManager; return manager.forget(); } void GetSelectedShippingOption(const PaymentDetailsBase& aDetails, nsAString& aOption) { SetDOMStringToNull(aOption); if (!aDetails.mShippingOptions.WasPassed()) { return; } const Sequence& shippingOptions = aDetails.mShippingOptions.Value(); for (const PaymentShippingOption& shippingOption : shippingOptions) { // set aOption to last selected option's ID if (shippingOption.mSelected) { aOption = shippingOption.mId; } } } void PaymentRequestManager::CreatePayment( JSContext* aCx, nsPIDOMWindowInner* aWindow, nsIPrincipal* aTopLevelPrincipal, const Sequence& aMethodData, const PaymentDetailsInit& aDetails, const PaymentOptions& aOptions, PaymentRequest** aRequest, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aCx); MOZ_ASSERT(aRequest); MOZ_ASSERT(aTopLevelPrincipal); *aRequest = nullptr; RefPtr request = PaymentRequest::CreatePaymentRequest(aWindow, aRv); if (aRv.Failed()) { return; } request->SetOptions(aOptions); /* * Set request's |mId| to details.id if details.id exists. * Otherwise, set |mId| to internal id. */ nsAutoString requestId; if (aDetails.mId.WasPassed() && !aDetails.mId.Value().IsEmpty()) { requestId = aDetails.mId.Value(); } else { request->GetInternalId(requestId); } request->SetId(requestId); /* * Set request's |mShippingType| and |mShippingOption| if shipping is * required. Set request's mShippingOption to last selected option's ID if * details.shippingOptions exists, otherwise set it as null. */ nsAutoString shippingOption; SetDOMStringToNull(shippingOption); if (aOptions.mRequestShipping) { request->ShippingWasRequested(); request->SetShippingType( Nullable(aOptions.mShippingType)); GetSelectedShippingOption(aDetails, shippingOption); } request->SetShippingOption(shippingOption); nsAutoString internalId; request->GetInternalId(internalId); nsTArray methodData; for (const PaymentMethodData& data : aMethodData) { IPCPaymentMethodData ipcMethodData; ConvertMethodData(aCx, data, ipcMethodData, aRv); if (aRv.Failed()) { return; } methodData.AppendElement(ipcMethodData); } IPCPaymentDetails details; ConvertDetailsInit(aCx, aDetails, details, aOptions.mRequestShipping, aRv); if (aRv.Failed()) { return; } IPCPaymentOptions options; ConvertOptions(aOptions, options); uint64_t topOuterWindowId = aWindow->GetWindowContext()->TopWindowContext()->OuterWindowId(); IPCPaymentCreateActionRequest action(topOuterWindowId, internalId, aTopLevelPrincipal, methodData, details, options, shippingOption); if (NS_WARN_IF(NS_FAILED(SendRequestPayment(request, action, false)))) { aRv.ThrowUnknownError("Internal error sending payment request"); return; } request.forget(aRequest); } void PaymentRequestManager::CanMakePayment(PaymentRequest* aRequest, ErrorResult& aRv) { nsAutoString requestId; aRequest->GetInternalId(requestId); IPCPaymentCanMakeActionRequest action(requestId); if (NS_WARN_IF(NS_FAILED(SendRequestPayment(aRequest, action)))) { aRv.ThrowUnknownError("Internal error sending payment request"); } } void PaymentRequestManager::ShowPayment(PaymentRequest* aRequest, ErrorResult& aRv) { nsAutoString requestId; aRequest->GetInternalId(requestId); IPCPaymentShowActionRequest action(requestId, aRequest->IsUpdating()); if (NS_WARN_IF(NS_FAILED(SendRequestPayment(aRequest, action)))) { aRv.ThrowUnknownError("Internal error sending payment request"); } } void PaymentRequestManager::AbortPayment(PaymentRequest* aRequest, ErrorResult& aRv) { nsAutoString requestId; aRequest->GetInternalId(requestId); IPCPaymentAbortActionRequest action(requestId); if (NS_WARN_IF(NS_FAILED(SendRequestPayment(aRequest, action)))) { aRv.ThrowUnknownError("Internal error sending payment request"); } } void PaymentRequestManager::CompletePayment(PaymentRequest* aRequest, const PaymentComplete& aComplete, ErrorResult& aRv, bool aTimedOut) { nsString completeStatusString(u"unknown"_ns); if (aTimedOut) { completeStatusString.AssignLiteral("timeout"); } else { completeStatusString.AssignASCII( PaymentCompleteValues::GetString(aComplete)); } nsAutoString requestId; aRequest->GetInternalId(requestId); IPCPaymentCompleteActionRequest action(requestId, completeStatusString); if (NS_WARN_IF(NS_FAILED(SendRequestPayment(aRequest, action, false)))) { aRv.ThrowUnknownError("Internal error sending payment request"); } } void PaymentRequestManager::UpdatePayment(JSContext* aCx, PaymentRequest* aRequest, const PaymentDetailsUpdate& aDetails, bool aRequestShipping, ErrorResult& aRv) { MOZ_ASSERT(aCx); IPCPaymentDetails details; ConvertDetailsUpdate(aCx, aDetails, details, aRequestShipping, aRv); if (aRv.Failed()) { return; } nsAutoString shippingOption; SetDOMStringToNull(shippingOption); if (aRequestShipping) { GetSelectedShippingOption(aDetails, shippingOption); aRequest->SetShippingOption(shippingOption); } nsAutoString requestId; aRequest->GetInternalId(requestId); IPCPaymentUpdateActionRequest action(requestId, details, shippingOption); if (NS_WARN_IF(NS_FAILED(SendRequestPayment(aRequest, action, false)))) { aRv.ThrowUnknownError("Internal error sending payment request"); } } nsresult PaymentRequestManager::ClosePayment(PaymentRequest* aRequest) { // for the case, the payment request is waiting for response from user. if (auto entry = mActivePayments.Lookup(aRequest)) { NotifyRequestDone(aRequest); } nsAutoString requestId; aRequest->GetInternalId(requestId); IPCPaymentCloseActionRequest action(requestId); return SendRequestPayment(aRequest, action, false); } void PaymentRequestManager::RetryPayment(JSContext* aCx, PaymentRequest* aRequest, const PaymentValidationErrors& aErrors, ErrorResult& aRv) { MOZ_ASSERT(aCx); MOZ_ASSERT(aRequest); nsAutoString requestId; aRequest->GetInternalId(requestId); nsAutoString error; if (aErrors.mError.WasPassed()) { error = aErrors.mError.Value(); } nsAutoString shippingAddressErrors; if (aErrors.mShippingAddress.WasPassed()) { if (!aErrors.mShippingAddress.Value().ToJSON(shippingAddressErrors)) { aRv.ThrowTypeError("The ShippingAddressErrors can not be serialized"); return; } } nsAutoString payerErrors; if (aErrors.mPayer.WasPassed()) { if (!aErrors.mPayer.Value().ToJSON(payerErrors)) { aRv.ThrowTypeError("The PayerErrors can not be serialized"); return; } } nsAutoString paymentMethodErrors; if (aErrors.mPaymentMethod.WasPassed()) { JS::Rooted object(aCx, aErrors.mPaymentMethod.Value()); if (NS_WARN_IF(NS_FAILED( SerializeFromJSObject(aCx, object, paymentMethodErrors)))) { aRv.ThrowTypeError("The PaymentMethodErrors can not be serialized"); return; } } IPCPaymentRetryActionRequest action(requestId, error, payerErrors, paymentMethodErrors, shippingAddressErrors); if (NS_WARN_IF(NS_FAILED(SendRequestPayment(aRequest, action)))) { aRv.ThrowUnknownError("Internal error sending payment request"); } } nsresult PaymentRequestManager::RespondPayment( PaymentRequest* aRequest, const IPCPaymentActionResponse& aResponse) { switch (aResponse.type()) { case IPCPaymentActionResponse::TIPCPaymentCanMakeActionResponse: { const IPCPaymentCanMakeActionResponse& response = aResponse; aRequest->RespondCanMakePayment(response.result()); NotifyRequestDone(aRequest); break; } case IPCPaymentActionResponse::TIPCPaymentShowActionResponse: { const IPCPaymentShowActionResponse& response = aResponse; ErrorResult rejectedReason; ResponseData responseData; ConvertResponseData(response.data(), responseData); switch (response.status()) { case nsIPaymentActionResponse::PAYMENT_ACCEPTED: { break; } case nsIPaymentActionResponse::PAYMENT_REJECTED: { rejectedReason.ThrowAbortError("The user rejected the payment"); break; } case nsIPaymentActionResponse::PAYMENT_NOTSUPPORTED: { rejectedReason.ThrowNotSupportedError("No supported payment method"); break; } default: { rejectedReason.ThrowUnknownError("Unknown response for the payment"); break; } } // If PaymentActionResponse is not PAYMENT_ACCEPTED, no need to keep the // PaymentRequestChild instance. Otherwise, keep PaymentRequestChild for // merchants call PaymentResponse.complete() if (rejectedReason.Failed()) { NotifyRequestDone(aRequest); } aRequest->RespondShowPayment(response.methodName(), responseData, response.payerName(), response.payerEmail(), response.payerPhone(), std::move(rejectedReason)); break; } case IPCPaymentActionResponse::TIPCPaymentAbortActionResponse: { const IPCPaymentAbortActionResponse& response = aResponse; aRequest->RespondAbortPayment(response.isSucceeded()); NotifyRequestDone(aRequest); break; } case IPCPaymentActionResponse::TIPCPaymentCompleteActionResponse: { aRequest->RespondComplete(); NotifyRequestDone(aRequest); break; } default: { return NS_ERROR_FAILURE; } } return NS_OK; } nsresult PaymentRequestManager::ChangeShippingAddress( PaymentRequest* aRequest, const IPCPaymentAddress& aAddress) { return aRequest->UpdateShippingAddress( aAddress.country(), aAddress.addressLine(), aAddress.region(), aAddress.regionCode(), aAddress.city(), aAddress.dependentLocality(), aAddress.postalCode(), aAddress.sortingCode(), aAddress.organization(), aAddress.recipient(), aAddress.phone()); } nsresult PaymentRequestManager::ChangeShippingOption(PaymentRequest* aRequest, const nsAString& aOption) { return aRequest->UpdateShippingOption(aOption); } nsresult PaymentRequestManager::ChangePayerDetail( PaymentRequest* aRequest, const nsAString& aPayerName, const nsAString& aPayerEmail, const nsAString& aPayerPhone) { MOZ_ASSERT(aRequest); RefPtr response = aRequest->GetResponse(); // ignoring the case call changePayerDetail during show(). if (!response) { return NS_OK; } return response->UpdatePayerDetail(aPayerName, aPayerEmail, aPayerPhone); } nsresult PaymentRequestManager::ChangePaymentMethod( PaymentRequest* aRequest, const nsAString& aMethodName, const IPCMethodChangeDetails& aMethodDetails) { NS_ENSURE_ARG_POINTER(aRequest); ChangeDetails methodDetails; ConvertMethodChangeDetails(aMethodDetails, methodDetails); return aRequest->UpdatePaymentMethod(aMethodName, methodDetails); } } // namespace mozilla::dom