OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "modules/payments/PaymentRequest.h" | 5 #include "modules/payments/PaymentRequest.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <utility> | 8 #include <utility> |
9 #include "bindings/core/v8/ExceptionState.h" | 9 #include "bindings/core/v8/ExceptionState.h" |
10 #include "bindings/core/v8/ScriptPromiseResolver.h" | 10 #include "bindings/core/v8/ScriptPromiseResolver.h" |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
129 namespace { | 129 namespace { |
130 | 130 |
131 // If the website does not call complete() 60 seconds after show() has been | 131 // If the website does not call complete() 60 seconds after show() has been |
132 // resolved, then behave as if the website called complete("fail"). | 132 // resolved, then behave as if the website called complete("fail"). |
133 static const int kCompleteTimeoutSeconds = 60; | 133 static const int kCompleteTimeoutSeconds = 60; |
134 | 134 |
135 // Validates ShippingOption or PaymentItem, which happen to have identical | 135 // Validates ShippingOption or PaymentItem, which happen to have identical |
136 // fields, except for "id", which is present only in ShippingOption. | 136 // fields, except for "id", which is present only in ShippingOption. |
137 template <typename T> | 137 template <typename T> |
138 void ValidateShippingOptionOrPaymentItem(const T& item, | 138 void ValidateShippingOptionOrPaymentItem(const T& item, |
| 139 const String& item_name, |
| 140 ExecutionContext& execution_context, |
139 ExceptionState& exception_state) { | 141 ExceptionState& exception_state) { |
140 if (!item.hasLabel() || item.label().IsEmpty()) { | 142 DCHECK(item.hasLabel()); |
141 exception_state.ThrowTypeError("Item label required"); | 143 DCHECK(item.hasAmount()); |
| 144 DCHECK(item.amount().hasValue()); |
| 145 DCHECK(item.amount().hasCurrency()); |
| 146 |
| 147 String error_message; |
| 148 if (!PaymentsValidators::IsValidAmountFormat(item.amount().value(), item_name, |
| 149 &error_message)) { |
| 150 exception_state.ThrowTypeError(error_message); |
142 return; | 151 return; |
143 } | 152 } |
144 | 153 |
145 if (!item.hasAmount()) { | 154 if (item.label().IsEmpty()) { |
146 exception_state.ThrowTypeError("Currency amount required"); | 155 execution_context.AddConsoleMessage(ConsoleMessage::Create( |
| 156 kJSMessageSource, kErrorMessageLevel, |
| 157 "Empty " + item_name + " label may be confusing the user")); |
147 return; | 158 return; |
148 } | 159 } |
149 | 160 |
150 if (!item.amount().hasCurrency()) { | |
151 exception_state.ThrowTypeError("Currency code required"); | |
152 return; | |
153 } | |
154 | |
155 if (!item.amount().hasValue()) { | |
156 exception_state.ThrowTypeError("Currency value required"); | |
157 return; | |
158 } | |
159 | |
160 String error_message; | |
161 if (!PaymentsValidators::IsValidCurrencyCodeFormat( | 161 if (!PaymentsValidators::IsValidCurrencyCodeFormat( |
162 item.amount().currency(), item.amount().currencySystem(), | 162 item.amount().currency(), item.amount().currencySystem(), |
163 &error_message)) { | 163 &error_message)) { |
164 exception_state.ThrowTypeError(error_message); | 164 exception_state.ThrowTypeError(error_message); |
165 return; | 165 return; |
166 } | 166 } |
167 | |
168 if (!PaymentsValidators::IsValidAmountFormat(item.amount().value(), | |
169 &error_message)) { | |
170 exception_state.ThrowTypeError(error_message); | |
171 return; | |
172 } | |
173 } | 167 } |
174 | 168 |
175 void ValidateAndConvertDisplayItems(const HeapVector<PaymentItem>& input, | 169 void ValidateAndConvertDisplayItems(const HeapVector<PaymentItem>& input, |
| 170 const String& item_names, |
176 Vector<PaymentItemPtr>& output, | 171 Vector<PaymentItemPtr>& output, |
| 172 ExecutionContext& execution_context, |
177 ExceptionState& exception_state) { | 173 ExceptionState& exception_state) { |
178 for (const PaymentItem& item : input) { | 174 for (const PaymentItem& item : input) { |
179 ValidateShippingOptionOrPaymentItem(item, exception_state); | 175 ValidateShippingOptionOrPaymentItem(item, item_names, execution_context, |
| 176 exception_state); |
180 if (exception_state.HadException()) | 177 if (exception_state.HadException()) |
181 return; | 178 return; |
182 output.push_back(payments::mojom::blink::PaymentItem::From(item)); | 179 output.push_back(payments::mojom::blink::PaymentItem::From(item)); |
183 } | 180 } |
184 } | 181 } |
185 | 182 |
186 // Validates and converts |input| shipping options into |output|. Throws an | 183 // Validates and converts |input| shipping options into |output|. Throws an |
187 // exception if the data is not valid, except for duplicate identifiers, which | 184 // exception if the data is not valid, except for duplicate identifiers, which |
188 // returns an empty |output| instead of throwing an exception. There's no need | 185 // returns an empty |output| instead of throwing an exception. There's no need |
189 // to clear |output| when an exception is thrown, because the caller takes care | 186 // to clear |output| when an exception is thrown, because the caller takes care |
190 // of deleting |output|. | 187 // of deleting |output|. |
191 void ValidateAndConvertShippingOptions( | 188 void ValidateAndConvertShippingOptions( |
192 const HeapVector<PaymentShippingOption>& input, | 189 const HeapVector<PaymentShippingOption>& input, |
193 Vector<PaymentShippingOptionPtr>& output, | 190 Vector<PaymentShippingOptionPtr>& output, |
| 191 String& shipping_option_output, |
194 ExecutionContext& execution_context, | 192 ExecutionContext& execution_context, |
195 ExceptionState& exception_state) { | 193 ExceptionState& exception_state) { |
196 HashSet<String> unique_ids; | 194 HashSet<String> unique_ids; |
197 for (const PaymentShippingOption& option : input) { | 195 for (const PaymentShippingOption& option : input) { |
198 if (!option.hasId() || option.id().IsEmpty()) { | 196 ValidateShippingOptionOrPaymentItem(option, "shippingOptions", |
199 exception_state.ThrowTypeError("ShippingOption id required"); | 197 execution_context, exception_state); |
| 198 if (exception_state.HadException()) |
| 199 return; |
| 200 |
| 201 DCHECK(option.hasId()); |
| 202 if (option.id().IsEmpty()) { |
| 203 execution_context.AddConsoleMessage(ConsoleMessage::Create( |
| 204 kJSMessageSource, kWarningMessageLevel, |
| 205 "Empty shipping option ID may be hard to debug")); |
200 return; | 206 return; |
201 } | 207 } |
202 | 208 |
203 if (unique_ids.Contains(option.id())) { | 209 if (unique_ids.Contains(option.id())) { |
204 execution_context.AddConsoleMessage(ConsoleMessage::Create( | 210 execution_context.AddConsoleMessage(ConsoleMessage::Create( |
205 kJSMessageSource, kWarningMessageLevel, | 211 kJSMessageSource, kWarningMessageLevel, |
206 "Duplicate shipping option identifier '" + option.id() + | 212 "Duplicate shipping option identifier '" + option.id() + |
207 "' is treated as an invalid address indicator.")); | 213 "' is treated as an invalid address indicator.")); |
208 // Clear |output| instead of throwing an exception. | 214 // Clear |output| instead of throwing an exception. |
209 output.clear(); | 215 output.clear(); |
| 216 shipping_option_output = String(); |
210 return; | 217 return; |
211 } | 218 } |
212 | 219 |
| 220 if (option.selected()) |
| 221 shipping_option_output = option.id(); |
| 222 |
213 unique_ids.insert(option.id()); | 223 unique_ids.insert(option.id()); |
214 | 224 |
215 ValidateShippingOptionOrPaymentItem(option, exception_state); | |
216 if (exception_state.HadException()) | |
217 return; | |
218 | |
219 output.push_back( | 225 output.push_back( |
220 payments::mojom::blink::PaymentShippingOption::From(option)); | 226 payments::mojom::blink::PaymentShippingOption::From(option)); |
221 } | 227 } |
222 } | 228 } |
223 | 229 |
224 void ValidateAndConvertTotal(const PaymentItem& input, | 230 void ValidateAndConvertTotal(const PaymentItem& input, |
| 231 const String& item_name, |
225 PaymentItemPtr& output, | 232 PaymentItemPtr& output, |
| 233 ExecutionContext& execution_context, |
226 ExceptionState& exception_state) { | 234 ExceptionState& exception_state) { |
227 ValidateShippingOptionOrPaymentItem(input, exception_state); | 235 ValidateShippingOptionOrPaymentItem(input, item_name, execution_context, |
| 236 exception_state); |
228 if (exception_state.HadException()) | 237 if (exception_state.HadException()) |
229 return; | 238 return; |
230 | 239 |
231 if (input.amount().value()[0] == '-') { | 240 if (input.amount().value()[0] == '-') { |
232 exception_state.ThrowTypeError("Total amount value should be non-negative"); | 241 exception_state.ThrowTypeError("Total amount value should be non-negative"); |
233 return; | 242 return; |
234 } | 243 } |
235 | 244 |
236 output = payments::mojom::blink::PaymentItem::From(input); | 245 output = payments::mojom::blink::PaymentItem::From(input); |
237 } | 246 } |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
391 } | 400 } |
392 } | 401 } |
393 | 402 |
394 void StringifyAndParseMethodSpecificData( | 403 void StringifyAndParseMethodSpecificData( |
395 const Vector<String>& supported_methods, | 404 const Vector<String>& supported_methods, |
396 const ScriptValue& input, | 405 const ScriptValue& input, |
397 PaymentMethodDataPtr& output, | 406 PaymentMethodDataPtr& output, |
398 ExecutionContext& execution_context, | 407 ExecutionContext& execution_context, |
399 ExceptionState& exception_state) { | 408 ExceptionState& exception_state) { |
400 DCHECK(!input.IsEmpty()); | 409 DCHECK(!input.IsEmpty()); |
401 if (!input.V8Value()->IsObject() || input.V8Value()->IsArray()) { | 410 v8::Local<v8::String> value; |
402 exception_state.ThrowTypeError("Data should be a JSON-serializable object"); | 411 if (!input.V8Value()->IsObject() || |
| 412 !v8::JSON::Stringify(input.GetContext(), input.V8Value().As<v8::Object>()) |
| 413 .ToLocal(&value)) { |
| 414 exception_state.ThrowTypeError( |
| 415 "Payment method data should be a JSON-serializable object"); |
403 return; | 416 return; |
404 } | 417 } |
405 | 418 |
406 v8::Local<v8::String> value; | |
407 if (!v8::JSON::Stringify(input.GetContext(), input.V8Value().As<v8::Object>()) | |
408 .ToLocal(&value)) { | |
409 exception_state.ThrowTypeError( | |
410 "Unable to parse payment method specific data"); | |
411 return; | |
412 } | |
413 | |
414 output->stringified_data = | 419 output->stringified_data = |
415 V8StringToWebCoreString<String>(value, kDoNotExternalize); | 420 V8StringToWebCoreString<String>(value, kDoNotExternalize); |
416 | 421 |
417 // Serialize payment method specific data to be sent to the payment apps. The | 422 // Serialize payment method specific data to be sent to the payment apps. The |
418 // payment apps are responsible for validating and processing their method | 423 // payment apps are responsible for validating and processing their method |
419 // data asynchronously. Do not throw exceptions here. | 424 // data asynchronously. Do not throw exceptions here. |
420 if (supported_methods.Contains("https://android.com/pay") || | 425 if (supported_methods.Contains("https://android.com/pay") || |
421 supported_methods.Contains("https://google.com/pay")) { | 426 supported_methods.Contains("https://google.com/pay")) { |
422 SetAndroidPayMethodData(input, output, exception_state); | 427 SetAndroidPayMethodData(input, output, exception_state); |
423 if (exception_state.HadException()) | 428 if (exception_state.HadException()) |
424 exception_state.ClearException(); | 429 exception_state.ClearException(); |
425 } | 430 } |
426 if (RuntimeEnabledFeatures::paymentRequestBasicCardEnabled() && | 431 if (RuntimeEnabledFeatures::paymentRequestBasicCardEnabled() && |
427 supported_methods.Contains("basic-card")) { | 432 supported_methods.Contains("basic-card")) { |
428 SetBasicCardMethodData(input, output, execution_context, exception_state); | 433 SetBasicCardMethodData(input, output, execution_context, exception_state); |
429 if (exception_state.HadException()) | 434 if (exception_state.HadException()) |
430 exception_state.ClearException(); | 435 exception_state.ClearException(); |
431 } | 436 } |
432 } | 437 } |
433 | 438 |
434 void ValidateAndConvertPaymentDetailsModifiers( | 439 void ValidateAndConvertPaymentDetailsModifiers( |
435 const HeapVector<PaymentDetailsModifier>& input, | 440 const HeapVector<PaymentDetailsModifier>& input, |
436 Vector<PaymentDetailsModifierPtr>& output, | 441 Vector<PaymentDetailsModifierPtr>& output, |
437 ExecutionContext& execution_context, | 442 ExecutionContext& execution_context, |
438 ExceptionState& exception_state) { | 443 ExceptionState& exception_state) { |
439 if (input.IsEmpty()) { | |
440 exception_state.ThrowTypeError( | |
441 "Must specify at least one payment details modifier"); | |
442 return; | |
443 } | |
444 | |
445 for (const PaymentDetailsModifier& modifier : input) { | 444 for (const PaymentDetailsModifier& modifier : input) { |
446 output.push_back(payments::mojom::blink::PaymentDetailsModifier::New()); | 445 output.push_back(payments::mojom::blink::PaymentDetailsModifier::New()); |
447 if (modifier.hasTotal()) { | 446 if (modifier.hasTotal()) { |
448 ValidateAndConvertTotal(modifier.total(), output.back()->total, | 447 ValidateAndConvertTotal(modifier.total(), "modifier total", |
| 448 output.back()->total, execution_context, |
449 exception_state); | 449 exception_state); |
450 if (exception_state.HadException()) | 450 if (exception_state.HadException()) |
451 return; | 451 return; |
452 } | 452 } |
453 | 453 |
454 if (modifier.hasAdditionalDisplayItems()) { | 454 if (modifier.hasAdditionalDisplayItems()) { |
455 ValidateAndConvertDisplayItems(modifier.additionalDisplayItems(), | 455 ValidateAndConvertDisplayItems(modifier.additionalDisplayItems(), |
| 456 "additional display items in modifier", |
456 output.back()->additional_display_items, | 457 output.back()->additional_display_items, |
457 exception_state); | 458 execution_context, exception_state); |
458 if (exception_state.HadException()) | 459 if (exception_state.HadException()) |
459 return; | 460 return; |
460 } | 461 } |
461 | 462 |
462 if (modifier.supportedMethods().IsEmpty()) { | 463 if (modifier.supportedMethods().IsEmpty()) { |
463 exception_state.ThrowTypeError( | 464 exception_state.ThrowTypeError( |
464 "Must specify at least one payment method identifier"); | 465 "Must specify at least one payment method identifier"); |
465 return; | 466 return; |
466 } | 467 } |
467 | 468 |
468 output.back()->method_data = | 469 output.back()->method_data = |
469 payments::mojom::blink::PaymentMethodData::New(); | 470 payments::mojom::blink::PaymentMethodData::New(); |
470 output.back()->method_data->supported_methods = modifier.supportedMethods(); | 471 output.back()->method_data->supported_methods = modifier.supportedMethods(); |
471 | 472 |
472 if (modifier.hasData() && !modifier.data().IsEmpty()) { | 473 if (modifier.hasData() && !modifier.data().IsEmpty()) { |
473 StringifyAndParseMethodSpecificData( | 474 StringifyAndParseMethodSpecificData( |
474 modifier.supportedMethods(), modifier.data(), | 475 modifier.supportedMethods(), modifier.data(), |
475 output.back()->method_data, execution_context, exception_state); | 476 output.back()->method_data, execution_context, exception_state); |
476 } else { | 477 } else { |
477 output.back()->method_data->stringified_data = ""; | 478 output.back()->method_data->stringified_data = ""; |
478 } | 479 } |
479 } | 480 } |
480 } | 481 } |
481 | 482 |
482 String GetSelectedShippingOption( | |
483 const Vector<PaymentShippingOptionPtr>& shipping_options) { | |
484 String result; | |
485 for (const PaymentShippingOptionPtr& shipping_option : shipping_options) { | |
486 if (shipping_option->selected) | |
487 result = shipping_option->id; | |
488 } | |
489 return result; | |
490 } | |
491 | |
492 void ValidateAndConvertPaymentDetailsBase(const PaymentDetailsBase& input, | 483 void ValidateAndConvertPaymentDetailsBase(const PaymentDetailsBase& input, |
493 bool request_shipping, | |
494 PaymentDetailsPtr& output, | 484 PaymentDetailsPtr& output, |
495 String& shipping_option_output, | 485 String& shipping_option_output, |
496 ExecutionContext& execution_context, | 486 ExecutionContext& execution_context, |
497 ExceptionState& exception_state) { | 487 ExceptionState& exception_state) { |
498 if (input.hasDisplayItems()) { | 488 if (input.hasDisplayItems()) { |
499 ValidateAndConvertDisplayItems(input.displayItems(), output->display_items, | 489 ValidateAndConvertDisplayItems(input.displayItems(), "display items", |
| 490 output->display_items, execution_context, |
500 exception_state); | 491 exception_state); |
501 if (exception_state.HadException()) | 492 if (exception_state.HadException()) |
502 return; | 493 return; |
503 } | 494 } |
504 | 495 |
505 if (input.hasShippingOptions() && request_shipping) { | 496 if (input.hasShippingOptions()) { |
506 ValidateAndConvertShippingOptions(input.shippingOptions(), | 497 ValidateAndConvertShippingOptions( |
507 output->shipping_options, | 498 input.shippingOptions(), output->shipping_options, |
508 execution_context, exception_state); | 499 shipping_option_output, execution_context, exception_state); |
509 if (exception_state.HadException()) | 500 if (exception_state.HadException()) |
510 return; | 501 return; |
| 502 } else { |
| 503 shipping_option_output = String(); |
511 } | 504 } |
512 | 505 |
513 shipping_option_output = GetSelectedShippingOption(output->shipping_options); | |
514 | |
515 if (input.hasModifiers()) { | 506 if (input.hasModifiers()) { |
516 ValidateAndConvertPaymentDetailsModifiers( | 507 ValidateAndConvertPaymentDetailsModifiers( |
517 input.modifiers(), output->modifiers, execution_context, | 508 input.modifiers(), output->modifiers, execution_context, |
518 exception_state); | 509 exception_state); |
519 if (exception_state.HadException()) | 510 if (exception_state.HadException()) |
520 return; | 511 return; |
521 } | 512 } |
522 } | 513 } |
523 | 514 |
524 void ValidateAndConvertPaymentDetailsInit(const PaymentDetailsInit& input, | 515 void ValidateAndConvertPaymentDetailsInit(const PaymentDetailsInit& input, |
525 bool request_shipping, | |
526 PaymentDetailsPtr& output, | 516 PaymentDetailsPtr& output, |
527 String& shipping_option_output, | 517 String& shipping_option_output, |
528 ExecutionContext& execution_context, | 518 ExecutionContext& execution_context, |
529 ExceptionState& exception_state) { | 519 ExceptionState& exception_state) { |
530 ValidateAndConvertPaymentDetailsBase(input, request_shipping, output, | 520 DCHECK(input.hasTotal()); |
531 shipping_option_output, | 521 ValidateAndConvertTotal(input.total(), "total", output->total, |
| 522 execution_context, exception_state); |
| 523 if (exception_state.HadException()) |
| 524 return; |
| 525 |
| 526 ValidateAndConvertPaymentDetailsBase(input, output, shipping_option_output, |
532 execution_context, exception_state); | 527 execution_context, exception_state); |
533 if (exception_state.HadException()) | 528 if (exception_state.HadException()) |
534 return; | 529 return; |
535 | |
536 if (!input.hasTotal()) { | |
537 exception_state.ThrowTypeError("Must specify total"); | |
538 return; | |
539 } | |
540 | |
541 if (input.hasId()) | |
542 output->id = input.id(); | |
543 else | |
544 output->id = CreateCanonicalUUIDString(); | |
545 | |
546 ValidateAndConvertTotal(input.total(), output->total, exception_state); | |
547 } | 530 } |
548 | 531 |
549 void ValidateAndConvertPaymentDetailsUpdate(const PaymentDetailsUpdate& input, | 532 void ValidateAndConvertPaymentDetailsUpdate(const PaymentDetailsUpdate& input, |
550 bool request_shipping, | |
551 PaymentDetailsPtr& output, | 533 PaymentDetailsPtr& output, |
552 String& shipping_option_output, | 534 String& shipping_option_output, |
553 ExecutionContext& execution_context, | 535 ExecutionContext& execution_context, |
554 ExceptionState& exception_state) { | 536 ExceptionState& exception_state) { |
555 ValidateAndConvertPaymentDetailsBase(input, request_shipping, output, | 537 ValidateAndConvertPaymentDetailsBase(input, output, shipping_option_output, |
556 shipping_option_output, | |
557 execution_context, exception_state); | 538 execution_context, exception_state); |
558 if (exception_state.HadException()) | 539 if (exception_state.HadException()) |
559 return; | 540 return; |
560 | 541 |
561 if (input.hasTotal()) { | 542 if (input.hasTotal()) { |
562 ValidateAndConvertTotal(input.total(), output->total, exception_state); | 543 ValidateAndConvertTotal(input.total(), "total", output->total, |
| 544 execution_context, exception_state); |
563 if (exception_state.HadException()) | 545 if (exception_state.HadException()) |
564 return; | 546 return; |
565 } | 547 } |
566 | 548 |
567 if (input.hasError() && !input.error().IsNull()) { | 549 if (input.hasError() && !input.error().IsNull()) { |
568 String error_message; | 550 String error_message; |
569 if (!PaymentsValidators::IsValidErrorMsgFormat(input.error(), | 551 if (!PaymentsValidators::IsValidErrorMsgFormat(input.error(), |
570 &error_message)) { | 552 &error_message)) { |
571 exception_state.ThrowTypeError(error_message); | 553 exception_state.ThrowTypeError(error_message); |
572 return; | 554 return; |
573 } | 555 } |
574 output->error = input.error(); | 556 output->error = input.error(); |
575 } else { | 557 } else { |
576 output->error = ""; | 558 output->error = ""; |
577 } | 559 } |
578 } | 560 } |
579 | 561 |
580 void ValidateAndConvertPaymentMethodData( | 562 void ValidateAndConvertPaymentMethodData( |
581 const HeapVector<PaymentMethodData>& input, | 563 const HeapVector<PaymentMethodData>& input, |
582 Vector<payments::mojom::blink::PaymentMethodDataPtr>& output, | 564 Vector<payments::mojom::blink::PaymentMethodDataPtr>& output, |
583 ExecutionContext& execution_context, | 565 ExecutionContext& execution_context, |
584 ExceptionState& exception_state) { | 566 ExceptionState& exception_state) { |
585 if (input.IsEmpty()) { | 567 if (input.IsEmpty()) { |
586 exception_state.ThrowTypeError( | 568 exception_state.ThrowTypeError("At least one payment method is required"); |
587 "Must specify at least one payment method identifier"); | |
588 return; | 569 return; |
589 } | 570 } |
590 | 571 |
591 for (const PaymentMethodData payment_method_data : input) { | 572 for (const PaymentMethodData payment_method_data : input) { |
592 if (payment_method_data.supportedMethods().IsEmpty()) { | 573 if (payment_method_data.supportedMethods().IsEmpty()) { |
593 exception_state.ThrowTypeError( | 574 exception_state.ThrowTypeError( |
594 "Must specify at least one payment method identifier"); | 575 "Each payment method needs to include at least one payment method " |
| 576 "identifier"); |
595 return; | 577 return; |
596 } | 578 } |
597 | 579 |
598 output.push_back(payments::mojom::blink::PaymentMethodData::New()); | 580 output.push_back(payments::mojom::blink::PaymentMethodData::New()); |
599 output.back()->supported_methods = payment_method_data.supportedMethods(); | 581 output.back()->supported_methods = payment_method_data.supportedMethods(); |
600 | 582 |
601 if (payment_method_data.hasData() && | 583 if (payment_method_data.hasData() && |
602 !payment_method_data.data().IsEmpty()) { | 584 !payment_method_data.data().IsEmpty()) { |
603 StringifyAndParseMethodSpecificData( | 585 StringifyAndParseMethodSpecificData( |
604 payment_method_data.supportedMethods(), payment_method_data.data(), | 586 payment_method_data.supportedMethods(), payment_method_data.data(), |
605 output.back(), execution_context, exception_state); | 587 output.back(), execution_context, exception_state); |
606 } else { | 588 } else { |
607 output.back()->stringified_data = ""; | 589 output.back()->stringified_data = ""; |
608 } | 590 } |
609 } | 591 } |
610 } | 592 } |
611 | 593 |
612 String GetValidShippingType(const String& shipping_type) { | |
613 static const char* const kValidValues[] = { | |
614 "shipping", "delivery", "pickup", | |
615 }; | |
616 for (size_t i = 0; i < arraysize(kValidValues); i++) { | |
617 if (shipping_type == kValidValues[i]) | |
618 return shipping_type; | |
619 } | |
620 return kValidValues[0]; | |
621 } | |
622 | |
623 bool AllowedToUsePaymentRequest(const Frame* frame) { | 594 bool AllowedToUsePaymentRequest(const Frame* frame) { |
624 // To determine whether a Document object |document| is allowed to use the | 595 // To determine whether a Document object |document| is allowed to use the |
625 // feature indicated by attribute name |allowpaymentrequest|, run these steps: | 596 // feature indicated by attribute name |allowpaymentrequest|, run these steps: |
626 | 597 |
627 // 1. If |document| has no browsing context, then return false. | 598 // 1. If |document| has no browsing context, then return false. |
628 if (!frame) | 599 if (!frame) |
629 return false; | 600 return false; |
630 | 601 |
631 if (!RuntimeEnabledFeatures::featurePolicyEnabled()) { | 602 if (!RuntimeEnabledFeatures::featurePolicyEnabled()) { |
632 // 2. If |document|'s browsing context is a top-level browsing context, then | 603 // 2. If |document|'s browsing context is a top-level browsing context, then |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
806 if (exception_state.HadException()) { | 777 if (exception_state.HadException()) { |
807 show_resolver_->Reject( | 778 show_resolver_->Reject( |
808 DOMException::Create(kSyntaxError, exception_state.Message())); | 779 DOMException::Create(kSyntaxError, exception_state.Message())); |
809 ClearResolversAndCloseMojoConnection(); | 780 ClearResolversAndCloseMojoConnection(); |
810 return; | 781 return; |
811 } | 782 } |
812 | 783 |
813 PaymentDetailsPtr validated_details = | 784 PaymentDetailsPtr validated_details = |
814 payments::mojom::blink::PaymentDetails::New(); | 785 payments::mojom::blink::PaymentDetails::New(); |
815 ValidateAndConvertPaymentDetailsUpdate( | 786 ValidateAndConvertPaymentDetailsUpdate( |
816 details, options_.requestShipping(), validated_details, shipping_option_, | 787 details, validated_details, shipping_option_, *GetExecutionContext(), |
817 *GetExecutionContext(), exception_state); | 788 exception_state); |
818 if (exception_state.HadException()) { | 789 if (exception_state.HadException()) { |
819 show_resolver_->Reject( | 790 show_resolver_->Reject( |
820 DOMException::Create(kSyntaxError, exception_state.Message())); | 791 DOMException::Create(kSyntaxError, exception_state.Message())); |
821 ClearResolversAndCloseMojoConnection(); | 792 ClearResolversAndCloseMojoConnection(); |
822 return; | 793 return; |
823 } | 794 } |
824 | 795 |
| 796 if (!options_.requestShipping()) |
| 797 validated_details->shipping_options.clear(); |
| 798 |
825 payment_provider_->UpdateWith(std::move(validated_details)); | 799 payment_provider_->UpdateWith(std::move(validated_details)); |
826 } | 800 } |
827 | 801 |
828 void PaymentRequest::OnUpdatePaymentDetailsFailure(const String& error) { | 802 void PaymentRequest::OnUpdatePaymentDetailsFailure(const String& error) { |
829 if (show_resolver_) | 803 if (show_resolver_) |
830 show_resolver_->Reject(DOMException::Create(kAbortError, error)); | 804 show_resolver_->Reject(DOMException::Create(kAbortError, error)); |
831 if (complete_resolver_) | 805 if (complete_resolver_) |
832 complete_resolver_->Reject(DOMException::Create(kAbortError, error)); | 806 complete_resolver_->Reject(DOMException::Create(kAbortError, error)); |
833 ClearResolversAndCloseMojoConnection(); | 807 ClearResolversAndCloseMojoConnection(); |
834 } | 808 } |
(...skipping 19 matching lines...) Expand all Loading... |
854 const PaymentDetailsInit& details, | 828 const PaymentDetailsInit& details, |
855 const PaymentOptions& options, | 829 const PaymentOptions& options, |
856 ExceptionState& exception_state) | 830 ExceptionState& exception_state) |
857 : ContextLifecycleObserver(execution_context), | 831 : ContextLifecycleObserver(execution_context), |
858 options_(options), | 832 options_(options), |
859 client_binding_(this), | 833 client_binding_(this), |
860 complete_timer_( | 834 complete_timer_( |
861 TaskRunnerHelper::Get(TaskType::kMiscPlatformAPI, GetFrame()), | 835 TaskRunnerHelper::Get(TaskType::kMiscPlatformAPI, GetFrame()), |
862 this, | 836 this, |
863 &PaymentRequest::OnCompleteTimeout) { | 837 &PaymentRequest::OnCompleteTimeout) { |
864 Vector<payments::mojom::blink::PaymentMethodDataPtr> validated_method_data; | |
865 ValidateAndConvertPaymentMethodData(method_data, validated_method_data, | |
866 *GetExecutionContext(), exception_state); | |
867 if (exception_state.HadException()) | |
868 return; | |
869 | |
870 if (!GetExecutionContext()->IsSecureContext()) { | 838 if (!GetExecutionContext()->IsSecureContext()) { |
871 exception_state.ThrowSecurityError("Must be in a secure context"); | 839 exception_state.ThrowSecurityError("Must be in a secure context"); |
872 return; | 840 return; |
873 } | 841 } |
874 | 842 |
875 if (!AllowedToUsePaymentRequest(GetFrame())) { | 843 if (!AllowedToUsePaymentRequest(GetFrame())) { |
876 exception_state.ThrowSecurityError( | 844 exception_state.ThrowSecurityError( |
877 "Must be in a top-level browsing context or an iframe needs to specify " | 845 "Must be in a top-level browsing context or an iframe needs to specify " |
878 "'allowpaymentrequest' explicitly"); | 846 "'allowpaymentrequest' explicitly"); |
879 return; | 847 return; |
880 } | 848 } |
881 | 849 |
882 PaymentDetailsPtr validated_details = | 850 PaymentDetailsPtr validated_details = |
883 payments::mojom::blink::PaymentDetails::New(); | 851 payments::mojom::blink::PaymentDetails::New(); |
884 ValidateAndConvertPaymentDetailsInit(details, options_.requestShipping(), | 852 validated_details->id = id_ = |
885 validated_details, shipping_option_, | 853 details.hasId() ? details.id() : CreateCanonicalUUIDString(); |
886 *GetExecutionContext(), exception_state); | 854 |
| 855 Vector<payments::mojom::blink::PaymentMethodDataPtr> validated_method_data; |
| 856 ValidateAndConvertPaymentMethodData(method_data, validated_method_data, |
| 857 *GetExecutionContext(), exception_state); |
887 if (exception_state.HadException()) | 858 if (exception_state.HadException()) |
888 return; | 859 return; |
889 | 860 |
890 id_ = validated_details->id; | 861 ValidateAndConvertPaymentDetailsInit(details, validated_details, |
| 862 shipping_option_, *GetExecutionContext(), |
| 863 exception_state); |
| 864 if (exception_state.HadException()) |
| 865 return; |
891 | 866 |
892 if (options_.requestShipping()) | 867 if (options_.requestShipping()) |
893 shipping_type_ = GetValidShippingType(options_.shippingType()); | 868 shipping_type_ = options_.shippingType(); |
| 869 else |
| 870 validated_details->shipping_options.clear(); |
| 871 |
| 872 DCHECK(shipping_type_.IsNull() || shipping_type_ == "shipping" || |
| 873 shipping_type_ == "delivery" || shipping_type_ == "pickup"); |
894 | 874 |
895 GetFrame()->GetInterfaceProvider()->GetInterface( | 875 GetFrame()->GetInterfaceProvider()->GetInterface( |
896 mojo::MakeRequest(&payment_provider_)); | 876 mojo::MakeRequest(&payment_provider_)); |
897 payment_provider_.set_connection_error_handler(ConvertToBaseCallback( | 877 payment_provider_.set_connection_error_handler(ConvertToBaseCallback( |
898 WTF::Bind(&PaymentRequest::OnError, WrapWeakPersistent(this), | 878 WTF::Bind(&PaymentRequest::OnError, WrapWeakPersistent(this), |
899 PaymentErrorReason::UNKNOWN))); | 879 PaymentErrorReason::UNKNOWN))); |
900 payment_provider_->Init( | 880 payment_provider_->Init( |
901 client_binding_.CreateInterfacePtrAndBind(), | 881 client_binding_.CreateInterfacePtrAndBind(), |
902 std::move(validated_method_data), std::move(validated_details), | 882 std::move(validated_method_data), std::move(validated_details), |
903 payments::mojom::blink::PaymentOptions::From(options_)); | 883 payments::mojom::blink::PaymentOptions::From(options_)); |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1089 complete_resolver_.Clear(); | 1069 complete_resolver_.Clear(); |
1090 show_resolver_.Clear(); | 1070 show_resolver_.Clear(); |
1091 abort_resolver_.Clear(); | 1071 abort_resolver_.Clear(); |
1092 can_make_payment_resolver_.Clear(); | 1072 can_make_payment_resolver_.Clear(); |
1093 if (client_binding_.is_bound()) | 1073 if (client_binding_.is_bound()) |
1094 client_binding_.Close(); | 1074 client_binding_.Close(); |
1095 payment_provider_.reset(); | 1075 payment_provider_.reset(); |
1096 } | 1076 } |
1097 | 1077 |
1098 } // namespace blink | 1078 } // namespace blink |
OLD | NEW |