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/. */
6
7 #include "mozilla/ClearOnShutdown.h"
8 #include "mozilla/dom/PaymentRequestChild.h"
9 #include "mozilla/dom/BrowserChild.h"
10 #include "nsContentUtils.h"
11 #include "nsString.h"
12 #include "nsIPrincipal.h"
13 #include "PaymentRequestManager.h"
14 #include "PaymentRequestUtils.h"
15 #include "PaymentResponse.h"
16
17 namespace mozilla {
18 namespace dom {
19 namespace {
20
21 /*
22 * Following Convert* functions are used for convert PaymentRequest structs
23 * to transferable structs for IPC.
24 */
ConvertMethodData(JSContext * aCx,const PaymentMethodData & aMethodData,IPCPaymentMethodData & aIPCMethodData,ErrorResult & aRv)25 void ConvertMethodData(JSContext* aCx, const PaymentMethodData& aMethodData,
26 IPCPaymentMethodData& aIPCMethodData, ErrorResult& aRv) {
27 MOZ_ASSERT(aCx);
28 // Convert JSObject to a serialized string
29 nsAutoString serializedData;
30 if (aMethodData.mData.WasPassed()) {
31 JS::RootedObject object(aCx, aMethodData.mData.Value());
32 if (NS_WARN_IF(
33 NS_FAILED(SerializeFromJSObject(aCx, object, serializedData)))) {
34 aRv.ThrowTypeError(
35 "The PaymentMethodData.data must be a serializable object");
36 return;
37 }
38 }
39 aIPCMethodData =
40 IPCPaymentMethodData(aMethodData.mSupportedMethods, serializedData);
41 }
42
ConvertCurrencyAmount(const PaymentCurrencyAmount & aAmount,IPCPaymentCurrencyAmount & aIPCCurrencyAmount)43 void ConvertCurrencyAmount(const PaymentCurrencyAmount& aAmount,
44 IPCPaymentCurrencyAmount& aIPCCurrencyAmount) {
45 aIPCCurrencyAmount =
46 IPCPaymentCurrencyAmount(aAmount.mCurrency, aAmount.mValue);
47 }
48
ConvertItem(const PaymentItem & aItem,IPCPaymentItem & aIPCItem)49 void ConvertItem(const PaymentItem& aItem, IPCPaymentItem& aIPCItem) {
50 IPCPaymentCurrencyAmount amount;
51 ConvertCurrencyAmount(aItem.mAmount, amount);
52 aIPCItem = IPCPaymentItem(aItem.mLabel, amount, aItem.mPending);
53 }
54
ConvertModifier(JSContext * aCx,const PaymentDetailsModifier & aModifier,IPCPaymentDetailsModifier & aIPCModifier,ErrorResult & aRv)55 void ConvertModifier(JSContext* aCx, const PaymentDetailsModifier& aModifier,
56 IPCPaymentDetailsModifier& aIPCModifier,
57 ErrorResult& aRv) {
58 MOZ_ASSERT(aCx);
59 // Convert JSObject to a serialized string
60 nsAutoString serializedData;
61 if (aModifier.mData.WasPassed()) {
62 JS::RootedObject object(aCx, aModifier.mData.Value());
63 if (NS_WARN_IF(
64 NS_FAILED(SerializeFromJSObject(aCx, object, serializedData)))) {
65 aRv.ThrowTypeError("The Modifier.data must be a serializable object");
66 return;
67 }
68 }
69
70 IPCPaymentItem total;
71 if (aModifier.mTotal.WasPassed()) {
72 ConvertItem(aModifier.mTotal.Value(), total);
73 }
74
75 nsTArray<IPCPaymentItem> additionalDisplayItems;
76 if (aModifier.mAdditionalDisplayItems.WasPassed()) {
77 for (const PaymentItem& item : aModifier.mAdditionalDisplayItems.Value()) {
78 IPCPaymentItem displayItem;
79 ConvertItem(item, displayItem);
80 additionalDisplayItems.AppendElement(displayItem);
81 }
82 }
83 aIPCModifier = IPCPaymentDetailsModifier(
84 aModifier.mSupportedMethods, total, additionalDisplayItems,
85 serializedData, aModifier.mAdditionalDisplayItems.WasPassed());
86 }
87
ConvertShippingOption(const PaymentShippingOption & aOption,IPCPaymentShippingOption & aIPCOption)88 void ConvertShippingOption(const PaymentShippingOption& aOption,
89 IPCPaymentShippingOption& aIPCOption) {
90 IPCPaymentCurrencyAmount amount;
91 ConvertCurrencyAmount(aOption.mAmount, amount);
92 aIPCOption = IPCPaymentShippingOption(aOption.mId, aOption.mLabel, amount,
93 aOption.mSelected);
94 }
95
ConvertDetailsBase(JSContext * aCx,const PaymentDetailsBase & aDetails,nsTArray<IPCPaymentItem> & aDisplayItems,nsTArray<IPCPaymentShippingOption> & aShippingOptions,nsTArray<IPCPaymentDetailsModifier> & aModifiers,bool aRequestShipping,ErrorResult & aRv)96 void ConvertDetailsBase(JSContext* aCx, const PaymentDetailsBase& aDetails,
97 nsTArray<IPCPaymentItem>& aDisplayItems,
98 nsTArray<IPCPaymentShippingOption>& aShippingOptions,
99 nsTArray<IPCPaymentDetailsModifier>& aModifiers,
100 bool aRequestShipping, ErrorResult& aRv) {
101 MOZ_ASSERT(aCx);
102 if (aDetails.mDisplayItems.WasPassed()) {
103 for (const PaymentItem& item : aDetails.mDisplayItems.Value()) {
104 IPCPaymentItem displayItem;
105 ConvertItem(item, displayItem);
106 aDisplayItems.AppendElement(displayItem);
107 }
108 }
109 if (aRequestShipping && aDetails.mShippingOptions.WasPassed()) {
110 for (const PaymentShippingOption& option :
111 aDetails.mShippingOptions.Value()) {
112 IPCPaymentShippingOption shippingOption;
113 ConvertShippingOption(option, shippingOption);
114 aShippingOptions.AppendElement(shippingOption);
115 }
116 }
117 if (aDetails.mModifiers.WasPassed()) {
118 for (const PaymentDetailsModifier& modifier : aDetails.mModifiers.Value()) {
119 IPCPaymentDetailsModifier detailsModifier;
120 ConvertModifier(aCx, modifier, detailsModifier, aRv);
121 if (aRv.Failed()) {
122 return;
123 }
124 aModifiers.AppendElement(detailsModifier);
125 }
126 }
127 }
128
ConvertDetailsInit(JSContext * aCx,const PaymentDetailsInit & aDetails,IPCPaymentDetails & aIPCDetails,bool aRequestShipping,ErrorResult & aRv)129 void ConvertDetailsInit(JSContext* aCx, const PaymentDetailsInit& aDetails,
130 IPCPaymentDetails& aIPCDetails, bool aRequestShipping,
131 ErrorResult& aRv) {
132 MOZ_ASSERT(aCx);
133 // Convert PaymentDetailsBase members
134 nsTArray<IPCPaymentItem> displayItems;
135 nsTArray<IPCPaymentShippingOption> shippingOptions;
136 nsTArray<IPCPaymentDetailsModifier> modifiers;
137 ConvertDetailsBase(aCx, aDetails, displayItems, shippingOptions, modifiers,
138 aRequestShipping, aRv);
139 if (aRv.Failed()) {
140 return;
141 }
142
143 // Convert |id|
144 nsAutoString id;
145 if (aDetails.mId.WasPassed()) {
146 id = aDetails.mId.Value();
147 }
148
149 // Convert required |total|
150 IPCPaymentItem total;
151 ConvertItem(aDetails.mTotal, total);
152
153 aIPCDetails =
154 IPCPaymentDetails(id, total, displayItems, shippingOptions, modifiers,
155 EmptyString(), // error message
156 EmptyString(), // shippingAddressErrors
157 EmptyString(), // payerErrors
158 EmptyString()); // paymentMethodErrors
159 }
160
ConvertDetailsUpdate(JSContext * aCx,const PaymentDetailsUpdate & aDetails,IPCPaymentDetails & aIPCDetails,bool aRequestShipping,ErrorResult & aRv)161 void ConvertDetailsUpdate(JSContext* aCx, const PaymentDetailsUpdate& aDetails,
162 IPCPaymentDetails& aIPCDetails, bool aRequestShipping,
163 ErrorResult& aRv) {
164 MOZ_ASSERT(aCx);
165 // Convert PaymentDetailsBase members
166 nsTArray<IPCPaymentItem> displayItems;
167 nsTArray<IPCPaymentShippingOption> shippingOptions;
168 nsTArray<IPCPaymentDetailsModifier> modifiers;
169 ConvertDetailsBase(aCx, aDetails, displayItems, shippingOptions, modifiers,
170 aRequestShipping, aRv);
171 if (aRv.Failed()) {
172 return;
173 }
174
175 // Convert required |total|
176 IPCPaymentItem total;
177 if (aDetails.mTotal.WasPassed()) {
178 ConvertItem(aDetails.mTotal.Value(), total);
179 }
180
181 // Convert |error|
182 nsAutoString error;
183 if (aDetails.mError.WasPassed()) {
184 error = aDetails.mError.Value();
185 }
186
187 nsAutoString shippingAddressErrors;
188 if (aDetails.mShippingAddressErrors.WasPassed()) {
189 if (!aDetails.mShippingAddressErrors.Value().ToJSON(
190 shippingAddressErrors)) {
191 aRv.ThrowTypeError("The ShippingAddressErrors can not be serailized");
192 return;
193 }
194 }
195
196 nsAutoString payerErrors;
197 if (aDetails.mPayerErrors.WasPassed()) {
198 if (!aDetails.mPayerErrors.Value().ToJSON(payerErrors)) {
199 aRv.ThrowTypeError("The PayerErrors can not be serialized");
200 return;
201 }
202 }
203
204 nsAutoString paymentMethodErrors;
205 if (aDetails.mPaymentMethodErrors.WasPassed()) {
206 JS::RootedObject object(aCx, aDetails.mPaymentMethodErrors.Value());
207 if (NS_WARN_IF(NS_FAILED(
208 SerializeFromJSObject(aCx, object, paymentMethodErrors)))) {
209 aRv.ThrowTypeError("The PaymentMethodErrors can not be serialized");
210 return;
211 }
212 }
213
214 aIPCDetails = IPCPaymentDetails(EmptyString(), // id
215 total, displayItems, shippingOptions,
216 modifiers, error, shippingAddressErrors,
217 payerErrors, paymentMethodErrors);
218 }
219
ConvertOptions(const PaymentOptions & aOptions,IPCPaymentOptions & aIPCOption)220 void ConvertOptions(const PaymentOptions& aOptions,
221 IPCPaymentOptions& aIPCOption) {
222 NS_ConvertASCIItoUTF16 shippingType(
223 PaymentShippingTypeValues::GetString(aOptions.mShippingType));
224 aIPCOption =
225 IPCPaymentOptions(aOptions.mRequestPayerName, aOptions.mRequestPayerEmail,
226 aOptions.mRequestPayerPhone, aOptions.mRequestShipping,
227 aOptions.mRequestBillingAddress, shippingType);
228 }
229
ConvertResponseData(const IPCPaymentResponseData & aIPCData,ResponseData & aData)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;
239 }
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;
263 }
264 default: {
265 break;
266 }
267 }
268 }
269
ConvertMethodChangeDetails(const IPCMethodChangeDetails & aIPCDetails,ChangeDetails & aDetails)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;
279 }
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;
302 }
303 default: {
304 break;
305 }
306 }
307 }
308 } // end of namespace
309
310 /* PaymentRequestManager */
311
312 StaticRefPtr<PaymentRequestManager> gPaymentManager;
313 const char kSupportedRegionsPref[] = "dom.payments.request.supportedRegions";
314
SupportedRegionsPrefChangedCallback(const char * aPrefName,void * aRetval)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));
319
320 nsAutoString supportedRegions;
321 Preferences::GetString(aPrefName, supportedRegions);
322 retval->Clear();
323 for (const nsAString& each : supportedRegions.Split(',')) {
324 retval->AppendElement(each);
325 }
326 }
327
PaymentRequestManager()328 PaymentRequestManager::PaymentRequestManager() {
329 Preferences::RegisterCallbackAndCall(SupportedRegionsPrefChangedCallback,
330 kSupportedRegionsPref,
331 &this->mSupportedRegions);
332 }
333
~PaymentRequestManager()334 PaymentRequestManager::~PaymentRequestManager() {
335 MOZ_ASSERT(mActivePayments.Count() == 0);
336 Preferences::UnregisterCallback(SupportedRegionsPrefChangedCallback,
337 kSupportedRegionsPref,
338 &this->mSupportedRegions);
339 mSupportedRegions.Clear();
340 }
341
IsRegionSupported(const nsAString & region) const342 bool PaymentRequestManager::IsRegionSupported(const nsAString& region) const {
343 return mSupportedRegions.Contains(region);
344 }
345
GetPaymentChild(PaymentRequest * aRequest)346 PaymentRequestChild* PaymentRequestManager::GetPaymentChild(
347 PaymentRequest* aRequest) {
348 MOZ_ASSERT(aRequest);
349
350 if (PaymentRequestChild* child = aRequest->GetIPC()) {
351 return child;
352 }
353
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);
360
361 PaymentRequestChild* paymentChild = new PaymentRequestChild(aRequest);
362 browserChild->SendPPaymentRequestConstructor(paymentChild);
363
364 return paymentChild;
365 }
366
SendRequestPayment(PaymentRequest * aRequest,const IPCPaymentActionRequest & aAction,bool aResponseExpected)367 nsresult PaymentRequestManager::SendRequestPayment(
368 PaymentRequest* aRequest, const IPCPaymentActionRequest& aAction,
369 bool aResponseExpected) {
370 PaymentRequestChild* requestChild = GetPaymentChild(aRequest);
371 // bug 1580496, ignoring the case that requestChild is nullptr. It could be
372 // nullptr while the corresponding nsPIDOMWindowInner is nullptr.
373 if (NS_WARN_IF(!requestChild)) {
374 return NS_ERROR_FAILURE;
375 }
376 nsresult rv = requestChild->RequestPayment(aAction);
377 if (NS_WARN_IF(NS_FAILED(rv))) {
378 return rv;
379 }
380
381 if (aResponseExpected) {
382 auto count = mActivePayments.LookupForAdd(aRequest);
383 if (count) {
384 count.Data()++;
385 } else {
386 count.OrInsert([]() { return 1; });
387 }
388 }
389 return NS_OK;
390 }
391
NotifyRequestDone(PaymentRequest * aRequest)392 void PaymentRequestManager::NotifyRequestDone(PaymentRequest* aRequest) {
393 auto entry = mActivePayments.Lookup(aRequest);
394 MOZ_ASSERT(entry);
395 MOZ_ASSERT(entry.Data() > 0);
396
397 uint32_t count = --entry.Data();
398 if (count == 0) {
399 entry.Remove();
400 }
401 }
402
RequestIPCOver(PaymentRequest * aRequest)403 void PaymentRequestManager::RequestIPCOver(PaymentRequest* aRequest) {
404 // This must only be called from ActorDestroy or if we're sure we won't
405 // receive any more IPC for aRequest.
406 mActivePayments.Remove(aRequest);
407 }
408
GetSingleton()409 already_AddRefed<PaymentRequestManager> PaymentRequestManager::GetSingleton() {
410 if (!gPaymentManager) {
411 gPaymentManager = new PaymentRequestManager();
412 ClearOnShutdown(&gPaymentManager);
413 }
414 RefPtr<PaymentRequestManager> manager = gPaymentManager;
415 return manager.forget();
416 }
417
GetSelectedShippingOption(const PaymentDetailsBase & aDetails,nsAString & aOption)418 void GetSelectedShippingOption(const PaymentDetailsBase& aDetails,
419 nsAString& aOption) {
420 SetDOMStringToNull(aOption);
421 if (!aDetails.mShippingOptions.WasPassed()) {
422 return;
423 }
424
425 const Sequence<PaymentShippingOption>& shippingOptions =
426 aDetails.mShippingOptions.Value();
427 for (const PaymentShippingOption& shippingOption : shippingOptions) {
428 // set aOption to last selected option's ID
429 if (shippingOption.mSelected) {
430 aOption = shippingOption.mId;
431 }
432 }
433 }
434
CreatePayment(JSContext * aCx,nsPIDOMWindowInner * aWindow,nsIPrincipal * aTopLevelPrincipal,const Sequence<PaymentMethodData> & aMethodData,const PaymentDetailsInit & aDetails,const PaymentOptions & aOptions,PaymentRequest ** aRequest,ErrorResult & aRv)435 void PaymentRequestManager::CreatePayment(
436 JSContext* aCx, nsPIDOMWindowInner* aWindow,
437 nsIPrincipal* aTopLevelPrincipal,
438 const Sequence<PaymentMethodData>& aMethodData,
439 const PaymentDetailsInit& aDetails, const PaymentOptions& aOptions,
440 PaymentRequest** aRequest, ErrorResult& aRv) {
441 MOZ_ASSERT(NS_IsMainThread());
442 MOZ_ASSERT(aCx);
443 MOZ_ASSERT(aRequest);
444 MOZ_ASSERT(aTopLevelPrincipal);
445 *aRequest = nullptr;
446
447 RefPtr<PaymentRequest> request =
448 PaymentRequest::CreatePaymentRequest(aWindow, aRv);
449 if (aRv.Failed()) {
450 return;
451 }
452 request->SetOptions(aOptions);
453 /*
454 * Set request's |mId| to details.id if details.id exists.
455 * Otherwise, set |mId| to internal id.
456 */
457 nsAutoString requestId;
458 if (aDetails.mId.WasPassed() && !aDetails.mId.Value().IsEmpty()) {
459 requestId = aDetails.mId.Value();
460 } else {
461 request->GetInternalId(requestId);
462 }
463 request->SetId(requestId);
464
465 /*
466 * Set request's |mShippingType| and |mShippingOption| if shipping is
467 * required. Set request's mShippingOption to last selected option's ID if
468 * details.shippingOptions exists, otherwise set it as null.
469 */
470 nsAutoString shippingOption;
471 SetDOMStringToNull(shippingOption);
472 if (aOptions.mRequestShipping) {
473 request->ShippingWasRequested();
474 request->SetShippingType(
475 Nullable<PaymentShippingType>(aOptions.mShippingType));
476 GetSelectedShippingOption(aDetails, shippingOption);
477 }
478 request->SetShippingOption(shippingOption);
479
480 nsAutoString internalId;
481 request->GetInternalId(internalId);
482
483 nsTArray<IPCPaymentMethodData> methodData;
484 for (const PaymentMethodData& data : aMethodData) {
485 IPCPaymentMethodData ipcMethodData;
486 ConvertMethodData(aCx, data, ipcMethodData, aRv);
487 if (aRv.Failed()) {
488 return;
489 }
490 methodData.AppendElement(ipcMethodData);
491 }
492
493 IPCPaymentDetails details;
494 ConvertDetailsInit(aCx, aDetails, details, aOptions.mRequestShipping, aRv);
495 if (aRv.Failed()) {
496 return;
497 }
498
499 IPCPaymentOptions options;
500 ConvertOptions(aOptions, options);
501
502 nsCOMPtr<nsPIDOMWindowOuter> outerWindow = aWindow->GetOuterWindow();
503 MOZ_ASSERT(outerWindow);
504 if (nsCOMPtr<nsPIDOMWindowOuter> topOuterWindow =
505 outerWindow->GetInProcessTop()) {
506 outerWindow = topOuterWindow;
507 }
508 uint64_t topOuterWindowId = outerWindow->WindowID();
509
510 IPCPaymentCreateActionRequest action(topOuterWindowId, internalId,
511 aTopLevelPrincipal, methodData, details,
512 options, shippingOption);
513
514 if (NS_WARN_IF(NS_FAILED(SendRequestPayment(request, action, false)))) {
515 aRv.ThrowUnknownError("Internal error sending payment request");
516 return;
517 }
518 request.forget(aRequest);
519 }
520
CanMakePayment(PaymentRequest * aRequest,ErrorResult & aRv)521 void PaymentRequestManager::CanMakePayment(PaymentRequest* aRequest,
522 ErrorResult& aRv) {
523 nsAutoString requestId;
524 aRequest->GetInternalId(requestId);
525 IPCPaymentCanMakeActionRequest action(requestId);
526 if (NS_WARN_IF(NS_FAILED(SendRequestPayment(aRequest, action)))) {
527 aRv.ThrowUnknownError("Internal error sending payment request");
528 }
529 }
530
ShowPayment(PaymentRequest * aRequest,ErrorResult & aRv)531 void PaymentRequestManager::ShowPayment(PaymentRequest* aRequest,
532 ErrorResult& aRv) {
533 nsAutoString requestId;
534 aRequest->GetInternalId(requestId);
535 IPCPaymentShowActionRequest action(requestId, aRequest->IsUpdating());
536 if (NS_WARN_IF(NS_FAILED(SendRequestPayment(aRequest, action)))) {
537 aRv.ThrowUnknownError("Internal error sending payment request");
538 }
539 }
540
AbortPayment(PaymentRequest * aRequest,ErrorResult & aRv)541 void PaymentRequestManager::AbortPayment(PaymentRequest* aRequest,
542 ErrorResult& aRv) {
543 nsAutoString requestId;
544 aRequest->GetInternalId(requestId);
545 IPCPaymentAbortActionRequest action(requestId);
546 if (NS_WARN_IF(NS_FAILED(SendRequestPayment(aRequest, action)))) {
547 aRv.ThrowUnknownError("Internal error sending payment request");
548 }
549 }
550
CompletePayment(PaymentRequest * aRequest,const PaymentComplete & aComplete,ErrorResult & aRv,bool aTimedOut)551 void PaymentRequestManager::CompletePayment(PaymentRequest* aRequest,
552 const PaymentComplete& aComplete,
553 ErrorResult& aRv, bool aTimedOut) {
554 nsString completeStatusString(NS_LITERAL_STRING("unknown"));
555 if (aTimedOut) {
556 completeStatusString.AssignLiteral("timeout");
557 } else {
558 completeStatusString.AssignASCII(
559 PaymentCompleteValues::GetString(aComplete));
560 }
561
562 nsAutoString requestId;
563 aRequest->GetInternalId(requestId);
564 IPCPaymentCompleteActionRequest action(requestId, completeStatusString);
565 if (NS_WARN_IF(NS_FAILED(SendRequestPayment(aRequest, action, false)))) {
566 aRv.ThrowUnknownError("Internal error sending payment request");
567 }
568 }
569
UpdatePayment(JSContext * aCx,PaymentRequest * aRequest,const PaymentDetailsUpdate & aDetails,bool aRequestShipping,ErrorResult & aRv)570 void PaymentRequestManager::UpdatePayment(JSContext* aCx,
571 PaymentRequest* aRequest,
572 const PaymentDetailsUpdate& aDetails,
573 bool aRequestShipping,
574 ErrorResult& aRv) {
575 MOZ_ASSERT(aCx);
576 IPCPaymentDetails details;
577 ConvertDetailsUpdate(aCx, aDetails, details, aRequestShipping, aRv);
578 if (aRv.Failed()) {
579 return;
580 }
581
582 nsAutoString shippingOption;
583 SetDOMStringToNull(shippingOption);
584 if (aRequestShipping) {
585 GetSelectedShippingOption(aDetails, shippingOption);
586 aRequest->SetShippingOption(shippingOption);
587 }
588
589 nsAutoString requestId;
590 aRequest->GetInternalId(requestId);
591 IPCPaymentUpdateActionRequest action(requestId, details, shippingOption);
592 if (NS_WARN_IF(NS_FAILED(SendRequestPayment(aRequest, action, false)))) {
593 aRv.ThrowUnknownError("Internal error sending payment request");
594 }
595 }
596
ClosePayment(PaymentRequest * aRequest)597 nsresult PaymentRequestManager::ClosePayment(PaymentRequest* aRequest) {
598 // for the case, the payment request is waiting for response from user.
599 if (auto entry = mActivePayments.Lookup(aRequest)) {
600 NotifyRequestDone(aRequest);
601 }
602 nsAutoString requestId;
603 aRequest->GetInternalId(requestId);
604 IPCPaymentCloseActionRequest action(requestId);
605 return SendRequestPayment(aRequest, action, false);
606 }
607
RetryPayment(JSContext * aCx,PaymentRequest * aRequest,const PaymentValidationErrors & aErrors,ErrorResult & aRv)608 void PaymentRequestManager::RetryPayment(JSContext* aCx,
609 PaymentRequest* aRequest,
610 const PaymentValidationErrors& aErrors,
611 ErrorResult& aRv) {
612 MOZ_ASSERT(aCx);
613 MOZ_ASSERT(aRequest);
614
615 nsAutoString requestId;
616 aRequest->GetInternalId(requestId);
617
618 nsAutoString error;
619 if (aErrors.mError.WasPassed()) {
620 error = aErrors.mError.Value();
621 }
622
623 nsAutoString shippingAddressErrors;
624 if (aErrors.mShippingAddress.WasPassed()) {
625 if (!aErrors.mShippingAddress.Value().ToJSON(shippingAddressErrors)) {
626 aRv.ThrowTypeError("The ShippingAddressErrors can not be serialized");
627 return;
628 }
629 }
630
631 nsAutoString payerErrors;
632 if (aErrors.mPayer.WasPassed()) {
633 if (!aErrors.mPayer.Value().ToJSON(payerErrors)) {
634 aRv.ThrowTypeError("The PayerErrors can not be serialized");
635 return;
636 }
637 }
638
639 nsAutoString paymentMethodErrors;
640 if (aErrors.mPaymentMethod.WasPassed()) {
641 JS::RootedObject object(aCx, aErrors.mPaymentMethod.Value());
642 if (NS_WARN_IF(NS_FAILED(
643 SerializeFromJSObject(aCx, object, paymentMethodErrors)))) {
644 aRv.ThrowTypeError("The PaymentMethodErrors can not be serialized");
645 return;
646 }
647 }
648 IPCPaymentRetryActionRequest action(requestId, error, payerErrors,
649 paymentMethodErrors,
650 shippingAddressErrors);
651 if (NS_WARN_IF(NS_FAILED(SendRequestPayment(aRequest, action)))) {
652 aRv.ThrowUnknownError("Internal error sending payment request");
653 }
654 }
655
RespondPayment(PaymentRequest * aRequest,const IPCPaymentActionResponse & aResponse)656 nsresult PaymentRequestManager::RespondPayment(
657 PaymentRequest* aRequest, const IPCPaymentActionResponse& aResponse) {
658 switch (aResponse.type()) {
659 case IPCPaymentActionResponse::TIPCPaymentCanMakeActionResponse: {
660 const IPCPaymentCanMakeActionResponse& response = aResponse;
661 aRequest->RespondCanMakePayment(response.result());
662 NotifyRequestDone(aRequest);
663 break;
664 }
665 case IPCPaymentActionResponse::TIPCPaymentShowActionResponse: {
666 const IPCPaymentShowActionResponse& response = aResponse;
667 ErrorResult rejectedReason;
668 ResponseData responseData;
669 ConvertResponseData(response.data(), responseData);
670 switch (response.status()) {
671 case nsIPaymentActionResponse::PAYMENT_ACCEPTED: {
672 break;
673 }
674 case nsIPaymentActionResponse::PAYMENT_REJECTED: {
675 rejectedReason.ThrowAbortError("The user rejected the payment");
676 break;
677 }
678 case nsIPaymentActionResponse::PAYMENT_NOTSUPPORTED: {
679 rejectedReason.ThrowNotSupportedError("No supported payment method");
680 break;
681 }
682 default: {
683 rejectedReason.ThrowUnknownError("Unknown response for the payment");
684 break;
685 }
686 }
687 // If PaymentActionResponse is not PAYMENT_ACCEPTED, no need to keep the
688 // PaymentRequestChild instance. Otherwise, keep PaymentRequestChild for
689 // merchants call PaymentResponse.complete()
690 if (rejectedReason.Failed()) {
691 NotifyRequestDone(aRequest);
692 }
693 aRequest->RespondShowPayment(response.methodName(), responseData,
694 response.payerName(), response.payerEmail(),
695 response.payerPhone(),
696 std::move(rejectedReason));
697 break;
698 }
699 case IPCPaymentActionResponse::TIPCPaymentAbortActionResponse: {
700 const IPCPaymentAbortActionResponse& response = aResponse;
701 aRequest->RespondAbortPayment(response.isSucceeded());
702 NotifyRequestDone(aRequest);
703 break;
704 }
705 case IPCPaymentActionResponse::TIPCPaymentCompleteActionResponse: {
706 aRequest->RespondComplete();
707 NotifyRequestDone(aRequest);
708 break;
709 }
710 default: {
711 return NS_ERROR_FAILURE;
712 }
713 }
714 return NS_OK;
715 }
716
ChangeShippingAddress(PaymentRequest * aRequest,const IPCPaymentAddress & aAddress)717 nsresult PaymentRequestManager::ChangeShippingAddress(
718 PaymentRequest* aRequest, const IPCPaymentAddress& aAddress) {
719 return aRequest->UpdateShippingAddress(
720 aAddress.country(), aAddress.addressLine(), aAddress.region(),
721 aAddress.regionCode(), aAddress.city(), aAddress.dependentLocality(),
722 aAddress.postalCode(), aAddress.sortingCode(), aAddress.organization(),
723 aAddress.recipient(), aAddress.phone());
724 }
725
ChangeShippingOption(PaymentRequest * aRequest,const nsAString & aOption)726 nsresult PaymentRequestManager::ChangeShippingOption(PaymentRequest* aRequest,
727 const nsAString& aOption) {
728 return aRequest->UpdateShippingOption(aOption);
729 }
730
ChangePayerDetail(PaymentRequest * aRequest,const nsAString & aPayerName,const nsAString & aPayerEmail,const nsAString & aPayerPhone)731 nsresult PaymentRequestManager::ChangePayerDetail(
732 PaymentRequest* aRequest, const nsAString& aPayerName,
733 const nsAString& aPayerEmail, const nsAString& aPayerPhone) {
734 MOZ_ASSERT(aRequest);
735 RefPtr<PaymentResponse> response = aRequest->GetResponse();
736 // ignoring the case call changePayerDetail during show().
737 if (!response) {
738 return NS_OK;
739 }
740 return response->UpdatePayerDetail(aPayerName, aPayerEmail, aPayerPhone);
741 }
742
ChangePaymentMethod(PaymentRequest * aRequest,const nsAString & aMethodName,const IPCMethodChangeDetails & aMethodDetails)743 nsresult PaymentRequestManager::ChangePaymentMethod(
744 PaymentRequest* aRequest, const nsAString& aMethodName,
745 const IPCMethodChangeDetails& aMethodDetails) {
746 NS_ENSURE_ARG_POINTER(aRequest);
747 ChangeDetails methodDetails;
748 ConvertMethodChangeDetails(aMethodDetails, methodDetails);
749 return aRequest->UpdatePaymentMethod(aMethodName, methodDetails);
750 }
751
752 } // end of namespace dom
753 } // end of namespace mozilla
754