Bug 1874684 - Part 6: Limit day length calculations to safe integers. r=mgaudet
[gecko.git] / dom / payments / PaymentRequestManager.cpp
blob1f21ff1bab3e76ea3002896c26e85863d73ce08f
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/ClearOnShutdown.h"
8 #include "mozilla/dom/PaymentRequestChild.h"
9 #include "mozilla/dom/BrowserChild.h"
10 #include "mozilla/Preferences.h"
11 #include "nsContentUtils.h"
12 #include "nsString.h"
13 #include "nsIPrincipal.h"
14 #include "nsIPaymentActionResponse.h"
15 #include "PaymentRequestManager.h"
16 #include "PaymentRequestUtils.h"
17 #include "PaymentResponse.h"
19 namespace mozilla::dom {
20 namespace {
23 * Following Convert* functions are used for convert PaymentRequest structs
24 * to transferable structs for IPC.
26 void ConvertMethodData(JSContext* aCx, const PaymentMethodData& aMethodData,
27 IPCPaymentMethodData& aIPCMethodData, ErrorResult& aRv) {
28 MOZ_ASSERT(aCx);
29 // Convert JSObject to a serialized string
30 nsAutoString serializedData;
31 if (aMethodData.mData.WasPassed()) {
32 JS::Rooted<JSObject*> object(aCx, aMethodData.mData.Value());
33 if (NS_WARN_IF(
34 NS_FAILED(SerializeFromJSObject(aCx, object, serializedData)))) {
35 aRv.ThrowTypeError(
36 "The PaymentMethodData.data must be a serializable object");
37 return;
40 aIPCMethodData =
41 IPCPaymentMethodData(aMethodData.mSupportedMethods, serializedData);
44 void ConvertCurrencyAmount(const PaymentCurrencyAmount& aAmount,
45 IPCPaymentCurrencyAmount& aIPCCurrencyAmount) {
46 aIPCCurrencyAmount =
47 IPCPaymentCurrencyAmount(aAmount.mCurrency, aAmount.mValue);
50 void ConvertItem(const PaymentItem& aItem, IPCPaymentItem& aIPCItem) {
51 IPCPaymentCurrencyAmount amount;
52 ConvertCurrencyAmount(aItem.mAmount, amount);
53 aIPCItem = IPCPaymentItem(aItem.mLabel, amount, aItem.mPending);
56 void ConvertModifier(JSContext* aCx, const PaymentDetailsModifier& aModifier,
57 IPCPaymentDetailsModifier& aIPCModifier,
58 ErrorResult& aRv) {
59 MOZ_ASSERT(aCx);
60 // Convert JSObject to a serialized string
61 nsAutoString serializedData;
62 if (aModifier.mData.WasPassed()) {
63 JS::Rooted<JSObject*> object(aCx, aModifier.mData.Value());
64 if (NS_WARN_IF(
65 NS_FAILED(SerializeFromJSObject(aCx, object, serializedData)))) {
66 aRv.ThrowTypeError("The Modifier.data must be a serializable object");
67 return;
71 IPCPaymentItem total;
72 if (aModifier.mTotal.WasPassed()) {
73 ConvertItem(aModifier.mTotal.Value(), total);
76 nsTArray<IPCPaymentItem> additionalDisplayItems;
77 if (aModifier.mAdditionalDisplayItems.WasPassed()) {
78 for (const PaymentItem& item : aModifier.mAdditionalDisplayItems.Value()) {
79 IPCPaymentItem displayItem;
80 ConvertItem(item, displayItem);
81 additionalDisplayItems.AppendElement(displayItem);
84 aIPCModifier = IPCPaymentDetailsModifier(
85 aModifier.mSupportedMethods, total, additionalDisplayItems,
86 serializedData, aModifier.mAdditionalDisplayItems.WasPassed());
89 void ConvertShippingOption(const PaymentShippingOption& aOption,
90 IPCPaymentShippingOption& aIPCOption) {
91 IPCPaymentCurrencyAmount amount;
92 ConvertCurrencyAmount(aOption.mAmount, amount);
93 aIPCOption = IPCPaymentShippingOption(aOption.mId, aOption.mLabel, amount,
94 aOption.mSelected);
97 void ConvertDetailsBase(JSContext* aCx, const PaymentDetailsBase& aDetails,
98 nsTArray<IPCPaymentItem>& aDisplayItems,
99 nsTArray<IPCPaymentShippingOption>& aShippingOptions,
100 nsTArray<IPCPaymentDetailsModifier>& aModifiers,
101 bool aRequestShipping, ErrorResult& aRv) {
102 MOZ_ASSERT(aCx);
103 if (aDetails.mDisplayItems.WasPassed()) {
104 for (const PaymentItem& item : aDetails.mDisplayItems.Value()) {
105 IPCPaymentItem displayItem;
106 ConvertItem(item, displayItem);
107 aDisplayItems.AppendElement(displayItem);
110 if (aRequestShipping && aDetails.mShippingOptions.WasPassed()) {
111 for (const PaymentShippingOption& option :
112 aDetails.mShippingOptions.Value()) {
113 IPCPaymentShippingOption shippingOption;
114 ConvertShippingOption(option, shippingOption);
115 aShippingOptions.AppendElement(shippingOption);
118 if (aDetails.mModifiers.WasPassed()) {
119 for (const PaymentDetailsModifier& modifier : aDetails.mModifiers.Value()) {
120 IPCPaymentDetailsModifier detailsModifier;
121 ConvertModifier(aCx, modifier, detailsModifier, aRv);
122 if (aRv.Failed()) {
123 return;
125 aModifiers.AppendElement(detailsModifier);
130 void ConvertDetailsInit(JSContext* aCx, const PaymentDetailsInit& aDetails,
131 IPCPaymentDetails& aIPCDetails, bool aRequestShipping,
132 ErrorResult& aRv) {
133 MOZ_ASSERT(aCx);
134 // Convert PaymentDetailsBase members
135 nsTArray<IPCPaymentItem> displayItems;
136 nsTArray<IPCPaymentShippingOption> shippingOptions;
137 nsTArray<IPCPaymentDetailsModifier> modifiers;
138 ConvertDetailsBase(aCx, aDetails, displayItems, shippingOptions, modifiers,
139 aRequestShipping, aRv);
140 if (aRv.Failed()) {
141 return;
144 // Convert |id|
145 nsAutoString id;
146 if (aDetails.mId.WasPassed()) {
147 id = aDetails.mId.Value();
150 // Convert required |total|
151 IPCPaymentItem total;
152 ConvertItem(aDetails.mTotal, total);
154 aIPCDetails =
155 IPCPaymentDetails(id, total, displayItems, shippingOptions, modifiers,
156 u""_ns, // error message
157 u""_ns, // shippingAddressErrors
158 u""_ns, // payerErrors
159 u""_ns); // paymentMethodErrors
162 void ConvertDetailsUpdate(JSContext* aCx, const PaymentDetailsUpdate& aDetails,
163 IPCPaymentDetails& aIPCDetails, bool aRequestShipping,
164 ErrorResult& aRv) {
165 MOZ_ASSERT(aCx);
166 // Convert PaymentDetailsBase members
167 nsTArray<IPCPaymentItem> displayItems;
168 nsTArray<IPCPaymentShippingOption> shippingOptions;
169 nsTArray<IPCPaymentDetailsModifier> modifiers;
170 ConvertDetailsBase(aCx, aDetails, displayItems, shippingOptions, modifiers,
171 aRequestShipping, aRv);
172 if (aRv.Failed()) {
173 return;
176 // Convert required |total|
177 IPCPaymentItem total;
178 if (aDetails.mTotal.WasPassed()) {
179 ConvertItem(aDetails.mTotal.Value(), total);
182 // Convert |error|
183 nsAutoString error;
184 if (aDetails.mError.WasPassed()) {
185 error = aDetails.mError.Value();
188 nsAutoString shippingAddressErrors;
189 if (aDetails.mShippingAddressErrors.WasPassed()) {
190 if (!aDetails.mShippingAddressErrors.Value().ToJSON(
191 shippingAddressErrors)) {
192 aRv.ThrowTypeError("The ShippingAddressErrors can not be serailized");
193 return;
197 nsAutoString payerErrors;
198 if (aDetails.mPayerErrors.WasPassed()) {
199 if (!aDetails.mPayerErrors.Value().ToJSON(payerErrors)) {
200 aRv.ThrowTypeError("The PayerErrors can not be serialized");
201 return;
205 nsAutoString paymentMethodErrors;
206 if (aDetails.mPaymentMethodErrors.WasPassed()) {
207 JS::Rooted<JSObject*> object(aCx, aDetails.mPaymentMethodErrors.Value());
208 if (NS_WARN_IF(NS_FAILED(
209 SerializeFromJSObject(aCx, object, paymentMethodErrors)))) {
210 aRv.ThrowTypeError("The PaymentMethodErrors can not be serialized");
211 return;
215 aIPCDetails = IPCPaymentDetails(u""_ns, // id
216 total, displayItems, shippingOptions,
217 modifiers, error, shippingAddressErrors,
218 payerErrors, paymentMethodErrors);
221 void ConvertOptions(const PaymentOptions& aOptions,
222 IPCPaymentOptions& aIPCOption) {
223 NS_ConvertASCIItoUTF16 shippingType(GetEnumString(aOptions.mShippingType));
224 aIPCOption =
225 IPCPaymentOptions(aOptions.mRequestPayerName, aOptions.mRequestPayerEmail,
226 aOptions.mRequestPayerPhone, aOptions.mRequestShipping,
227 aOptions.mRequestBillingAddress, shippingType);
230 void ConvertResponseData(const IPCPaymentResponseData& aIPCData,
231 ResponseData& aData) {
232 switch (aIPCData.type()) {
233 case IPCPaymentResponseData::TIPCGeneralResponse: {
234 const IPCGeneralResponse& data = aIPCData;
235 GeneralData gData;
236 gData.data = data.data();
237 aData = gData;
238 break;
240 case IPCPaymentResponseData::TIPCBasicCardResponse: {
241 const IPCBasicCardResponse& data = aIPCData;
242 BasicCardData bData;
243 bData.cardholderName = data.cardholderName();
244 bData.cardNumber = data.cardNumber();
245 bData.expiryMonth = data.expiryMonth();
246 bData.expiryYear = data.expiryYear();
247 bData.cardSecurityCode = data.cardSecurityCode();
248 bData.billingAddress.country = data.billingAddress().country();
249 bData.billingAddress.addressLine =
250 data.billingAddress().addressLine().Clone();
251 bData.billingAddress.region = data.billingAddress().region();
252 bData.billingAddress.regionCode = data.billingAddress().regionCode();
253 bData.billingAddress.city = data.billingAddress().city();
254 bData.billingAddress.dependentLocality =
255 data.billingAddress().dependentLocality();
256 bData.billingAddress.postalCode = data.billingAddress().postalCode();
257 bData.billingAddress.sortingCode = data.billingAddress().sortingCode();
258 bData.billingAddress.organization = data.billingAddress().organization();
259 bData.billingAddress.recipient = data.billingAddress().recipient();
260 bData.billingAddress.phone = data.billingAddress().phone();
261 aData = bData;
262 break;
264 default: {
265 break;
270 void ConvertMethodChangeDetails(const IPCMethodChangeDetails& aIPCDetails,
271 ChangeDetails& aDetails) {
272 switch (aIPCDetails.type()) {
273 case IPCMethodChangeDetails::TIPCGeneralChangeDetails: {
274 const IPCGeneralChangeDetails& details = aIPCDetails;
275 GeneralDetails gDetails;
276 gDetails.details = details.details();
277 aDetails = gDetails;
278 break;
280 case IPCMethodChangeDetails::TIPCBasicCardChangeDetails: {
281 const IPCBasicCardChangeDetails& details = aIPCDetails;
282 BasicCardDetails bDetails;
283 bDetails.billingAddress.country = details.billingAddress().country();
284 bDetails.billingAddress.addressLine =
285 details.billingAddress().addressLine();
286 bDetails.billingAddress.region = details.billingAddress().region();
287 bDetails.billingAddress.regionCode =
288 details.billingAddress().regionCode();
289 bDetails.billingAddress.city = details.billingAddress().city();
290 bDetails.billingAddress.dependentLocality =
291 details.billingAddress().dependentLocality();
292 bDetails.billingAddress.postalCode =
293 details.billingAddress().postalCode();
294 bDetails.billingAddress.sortingCode =
295 details.billingAddress().sortingCode();
296 bDetails.billingAddress.organization =
297 details.billingAddress().organization();
298 bDetails.billingAddress.recipient = details.billingAddress().recipient();
299 bDetails.billingAddress.phone = details.billingAddress().phone();
300 aDetails = bDetails;
301 break;
303 default: {
304 break;
308 } // end of namespace
310 /* PaymentRequestManager */
312 StaticRefPtr<PaymentRequestManager> gPaymentManager;
313 const char kSupportedRegionsPref[] = "dom.payments.request.supportedRegions";
315 void SupportedRegionsPrefChangedCallback(const char* aPrefName, void* aRetval) {
316 auto retval = static_cast<nsTArray<nsString>*>(aRetval);
317 MOZ_ASSERT(NS_IsMainThread());
318 MOZ_ASSERT(!strcmp(aPrefName, kSupportedRegionsPref));
320 nsAutoString supportedRegions;
321 Preferences::GetString(aPrefName, supportedRegions);
322 retval->Clear();
323 for (const nsAString& each : supportedRegions.Split(',')) {
324 retval->AppendElement(each);
328 PaymentRequestManager::PaymentRequestManager() {
329 Preferences::RegisterCallbackAndCall(SupportedRegionsPrefChangedCallback,
330 kSupportedRegionsPref,
331 &this->mSupportedRegions);
334 PaymentRequestManager::~PaymentRequestManager() {
335 MOZ_ASSERT(mActivePayments.Count() == 0);
336 Preferences::UnregisterCallback(SupportedRegionsPrefChangedCallback,
337 kSupportedRegionsPref,
338 &this->mSupportedRegions);
339 mSupportedRegions.Clear();
342 bool PaymentRequestManager::IsRegionSupported(const nsAString& region) const {
343 return mSupportedRegions.Contains(region);
346 PaymentRequestChild* PaymentRequestManager::GetPaymentChild(
347 PaymentRequest* aRequest) {
348 MOZ_ASSERT(aRequest);
350 if (PaymentRequestChild* child = aRequest->GetIPC()) {
351 return child;
354 nsPIDOMWindowInner* win = aRequest->GetOwner();
355 NS_ENSURE_TRUE(win, nullptr);
356 BrowserChild* browserChild = BrowserChild::GetFrom(win->GetDocShell());
357 NS_ENSURE_TRUE(browserChild, nullptr);
358 nsAutoString requestId;
359 aRequest->GetInternalId(requestId);
361 PaymentRequestChild* paymentChild = new PaymentRequestChild(aRequest);
362 if (!browserChild->SendPPaymentRequestConstructor(paymentChild)) {
363 // deleted by Constructor
364 return nullptr;
367 return paymentChild;
370 nsresult PaymentRequestManager::SendRequestPayment(
371 PaymentRequest* aRequest, const IPCPaymentActionRequest& aAction,
372 bool aResponseExpected) {
373 PaymentRequestChild* requestChild = GetPaymentChild(aRequest);
374 // bug 1580496, ignoring the case that requestChild is nullptr. It could be
375 // nullptr while the corresponding nsPIDOMWindowInner is nullptr.
376 if (NS_WARN_IF(!requestChild)) {
377 return NS_ERROR_FAILURE;
379 nsresult rv = requestChild->RequestPayment(aAction);
380 if (NS_WARN_IF(NS_FAILED(rv))) {
381 return rv;
384 if (aResponseExpected) {
385 ++mActivePayments.LookupOrInsert(aRequest, 0);
387 return NS_OK;
390 void PaymentRequestManager::NotifyRequestDone(PaymentRequest* aRequest) {
391 auto entry = mActivePayments.Lookup(aRequest);
392 MOZ_ASSERT(entry);
393 MOZ_ASSERT(entry.Data() > 0);
395 uint32_t count = --entry.Data();
396 if (count == 0) {
397 entry.Remove();
401 void PaymentRequestManager::RequestIPCOver(PaymentRequest* aRequest) {
402 // This must only be called from ActorDestroy or if we're sure we won't
403 // receive any more IPC for aRequest.
404 mActivePayments.Remove(aRequest);
407 already_AddRefed<PaymentRequestManager> PaymentRequestManager::GetSingleton() {
408 if (!gPaymentManager) {
409 gPaymentManager = new PaymentRequestManager();
410 ClearOnShutdown(&gPaymentManager);
412 RefPtr<PaymentRequestManager> manager = gPaymentManager;
413 return manager.forget();
416 void GetSelectedShippingOption(const PaymentDetailsBase& aDetails,
417 nsAString& aOption) {
418 SetDOMStringToNull(aOption);
419 if (!aDetails.mShippingOptions.WasPassed()) {
420 return;
423 const Sequence<PaymentShippingOption>& shippingOptions =
424 aDetails.mShippingOptions.Value();
425 for (const PaymentShippingOption& shippingOption : shippingOptions) {
426 // set aOption to last selected option's ID
427 if (shippingOption.mSelected) {
428 aOption = shippingOption.mId;
433 void PaymentRequestManager::CreatePayment(
434 JSContext* aCx, nsPIDOMWindowInner* aWindow,
435 nsIPrincipal* aTopLevelPrincipal,
436 const Sequence<PaymentMethodData>& aMethodData,
437 const PaymentDetailsInit& aDetails, const PaymentOptions& aOptions,
438 PaymentRequest** aRequest, ErrorResult& aRv) {
439 MOZ_ASSERT(NS_IsMainThread());
440 MOZ_ASSERT(aCx);
441 MOZ_ASSERT(aRequest);
442 MOZ_ASSERT(aTopLevelPrincipal);
443 *aRequest = nullptr;
445 RefPtr<PaymentRequest> request =
446 PaymentRequest::CreatePaymentRequest(aWindow, aRv);
447 if (aRv.Failed()) {
448 return;
450 request->SetOptions(aOptions);
452 * Set request's |mId| to details.id if details.id exists.
453 * Otherwise, set |mId| to internal id.
455 nsAutoString requestId;
456 if (aDetails.mId.WasPassed() && !aDetails.mId.Value().IsEmpty()) {
457 requestId = aDetails.mId.Value();
458 } else {
459 request->GetInternalId(requestId);
461 request->SetId(requestId);
464 * Set request's |mShippingType| and |mShippingOption| if shipping is
465 * required. Set request's mShippingOption to last selected option's ID if
466 * details.shippingOptions exists, otherwise set it as null.
468 nsAutoString shippingOption;
469 SetDOMStringToNull(shippingOption);
470 if (aOptions.mRequestShipping) {
471 request->ShippingWasRequested();
472 request->SetShippingType(
473 Nullable<PaymentShippingType>(aOptions.mShippingType));
474 GetSelectedShippingOption(aDetails, shippingOption);
476 request->SetShippingOption(shippingOption);
478 nsAutoString internalId;
479 request->GetInternalId(internalId);
481 nsTArray<IPCPaymentMethodData> methodData;
482 for (const PaymentMethodData& data : aMethodData) {
483 IPCPaymentMethodData ipcMethodData;
484 ConvertMethodData(aCx, data, ipcMethodData, aRv);
485 if (aRv.Failed()) {
486 return;
488 methodData.AppendElement(ipcMethodData);
491 IPCPaymentDetails details;
492 ConvertDetailsInit(aCx, aDetails, details, aOptions.mRequestShipping, aRv);
493 if (aRv.Failed()) {
494 return;
497 IPCPaymentOptions options;
498 ConvertOptions(aOptions, options);
500 uint64_t topOuterWindowId =
501 aWindow->GetWindowContext()->TopWindowContext()->OuterWindowId();
502 IPCPaymentCreateActionRequest action(topOuterWindowId, internalId,
503 aTopLevelPrincipal, methodData, details,
504 options, shippingOption);
506 if (NS_WARN_IF(NS_FAILED(SendRequestPayment(request, action, false)))) {
507 aRv.ThrowUnknownError("Internal error sending payment request");
508 return;
510 request.forget(aRequest);
513 void PaymentRequestManager::CanMakePayment(PaymentRequest* aRequest,
514 ErrorResult& aRv) {
515 nsAutoString requestId;
516 aRequest->GetInternalId(requestId);
517 IPCPaymentCanMakeActionRequest action(requestId);
518 if (NS_WARN_IF(NS_FAILED(SendRequestPayment(aRequest, action)))) {
519 aRv.ThrowUnknownError("Internal error sending payment request");
523 void PaymentRequestManager::ShowPayment(PaymentRequest* aRequest,
524 ErrorResult& aRv) {
525 nsAutoString requestId;
526 aRequest->GetInternalId(requestId);
527 IPCPaymentShowActionRequest action(requestId, aRequest->IsUpdating());
528 if (NS_WARN_IF(NS_FAILED(SendRequestPayment(aRequest, action)))) {
529 aRv.ThrowUnknownError("Internal error sending payment request");
533 void PaymentRequestManager::AbortPayment(PaymentRequest* aRequest,
534 ErrorResult& aRv) {
535 nsAutoString requestId;
536 aRequest->GetInternalId(requestId);
537 IPCPaymentAbortActionRequest action(requestId);
538 if (NS_WARN_IF(NS_FAILED(SendRequestPayment(aRequest, action)))) {
539 aRv.ThrowUnknownError("Internal error sending payment request");
543 void PaymentRequestManager::CompletePayment(PaymentRequest* aRequest,
544 const PaymentComplete& aComplete,
545 ErrorResult& aRv, bool aTimedOut) {
546 nsString completeStatusString(u"unknown"_ns);
547 if (aTimedOut) {
548 completeStatusString.AssignLiteral("timeout");
549 } else {
550 completeStatusString.AssignASCII(GetEnumString(aComplete));
553 nsAutoString requestId;
554 aRequest->GetInternalId(requestId);
555 IPCPaymentCompleteActionRequest action(requestId, completeStatusString);
556 if (NS_WARN_IF(NS_FAILED(SendRequestPayment(aRequest, action, false)))) {
557 aRv.ThrowUnknownError("Internal error sending payment request");
561 void PaymentRequestManager::UpdatePayment(JSContext* aCx,
562 PaymentRequest* aRequest,
563 const PaymentDetailsUpdate& aDetails,
564 bool aRequestShipping,
565 ErrorResult& aRv) {
566 MOZ_ASSERT(aCx);
567 IPCPaymentDetails details;
568 ConvertDetailsUpdate(aCx, aDetails, details, aRequestShipping, aRv);
569 if (aRv.Failed()) {
570 return;
573 nsAutoString shippingOption;
574 SetDOMStringToNull(shippingOption);
575 if (aRequestShipping) {
576 GetSelectedShippingOption(aDetails, shippingOption);
577 aRequest->SetShippingOption(shippingOption);
580 nsAutoString requestId;
581 aRequest->GetInternalId(requestId);
582 IPCPaymentUpdateActionRequest action(requestId, details, shippingOption);
583 if (NS_WARN_IF(NS_FAILED(SendRequestPayment(aRequest, action, false)))) {
584 aRv.ThrowUnknownError("Internal error sending payment request");
588 nsresult PaymentRequestManager::ClosePayment(PaymentRequest* aRequest) {
589 // for the case, the payment request is waiting for response from user.
590 if (auto entry = mActivePayments.Lookup(aRequest)) {
591 NotifyRequestDone(aRequest);
593 nsAutoString requestId;
594 aRequest->GetInternalId(requestId);
595 IPCPaymentCloseActionRequest action(requestId);
596 return SendRequestPayment(aRequest, action, false);
599 void PaymentRequestManager::RetryPayment(JSContext* aCx,
600 PaymentRequest* aRequest,
601 const PaymentValidationErrors& aErrors,
602 ErrorResult& aRv) {
603 MOZ_ASSERT(aCx);
604 MOZ_ASSERT(aRequest);
606 nsAutoString requestId;
607 aRequest->GetInternalId(requestId);
609 nsAutoString error;
610 if (aErrors.mError.WasPassed()) {
611 error = aErrors.mError.Value();
614 nsAutoString shippingAddressErrors;
615 if (aErrors.mShippingAddress.WasPassed()) {
616 if (!aErrors.mShippingAddress.Value().ToJSON(shippingAddressErrors)) {
617 aRv.ThrowTypeError("The ShippingAddressErrors can not be serialized");
618 return;
622 nsAutoString payerErrors;
623 if (aErrors.mPayer.WasPassed()) {
624 if (!aErrors.mPayer.Value().ToJSON(payerErrors)) {
625 aRv.ThrowTypeError("The PayerErrors can not be serialized");
626 return;
630 nsAutoString paymentMethodErrors;
631 if (aErrors.mPaymentMethod.WasPassed()) {
632 JS::Rooted<JSObject*> object(aCx, aErrors.mPaymentMethod.Value());
633 if (NS_WARN_IF(NS_FAILED(
634 SerializeFromJSObject(aCx, object, paymentMethodErrors)))) {
635 aRv.ThrowTypeError("The PaymentMethodErrors can not be serialized");
636 return;
639 IPCPaymentRetryActionRequest action(requestId, error, payerErrors,
640 paymentMethodErrors,
641 shippingAddressErrors);
642 if (NS_WARN_IF(NS_FAILED(SendRequestPayment(aRequest, action)))) {
643 aRv.ThrowUnknownError("Internal error sending payment request");
647 nsresult PaymentRequestManager::RespondPayment(
648 PaymentRequest* aRequest, const IPCPaymentActionResponse& aResponse) {
649 switch (aResponse.type()) {
650 case IPCPaymentActionResponse::TIPCPaymentCanMakeActionResponse: {
651 const IPCPaymentCanMakeActionResponse& response = aResponse;
652 aRequest->RespondCanMakePayment(response.result());
653 NotifyRequestDone(aRequest);
654 break;
656 case IPCPaymentActionResponse::TIPCPaymentShowActionResponse: {
657 const IPCPaymentShowActionResponse& response = aResponse;
658 ErrorResult rejectedReason;
659 ResponseData responseData;
660 ConvertResponseData(response.data(), responseData);
661 switch (response.status()) {
662 case nsIPaymentActionResponse::PAYMENT_ACCEPTED: {
663 break;
665 case nsIPaymentActionResponse::PAYMENT_REJECTED: {
666 rejectedReason.ThrowAbortError("The user rejected the payment");
667 break;
669 case nsIPaymentActionResponse::PAYMENT_NOTSUPPORTED: {
670 rejectedReason.ThrowNotSupportedError("No supported payment method");
671 break;
673 default: {
674 rejectedReason.ThrowUnknownError("Unknown response for the payment");
675 break;
678 // If PaymentActionResponse is not PAYMENT_ACCEPTED, no need to keep the
679 // PaymentRequestChild instance. Otherwise, keep PaymentRequestChild for
680 // merchants call PaymentResponse.complete()
681 if (rejectedReason.Failed()) {
682 NotifyRequestDone(aRequest);
684 aRequest->RespondShowPayment(response.methodName(), responseData,
685 response.payerName(), response.payerEmail(),
686 response.payerPhone(),
687 std::move(rejectedReason));
688 break;
690 case IPCPaymentActionResponse::TIPCPaymentAbortActionResponse: {
691 const IPCPaymentAbortActionResponse& response = aResponse;
692 aRequest->RespondAbortPayment(response.isSucceeded());
693 NotifyRequestDone(aRequest);
694 break;
696 case IPCPaymentActionResponse::TIPCPaymentCompleteActionResponse: {
697 aRequest->RespondComplete();
698 NotifyRequestDone(aRequest);
699 break;
701 default: {
702 return NS_ERROR_FAILURE;
705 return NS_OK;
708 nsresult PaymentRequestManager::ChangeShippingAddress(
709 PaymentRequest* aRequest, const IPCPaymentAddress& aAddress) {
710 return aRequest->UpdateShippingAddress(
711 aAddress.country(), aAddress.addressLine(), aAddress.region(),
712 aAddress.regionCode(), aAddress.city(), aAddress.dependentLocality(),
713 aAddress.postalCode(), aAddress.sortingCode(), aAddress.organization(),
714 aAddress.recipient(), aAddress.phone());
717 nsresult PaymentRequestManager::ChangeShippingOption(PaymentRequest* aRequest,
718 const nsAString& aOption) {
719 return aRequest->UpdateShippingOption(aOption);
722 nsresult PaymentRequestManager::ChangePayerDetail(
723 PaymentRequest* aRequest, const nsAString& aPayerName,
724 const nsAString& aPayerEmail, const nsAString& aPayerPhone) {
725 MOZ_ASSERT(aRequest);
726 RefPtr<PaymentResponse> response = aRequest->GetResponse();
727 // ignoring the case call changePayerDetail during show().
728 if (!response) {
729 return NS_OK;
731 return response->UpdatePayerDetail(aPayerName, aPayerEmail, aPayerPhone);
734 nsresult PaymentRequestManager::ChangePaymentMethod(
735 PaymentRequest* aRequest, const nsAString& aMethodName,
736 const IPCMethodChangeDetails& aMethodDetails) {
737 NS_ENSURE_ARG_POINTER(aRequest);
738 ChangeDetails methodDetails;
739 ConvertMethodChangeDetails(aMethodDetails, methodDetails);
740 return aRequest->UpdatePaymentMethod(aMethodName, methodDetails);
743 } // namespace mozilla::dom