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( |
156 ConsoleMessage::Create(kJSMessageSource, kErrorMessageLevel, | |
Marijn Kruisselbrink
2017/05/03 23:10:59
nit: would it make sense for this message to expla
please use gerrit instead
2017/05/04 15:17:15
Done.
| |
157 "Empty " + item_name + " label is discouraged")); | |
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( | |
204 ConsoleMessage::Create(kJSMessageSource, kWarningMessageLevel, | |
205 "Empty shipping option ID is discouraged")); | |
Marijn Kruisselbrink
2017/05/03 23:10:59
nit: same here, why is an empty ID a problem? If I
please use gerrit instead
2017/05/04 15:17:15
Done.
| |
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() || input.V8Value()->IsArray() || |
haraken
2017/05/04 09:47:51
Is it worth checking IsArray? To check whether the
please use gerrit instead
2017/05/04 15:17:15
Good point, the spec does prohibit arrays. Added a
| |
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 SetAndroidPayMethodData(input, output, exception_state); | 426 SetAndroidPayMethodData(input, output, exception_state); |
422 if (exception_state.HadException()) | 427 if (exception_state.HadException()) |
423 exception_state.ClearException(); | 428 exception_state.ClearException(); |
424 } | 429 } |
425 if (RuntimeEnabledFeatures::paymentRequestBasicCardEnabled() && | 430 if (RuntimeEnabledFeatures::paymentRequestBasicCardEnabled() && |
426 supported_methods.Contains("basic-card")) { | 431 supported_methods.Contains("basic-card")) { |
427 SetBasicCardMethodData(input, output, execution_context, exception_state); | 432 SetBasicCardMethodData(input, output, execution_context, exception_state); |
428 if (exception_state.HadException()) | 433 if (exception_state.HadException()) |
429 exception_state.ClearException(); | 434 exception_state.ClearException(); |
430 } | 435 } |
431 } | 436 } |
432 | 437 |
433 void ValidateAndConvertPaymentDetailsModifiers( | 438 void ValidateAndConvertPaymentDetailsModifiers( |
434 const HeapVector<PaymentDetailsModifier>& input, | 439 const HeapVector<PaymentDetailsModifier>& input, |
435 Vector<PaymentDetailsModifierPtr>& output, | 440 Vector<PaymentDetailsModifierPtr>& output, |
436 ExecutionContext& execution_context, | 441 ExecutionContext& execution_context, |
437 ExceptionState& exception_state) { | 442 ExceptionState& exception_state) { |
438 if (input.IsEmpty()) { | |
439 exception_state.ThrowTypeError( | |
440 "Must specify at least one payment details modifier"); | |
441 return; | |
442 } | |
443 | |
444 for (const PaymentDetailsModifier& modifier : input) { | 443 for (const PaymentDetailsModifier& modifier : input) { |
445 output.push_back(payments::mojom::blink::PaymentDetailsModifier::New()); | 444 output.push_back(payments::mojom::blink::PaymentDetailsModifier::New()); |
446 if (modifier.hasTotal()) { | 445 if (modifier.hasTotal()) { |
447 ValidateAndConvertTotal(modifier.total(), output.back()->total, | 446 ValidateAndConvertTotal(modifier.total(), "modifier total", |
447 output.back()->total, execution_context, | |
448 exception_state); | 448 exception_state); |
449 if (exception_state.HadException()) | 449 if (exception_state.HadException()) |
450 return; | 450 return; |
451 } | 451 } |
452 | 452 |
453 if (modifier.hasAdditionalDisplayItems()) { | 453 if (modifier.hasAdditionalDisplayItems()) { |
454 ValidateAndConvertDisplayItems(modifier.additionalDisplayItems(), | 454 ValidateAndConvertDisplayItems(modifier.additionalDisplayItems(), |
455 "additional display items in modifier", | |
455 output.back()->additional_display_items, | 456 output.back()->additional_display_items, |
456 exception_state); | 457 execution_context, exception_state); |
457 if (exception_state.HadException()) | 458 if (exception_state.HadException()) |
458 return; | 459 return; |
459 } | 460 } |
460 | 461 |
461 if (modifier.supportedMethods().IsEmpty()) { | 462 if (modifier.supportedMethods().IsEmpty()) { |
462 exception_state.ThrowTypeError( | 463 exception_state.ThrowTypeError( |
463 "Must specify at least one payment method identifier"); | 464 "Must specify at least one payment method identifier"); |
464 return; | 465 return; |
465 } | 466 } |
466 | 467 |
467 output.back()->method_data = | 468 output.back()->method_data = |
468 payments::mojom::blink::PaymentMethodData::New(); | 469 payments::mojom::blink::PaymentMethodData::New(); |
469 output.back()->method_data->supported_methods = modifier.supportedMethods(); | 470 output.back()->method_data->supported_methods = modifier.supportedMethods(); |
470 | 471 |
471 if (modifier.hasData() && !modifier.data().IsEmpty()) { | 472 if (modifier.hasData() && !modifier.data().IsEmpty()) { |
472 StringifyAndParseMethodSpecificData( | 473 StringifyAndParseMethodSpecificData( |
473 modifier.supportedMethods(), modifier.data(), | 474 modifier.supportedMethods(), modifier.data(), |
474 output.back()->method_data, execution_context, exception_state); | 475 output.back()->method_data, execution_context, exception_state); |
475 } else { | 476 } else { |
476 output.back()->method_data->stringified_data = ""; | 477 output.back()->method_data->stringified_data = ""; |
477 } | 478 } |
478 } | 479 } |
479 } | 480 } |
480 | 481 |
481 String GetSelectedShippingOption( | |
482 const Vector<PaymentShippingOptionPtr>& shipping_options) { | |
483 String result; | |
484 for (const PaymentShippingOptionPtr& shipping_option : shipping_options) { | |
485 if (shipping_option->selected) | |
486 result = shipping_option->id; | |
487 } | |
488 return result; | |
489 } | |
490 | |
491 void ValidateAndConvertPaymentDetailsBase(const PaymentDetailsBase& input, | 482 void ValidateAndConvertPaymentDetailsBase(const PaymentDetailsBase& input, |
492 bool request_shipping, | |
493 PaymentDetailsPtr& output, | 483 PaymentDetailsPtr& output, |
494 String& shipping_option_output, | 484 String& shipping_option_output, |
495 ExecutionContext& execution_context, | 485 ExecutionContext& execution_context, |
496 ExceptionState& exception_state) { | 486 ExceptionState& exception_state) { |
497 if (input.hasDisplayItems()) { | 487 if (input.hasDisplayItems()) { |
498 ValidateAndConvertDisplayItems(input.displayItems(), output->display_items, | 488 ValidateAndConvertDisplayItems(input.displayItems(), "display items", |
489 output->display_items, execution_context, | |
499 exception_state); | 490 exception_state); |
500 if (exception_state.HadException()) | 491 if (exception_state.HadException()) |
501 return; | 492 return; |
502 } | 493 } |
503 | 494 |
504 if (input.hasShippingOptions() && request_shipping) { | 495 if (input.hasShippingOptions()) { |
505 ValidateAndConvertShippingOptions(input.shippingOptions(), | 496 ValidateAndConvertShippingOptions( |
506 output->shipping_options, | 497 input.shippingOptions(), output->shipping_options, |
507 execution_context, exception_state); | 498 shipping_option_output, execution_context, exception_state); |
508 if (exception_state.HadException()) | 499 if (exception_state.HadException()) |
509 return; | 500 return; |
501 } else { | |
502 shipping_option_output = String(); | |
510 } | 503 } |
511 | 504 |
512 shipping_option_output = GetSelectedShippingOption(output->shipping_options); | |
513 | |
514 if (input.hasModifiers()) { | 505 if (input.hasModifiers()) { |
515 ValidateAndConvertPaymentDetailsModifiers( | 506 ValidateAndConvertPaymentDetailsModifiers( |
516 input.modifiers(), output->modifiers, execution_context, | 507 input.modifiers(), output->modifiers, execution_context, |
517 exception_state); | 508 exception_state); |
518 if (exception_state.HadException()) | 509 if (exception_state.HadException()) |
519 return; | 510 return; |
520 } | 511 } |
521 } | 512 } |
522 | 513 |
523 void ValidateAndConvertPaymentDetailsInit(const PaymentDetailsInit& input, | 514 void ValidateAndConvertPaymentDetailsInit(const PaymentDetailsInit& input, |
524 bool request_shipping, | |
525 PaymentDetailsPtr& output, | 515 PaymentDetailsPtr& output, |
526 String& shipping_option_output, | 516 String& shipping_option_output, |
527 ExecutionContext& execution_context, | 517 ExecutionContext& execution_context, |
528 ExceptionState& exception_state) { | 518 ExceptionState& exception_state) { |
529 ValidateAndConvertPaymentDetailsBase(input, request_shipping, output, | 519 DCHECK(input.hasTotal()); |
530 shipping_option_output, | 520 ValidateAndConvertTotal(input.total(), "total", output->total, |
521 execution_context, exception_state); | |
522 if (exception_state.HadException()) | |
523 return; | |
524 | |
525 ValidateAndConvertPaymentDetailsBase(input, output, shipping_option_output, | |
531 execution_context, exception_state); | 526 execution_context, exception_state); |
532 if (exception_state.HadException()) | 527 if (exception_state.HadException()) |
533 return; | 528 return; |
534 | |
535 if (!input.hasTotal()) { | |
536 exception_state.ThrowTypeError("Must specify total"); | |
537 return; | |
538 } | |
539 | |
540 if (input.hasId()) | |
541 output->id = input.id(); | |
542 else | |
543 output->id = CreateCanonicalUUIDString(); | |
544 | |
545 ValidateAndConvertTotal(input.total(), output->total, exception_state); | |
546 } | 529 } |
547 | 530 |
548 void ValidateAndConvertPaymentDetailsUpdate(const PaymentDetailsUpdate& input, | 531 void ValidateAndConvertPaymentDetailsUpdate(const PaymentDetailsUpdate& input, |
549 bool request_shipping, | |
550 PaymentDetailsPtr& output, | 532 PaymentDetailsPtr& output, |
551 String& shipping_option_output, | 533 String& shipping_option_output, |
552 ExecutionContext& execution_context, | 534 ExecutionContext& execution_context, |
553 ExceptionState& exception_state) { | 535 ExceptionState& exception_state) { |
554 ValidateAndConvertPaymentDetailsBase(input, request_shipping, output, | 536 ValidateAndConvertPaymentDetailsBase(input, output, shipping_option_output, |
555 shipping_option_output, | |
556 execution_context, exception_state); | 537 execution_context, exception_state); |
557 if (exception_state.HadException()) | 538 if (exception_state.HadException()) |
558 return; | 539 return; |
559 | 540 |
560 if (input.hasTotal()) { | 541 if (input.hasTotal()) { |
561 ValidateAndConvertTotal(input.total(), output->total, exception_state); | 542 ValidateAndConvertTotal(input.total(), "total", output->total, |
543 execution_context, exception_state); | |
562 if (exception_state.HadException()) | 544 if (exception_state.HadException()) |
563 return; | 545 return; |
564 } | 546 } |
565 | 547 |
566 if (input.hasError() && !input.error().IsNull()) { | 548 if (input.hasError() && !input.error().IsNull()) { |
567 String error_message; | 549 String error_message; |
568 if (!PaymentsValidators::IsValidErrorMsgFormat(input.error(), | 550 if (!PaymentsValidators::IsValidErrorMsgFormat(input.error(), |
569 &error_message)) { | 551 &error_message)) { |
570 exception_state.ThrowTypeError(error_message); | 552 exception_state.ThrowTypeError(error_message); |
571 return; | 553 return; |
572 } | 554 } |
573 output->error = input.error(); | 555 output->error = input.error(); |
574 } else { | 556 } else { |
575 output->error = ""; | 557 output->error = ""; |
576 } | 558 } |
577 } | 559 } |
578 | 560 |
579 void ValidateAndConvertPaymentMethodData( | 561 void ValidateAndConvertPaymentMethodData( |
580 const HeapVector<PaymentMethodData>& input, | 562 const HeapVector<PaymentMethodData>& input, |
581 Vector<payments::mojom::blink::PaymentMethodDataPtr>& output, | 563 Vector<payments::mojom::blink::PaymentMethodDataPtr>& output, |
582 ExecutionContext& execution_context, | 564 ExecutionContext& execution_context, |
583 ExceptionState& exception_state) { | 565 ExceptionState& exception_state) { |
584 if (input.IsEmpty()) { | 566 if (input.IsEmpty()) { |
585 exception_state.ThrowTypeError( | 567 exception_state.ThrowTypeError("At least one payment method is required"); |
586 "Must specify at least one payment method identifier"); | |
587 return; | 568 return; |
588 } | 569 } |
589 | 570 |
590 for (const PaymentMethodData payment_method_data : input) { | 571 for (const PaymentMethodData payment_method_data : input) { |
591 if (payment_method_data.supportedMethods().IsEmpty()) { | 572 if (payment_method_data.supportedMethods().IsEmpty()) { |
592 exception_state.ThrowTypeError( | 573 exception_state.ThrowTypeError( |
593 "Must specify at least one payment method identifier"); | 574 "Each payment method needs to include at least one payment method " |
575 "identifier"); | |
594 return; | 576 return; |
595 } | 577 } |
596 | 578 |
597 output.push_back(payments::mojom::blink::PaymentMethodData::New()); | 579 output.push_back(payments::mojom::blink::PaymentMethodData::New()); |
598 output.back()->supported_methods = payment_method_data.supportedMethods(); | 580 output.back()->supported_methods = payment_method_data.supportedMethods(); |
599 | 581 |
600 if (payment_method_data.hasData() && | 582 if (payment_method_data.hasData() && |
601 !payment_method_data.data().IsEmpty()) { | 583 !payment_method_data.data().IsEmpty()) { |
602 StringifyAndParseMethodSpecificData( | 584 StringifyAndParseMethodSpecificData( |
603 payment_method_data.supportedMethods(), payment_method_data.data(), | 585 payment_method_data.supportedMethods(), payment_method_data.data(), |
604 output.back(), execution_context, exception_state); | 586 output.back(), execution_context, exception_state); |
605 } else { | 587 } else { |
606 output.back()->stringified_data = ""; | 588 output.back()->stringified_data = ""; |
607 } | 589 } |
608 } | 590 } |
609 } | 591 } |
610 | 592 |
611 String GetValidShippingType(const String& shipping_type) { | |
612 static const char* const kValidValues[] = { | |
613 "shipping", "delivery", "pickup", | |
614 }; | |
615 for (size_t i = 0; i < arraysize(kValidValues); i++) { | |
616 if (shipping_type == kValidValues[i]) | |
617 return shipping_type; | |
618 } | |
619 return kValidValues[0]; | |
620 } | |
621 | |
622 bool AllowedToUsePaymentRequest(const Frame* frame) { | 593 bool AllowedToUsePaymentRequest(const Frame* frame) { |
623 // To determine whether a Document object |document| is allowed to use the | 594 // To determine whether a Document object |document| is allowed to use the |
624 // feature indicated by attribute name |allowpaymentrequest|, run these steps: | 595 // feature indicated by attribute name |allowpaymentrequest|, run these steps: |
625 | 596 |
626 // 1. If |document| has no browsing context, then return false. | 597 // 1. If |document| has no browsing context, then return false. |
627 if (!frame) | 598 if (!frame) |
628 return false; | 599 return false; |
629 | 600 |
630 if (!RuntimeEnabledFeatures::featurePolicyEnabled()) { | 601 if (!RuntimeEnabledFeatures::featurePolicyEnabled()) { |
631 // 2. If |document|'s browsing context is a top-level browsing context, then | 602 // 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... | |
805 if (exception_state.HadException()) { | 776 if (exception_state.HadException()) { |
806 show_resolver_->Reject( | 777 show_resolver_->Reject( |
807 DOMException::Create(kSyntaxError, exception_state.Message())); | 778 DOMException::Create(kSyntaxError, exception_state.Message())); |
808 ClearResolversAndCloseMojoConnection(); | 779 ClearResolversAndCloseMojoConnection(); |
809 return; | 780 return; |
810 } | 781 } |
811 | 782 |
812 PaymentDetailsPtr validated_details = | 783 PaymentDetailsPtr validated_details = |
813 payments::mojom::blink::PaymentDetails::New(); | 784 payments::mojom::blink::PaymentDetails::New(); |
814 ValidateAndConvertPaymentDetailsUpdate( | 785 ValidateAndConvertPaymentDetailsUpdate( |
815 details, options_.requestShipping(), validated_details, shipping_option_, | 786 details, validated_details, shipping_option_, *GetExecutionContext(), |
816 *GetExecutionContext(), exception_state); | 787 exception_state); |
817 if (exception_state.HadException()) { | 788 if (exception_state.HadException()) { |
818 show_resolver_->Reject( | 789 show_resolver_->Reject( |
819 DOMException::Create(kSyntaxError, exception_state.Message())); | 790 DOMException::Create(kSyntaxError, exception_state.Message())); |
820 ClearResolversAndCloseMojoConnection(); | 791 ClearResolversAndCloseMojoConnection(); |
821 return; | 792 return; |
822 } | 793 } |
823 | 794 |
795 if (!options_.requestShipping()) | |
796 validated_details->shipping_options.clear(); | |
797 | |
824 payment_provider_->UpdateWith(std::move(validated_details)); | 798 payment_provider_->UpdateWith(std::move(validated_details)); |
825 } | 799 } |
826 | 800 |
827 void PaymentRequest::OnUpdatePaymentDetailsFailure(const String& error) { | 801 void PaymentRequest::OnUpdatePaymentDetailsFailure(const String& error) { |
828 if (show_resolver_) | 802 if (show_resolver_) |
829 show_resolver_->Reject(DOMException::Create(kAbortError, error)); | 803 show_resolver_->Reject(DOMException::Create(kAbortError, error)); |
830 if (complete_resolver_) | 804 if (complete_resolver_) |
831 complete_resolver_->Reject(DOMException::Create(kAbortError, error)); | 805 complete_resolver_->Reject(DOMException::Create(kAbortError, error)); |
832 ClearResolversAndCloseMojoConnection(); | 806 ClearResolversAndCloseMojoConnection(); |
833 } | 807 } |
(...skipping 19 matching lines...) Expand all Loading... | |
853 const PaymentDetailsInit& details, | 827 const PaymentDetailsInit& details, |
854 const PaymentOptions& options, | 828 const PaymentOptions& options, |
855 ExceptionState& exception_state) | 829 ExceptionState& exception_state) |
856 : ContextLifecycleObserver(execution_context), | 830 : ContextLifecycleObserver(execution_context), |
857 options_(options), | 831 options_(options), |
858 client_binding_(this), | 832 client_binding_(this), |
859 complete_timer_( | 833 complete_timer_( |
860 TaskRunnerHelper::Get(TaskType::kMiscPlatformAPI, GetFrame()), | 834 TaskRunnerHelper::Get(TaskType::kMiscPlatformAPI, GetFrame()), |
861 this, | 835 this, |
862 &PaymentRequest::OnCompleteTimeout) { | 836 &PaymentRequest::OnCompleteTimeout) { |
863 Vector<payments::mojom::blink::PaymentMethodDataPtr> validated_method_data; | |
864 ValidateAndConvertPaymentMethodData(method_data, validated_method_data, | |
865 *GetExecutionContext(), exception_state); | |
866 if (exception_state.HadException()) | |
867 return; | |
868 | |
869 if (!GetExecutionContext()->IsSecureContext()) { | 837 if (!GetExecutionContext()->IsSecureContext()) { |
870 exception_state.ThrowSecurityError("Must be in a secure context"); | 838 exception_state.ThrowSecurityError("Must be in a secure context"); |
871 return; | 839 return; |
872 } | 840 } |
873 | 841 |
874 if (!AllowedToUsePaymentRequest(GetFrame())) { | 842 if (!AllowedToUsePaymentRequest(GetFrame())) { |
875 exception_state.ThrowSecurityError( | 843 exception_state.ThrowSecurityError( |
876 "Must be in a top-level browsing context or an iframe needs to specify " | 844 "Must be in a top-level browsing context or an iframe needs to specify " |
877 "'allowpaymentrequest' explicitly"); | 845 "'allowpaymentrequest' explicitly"); |
878 return; | 846 return; |
879 } | 847 } |
880 | 848 |
881 PaymentDetailsPtr validated_details = | 849 PaymentDetailsPtr validated_details = |
882 payments::mojom::blink::PaymentDetails::New(); | 850 payments::mojom::blink::PaymentDetails::New(); |
883 ValidateAndConvertPaymentDetailsInit(details, options_.requestShipping(), | 851 validated_details->id = id_ = |
884 validated_details, shipping_option_, | 852 details.hasId() ? details.id() : CreateCanonicalUUIDString(); |
885 *GetExecutionContext(), exception_state); | 853 |
854 Vector<payments::mojom::blink::PaymentMethodDataPtr> validated_method_data; | |
855 ValidateAndConvertPaymentMethodData(method_data, validated_method_data, | |
856 *GetExecutionContext(), exception_state); | |
886 if (exception_state.HadException()) | 857 if (exception_state.HadException()) |
887 return; | 858 return; |
888 | 859 |
889 id_ = validated_details->id; | 860 ValidateAndConvertPaymentDetailsInit(details, validated_details, |
861 shipping_option_, *GetExecutionContext(), | |
862 exception_state); | |
863 if (exception_state.HadException()) | |
864 return; | |
890 | 865 |
891 if (options_.requestShipping()) | 866 if (options_.requestShipping()) |
892 shipping_type_ = GetValidShippingType(options_.shippingType()); | 867 shipping_type_ = options_.shippingType(); |
868 else | |
869 validated_details->shipping_options.clear(); | |
870 | |
871 DCHECK(shipping_type_.IsNull() || shipping_type_ == "shipping" || | |
872 shipping_type_ == "delivery" || shipping_type_ == "pickup"); | |
893 | 873 |
894 GetFrame()->GetInterfaceProvider()->GetInterface( | 874 GetFrame()->GetInterfaceProvider()->GetInterface( |
895 mojo::MakeRequest(&payment_provider_)); | 875 mojo::MakeRequest(&payment_provider_)); |
896 payment_provider_.set_connection_error_handler(ConvertToBaseCallback( | 876 payment_provider_.set_connection_error_handler(ConvertToBaseCallback( |
897 WTF::Bind(&PaymentRequest::OnError, WrapWeakPersistent(this), | 877 WTF::Bind(&PaymentRequest::OnError, WrapWeakPersistent(this), |
898 PaymentErrorReason::UNKNOWN))); | 878 PaymentErrorReason::UNKNOWN))); |
899 payment_provider_->Init( | 879 payment_provider_->Init( |
900 client_binding_.CreateInterfacePtrAndBind(), | 880 client_binding_.CreateInterfacePtrAndBind(), |
901 std::move(validated_method_data), std::move(validated_details), | 881 std::move(validated_method_data), std::move(validated_details), |
902 payments::mojom::blink::PaymentOptions::From(options_)); | 882 payments::mojom::blink::PaymentOptions::From(options_)); |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1088 complete_resolver_.Clear(); | 1068 complete_resolver_.Clear(); |
1089 show_resolver_.Clear(); | 1069 show_resolver_.Clear(); |
1090 abort_resolver_.Clear(); | 1070 abort_resolver_.Clear(); |
1091 can_make_payment_resolver_.Clear(); | 1071 can_make_payment_resolver_.Clear(); |
1092 if (client_binding_.is_bound()) | 1072 if (client_binding_.is_bound()) |
1093 client_binding_.Close(); | 1073 client_binding_.Close(); |
1094 payment_provider_.reset(); | 1074 payment_provider_.reset(); |
1095 } | 1075 } |
1096 | 1076 |
1097 } // namespace blink | 1077 } // namespace blink |
OLD | NEW |