Chromium Code Reviews| 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 "bindings/core/v8/ExceptionState.h" | 7 #include "bindings/core/v8/ExceptionState.h" |
| 8 #include "bindings/core/v8/JSONValuesForV8.h" | 8 #include "bindings/core/v8/JSONValuesForV8.h" |
| 9 #include "bindings/core/v8/ScriptPromiseResolver.h" | 9 #include "bindings/core/v8/ScriptPromiseResolver.h" |
| 10 #include "bindings/core/v8/ScriptState.h" | 10 #include "bindings/core/v8/ScriptState.h" |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 216 | 216 |
| 217 void validateDisplayItems(const HeapVector<PaymentItem>& items, | 217 void validateDisplayItems(const HeapVector<PaymentItem>& items, |
| 218 ExceptionState& exceptionState) { | 218 ExceptionState& exceptionState) { |
| 219 for (const auto& item : items) { | 219 for (const auto& item : items) { |
| 220 validateShippingOptionOrPaymentItem(item, exceptionState); | 220 validateShippingOptionOrPaymentItem(item, exceptionState); |
| 221 if (exceptionState.hadException()) | 221 if (exceptionState.hadException()) |
| 222 return; | 222 return; |
| 223 } | 223 } |
| 224 } | 224 } |
| 225 | 225 |
| 226 void validateAndFixupShippingOptions(HeapVector<PaymentShippingOption>& options, | 226 // Returns false if |options| should be ignored without throwing an exception. |
| 227 ExceptionState& exceptionState) { | 227 bool validateShippingOptions(const HeapVector<PaymentShippingOption>& options, |
| 228 ExceptionState& exceptionState) { | |
| 228 HashSet<String> uniqueIds; | 229 HashSet<String> uniqueIds; |
| 229 for (const auto& option : options) { | 230 for (const auto& option : options) { |
| 230 if (!option.hasId() || option.id().isEmpty()) { | 231 if (!option.hasId() || option.id().isEmpty()) { |
| 231 exceptionState.throwTypeError("ShippingOption id required"); | 232 exceptionState.throwTypeError("ShippingOption id required"); |
| 232 return; | 233 return true; |
| 233 } | 234 } |
| 234 | 235 |
| 235 if (uniqueIds.contains(option.id())) { | 236 if (uniqueIds.contains(option.id())) |
| 236 options = HeapVector<PaymentShippingOption>(); | 237 return false; |
| 237 return; | 238 |
| 238 } | |
| 239 uniqueIds.add(option.id()); | 239 uniqueIds.add(option.id()); |
| 240 | 240 |
| 241 validateShippingOptionOrPaymentItem(option, exceptionState); | 241 validateShippingOptionOrPaymentItem(option, exceptionState); |
| 242 if (exceptionState.hadException()) | 242 if (exceptionState.hadException()) |
| 243 return; | 243 return true; |
| 244 } | 244 } |
| 245 | |
| 246 return true; | |
| 245 } | 247 } |
| 246 | 248 |
| 247 void validatePaymentDetailsModifiers( | 249 void validatePaymentDetailsModifiers( |
| 248 const HeapVector<PaymentDetailsModifier>& modifiers, | 250 const HeapVector<PaymentDetailsModifier>& modifiers, |
| 249 ExceptionState& exceptionState) { | 251 ExceptionState& exceptionState) { |
| 250 if (modifiers.isEmpty()) { | 252 if (modifiers.isEmpty()) { |
| 251 exceptionState.throwTypeError( | 253 exceptionState.throwTypeError( |
| 252 "Must specify at least one payment details modifier"); | 254 "Must specify at least one payment details modifier"); |
| 253 return; | 255 return; |
| 254 } | 256 } |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 283 } | 285 } |
| 284 | 286 |
| 285 if (modifier.hasAdditionalDisplayItems()) { | 287 if (modifier.hasAdditionalDisplayItems()) { |
| 286 validateDisplayItems(modifier.additionalDisplayItems(), exceptionState); | 288 validateDisplayItems(modifier.additionalDisplayItems(), exceptionState); |
| 287 if (exceptionState.hadException()) | 289 if (exceptionState.hadException()) |
| 288 return; | 290 return; |
| 289 } | 291 } |
| 290 } | 292 } |
| 291 } | 293 } |
| 292 | 294 |
| 293 void validateAndFixupPaymentDetails(PaymentDetails& details, | 295 // Returns false if the shipping options should be ignored without throwing an |
| 294 ExceptionState& exceptionState) { | 296 // exception. |
|
Mathieu
2016/10/18 14:13:00
It took me a few passes to understand this pattern
please use gerrit instead
2016/10/19 15:44:34
Done.
| |
| 297 bool validatePaymentDetails(const PaymentDetails& details, | |
| 298 ExceptionState& exceptionState) { | |
| 295 if (!details.hasTotal()) { | 299 if (!details.hasTotal()) { |
| 296 exceptionState.throwTypeError("Must specify total"); | 300 exceptionState.throwTypeError("Must specify total"); |
| 297 return; | 301 return true; |
| 298 } | 302 } |
| 299 | 303 |
| 300 validateShippingOptionOrPaymentItem(details.total(), exceptionState); | 304 validateShippingOptionOrPaymentItem(details.total(), exceptionState); |
| 301 if (exceptionState.hadException()) | 305 if (exceptionState.hadException()) |
| 302 return; | 306 return true; |
| 303 | 307 |
| 304 if (details.total().amount().value()[0] == '-') { | 308 if (details.total().amount().value()[0] == '-') { |
| 305 exceptionState.throwTypeError("Total amount value should be non-negative"); | 309 exceptionState.throwTypeError("Total amount value should be non-negative"); |
| 306 return; | 310 return true; |
| 307 } | 311 } |
| 308 | 312 |
| 309 if (details.hasDisplayItems()) { | 313 if (details.hasDisplayItems()) { |
| 310 validateDisplayItems(details.displayItems(), exceptionState); | 314 validateDisplayItems(details.displayItems(), exceptionState); |
| 311 if (exceptionState.hadException()) | 315 if (exceptionState.hadException()) |
| 312 return; | 316 return true; |
| 313 } | 317 } |
| 314 | 318 |
| 315 if (details.hasShippingOptions()) { | 319 if (details.hasShippingOptions()) { |
| 316 HeapVector<PaymentShippingOption> fixedShippingOptions = | 320 if (!validateShippingOptions(details.shippingOptions(), exceptionState)) |
| 317 details.shippingOptions(); | 321 return false; |
| 318 validateAndFixupShippingOptions(fixedShippingOptions, exceptionState); | 322 |
| 319 details.setShippingOptions(fixedShippingOptions); | |
| 320 if (exceptionState.hadException()) | 323 if (exceptionState.hadException()) |
| 321 return; | 324 return true; |
| 322 } | 325 } |
| 323 | 326 |
| 324 if (details.hasModifiers()) { | 327 if (details.hasModifiers()) { |
| 325 validatePaymentDetailsModifiers(details.modifiers(), exceptionState); | 328 validatePaymentDetailsModifiers(details.modifiers(), exceptionState); |
| 326 } | 329 } |
| 327 | 330 |
| 328 String errorMessage; | 331 String errorMessage; |
| 329 if (!PaymentsValidators::isValidErrorMsgFormat(details.error(), | 332 if (!PaymentsValidators::isValidErrorMsgFormat(details.error(), |
| 330 &errorMessage)) { | 333 &errorMessage)) { |
| 331 exceptionState.throwTypeError(errorMessage); | 334 exceptionState.throwTypeError(errorMessage); |
| 332 return; | |
| 333 } | 335 } |
| 336 | |
| 337 return true; | |
| 334 } | 338 } |
| 335 | 339 |
| 336 void validateAndConvertPaymentMethodData( | 340 void validateAndConvertPaymentMethodData( |
| 337 const HeapVector<PaymentMethodData>& paymentMethodData, | 341 const HeapVector<PaymentMethodData>& paymentMethodData, |
| 338 Vector<PaymentRequest::MethodData>* methodData, | 342 Vector<PaymentRequest::MethodData>* methodData, |
| 339 ExceptionState& exceptionState) { | 343 ExceptionState& exceptionState) { |
| 340 if (paymentMethodData.isEmpty()) { | 344 if (paymentMethodData.isEmpty()) { |
| 341 exceptionState.throwTypeError( | 345 exceptionState.throwTypeError( |
| 342 "Must specify at least one payment method identifier"); | 346 "Must specify at least one payment method identifier"); |
| 343 return; | 347 return; |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 402 static const char* const validValues[] = { | 406 static const char* const validValues[] = { |
| 403 "shipping", "delivery", "pickup", | 407 "shipping", "delivery", "pickup", |
| 404 }; | 408 }; |
| 405 for (size_t i = 0; i < WTF_ARRAY_LENGTH(validValues); i++) { | 409 for (size_t i = 0; i < WTF_ARRAY_LENGTH(validValues); i++) { |
| 406 if (shippingType == validValues[i]) | 410 if (shippingType == validValues[i]) |
| 407 return shippingType; | 411 return shippingType; |
| 408 } | 412 } |
| 409 return validValues[0]; | 413 return validValues[0]; |
| 410 } | 414 } |
| 411 | 415 |
| 416 mojom::blink::PaymentDetailsPtr maybeKeepShippingOptions( | |
| 417 mojom::blink::PaymentDetailsPtr details, | |
| 418 bool keep) { | |
| 419 if (!keep) | |
| 420 details->shipping_options.resize(0); | |
| 421 | |
| 422 return details; | |
| 423 } | |
| 424 | |
| 412 } // namespace | 425 } // namespace |
| 413 | 426 |
| 414 PaymentRequest* PaymentRequest::create( | 427 PaymentRequest* PaymentRequest::create( |
| 415 ScriptState* scriptState, | 428 ScriptState* scriptState, |
| 416 const HeapVector<PaymentMethodData>& methodData, | 429 const HeapVector<PaymentMethodData>& methodData, |
| 417 const PaymentDetails& details, | 430 const PaymentDetails& details, |
| 418 ExceptionState& exceptionState) { | 431 ExceptionState& exceptionState) { |
| 419 return new PaymentRequest(scriptState, methodData, details, PaymentOptions(), | 432 return new PaymentRequest(scriptState, methodData, details, PaymentOptions(), |
| 420 exceptionState); | 433 exceptionState); |
| 421 } | 434 } |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 519 V8PaymentDetails::toImpl(detailsScriptValue.isolate(), | 532 V8PaymentDetails::toImpl(detailsScriptValue.isolate(), |
| 520 detailsScriptValue.v8Value(), details, | 533 detailsScriptValue.v8Value(), details, |
| 521 exceptionState); | 534 exceptionState); |
| 522 if (exceptionState.hadException()) { | 535 if (exceptionState.hadException()) { |
| 523 m_showResolver->reject( | 536 m_showResolver->reject( |
| 524 DOMException::create(SyntaxError, exceptionState.message())); | 537 DOMException::create(SyntaxError, exceptionState.message())); |
| 525 clearResolversAndCloseMojoConnection(); | 538 clearResolversAndCloseMojoConnection(); |
| 526 return; | 539 return; |
| 527 } | 540 } |
| 528 | 541 |
| 529 validateAndFixupPaymentDetails(details, exceptionState); | 542 bool keepShippingOptions = validatePaymentDetails(details, exceptionState); |
| 530 if (exceptionState.hadException()) { | 543 if (exceptionState.hadException()) { |
| 531 m_showResolver->reject( | 544 m_showResolver->reject( |
| 532 DOMException::create(SyntaxError, exceptionState.message())); | 545 DOMException::create(SyntaxError, exceptionState.message())); |
| 533 clearResolversAndCloseMojoConnection(); | 546 clearResolversAndCloseMojoConnection(); |
| 534 return; | 547 return; |
| 535 } | 548 } |
| 536 | 549 |
| 537 if (m_options.requestShipping()) | 550 if (m_options.requestShipping()) { |
| 538 m_shippingOption = getSelectedShippingOption(details); | 551 if (keepShippingOptions) |
| 552 m_shippingOption = getSelectedShippingOption(details); | |
| 553 else | |
| 554 m_shippingOption = String(); | |
| 555 } | |
| 539 | 556 |
| 540 m_paymentProvider->UpdateWith(mojom::blink::PaymentDetails::From(details)); | 557 m_paymentProvider->UpdateWith(maybeKeepShippingOptions( |
| 558 mojom::blink::PaymentDetails::From(details), keepShippingOptions)); | |
| 541 } | 559 } |
| 542 | 560 |
| 543 void PaymentRequest::onUpdatePaymentDetailsFailure(const String& error) { | 561 void PaymentRequest::onUpdatePaymentDetailsFailure(const String& error) { |
| 544 if (m_showResolver) | 562 if (m_showResolver) |
| 545 m_showResolver->reject(DOMException::create(AbortError, error)); | 563 m_showResolver->reject(DOMException::create(AbortError, error)); |
| 546 if (m_completeResolver) | 564 if (m_completeResolver) |
| 547 m_completeResolver->reject(DOMException::create(AbortError, error)); | 565 m_completeResolver->reject(DOMException::create(AbortError, error)); |
| 548 clearResolversAndCloseMojoConnection(); | 566 clearResolversAndCloseMojoConnection(); |
| 549 } | 567 } |
| 550 | 568 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 584 return; | 602 return; |
| 585 } | 603 } |
| 586 | 604 |
| 587 if (!scriptState->domWindow()->frame() || | 605 if (!scriptState->domWindow()->frame() || |
| 588 !scriptState->domWindow()->frame()->isMainFrame()) { | 606 !scriptState->domWindow()->frame()->isMainFrame()) { |
| 589 exceptionState.throwSecurityError( | 607 exceptionState.throwSecurityError( |
| 590 "Must be in a top-level browsing context"); | 608 "Must be in a top-level browsing context"); |
| 591 return; | 609 return; |
| 592 } | 610 } |
| 593 | 611 |
| 594 PaymentDetails fixedDetails(details); | 612 bool keepShippingOptions = validatePaymentDetails(details, exceptionState); |
| 595 validateAndFixupPaymentDetails(fixedDetails, exceptionState); | |
| 596 if (exceptionState.hadException()) | 613 if (exceptionState.hadException()) |
| 597 return; | 614 return; |
| 598 | 615 |
| 599 if (fixedDetails.hasError() && !fixedDetails.error().isEmpty()) { | 616 if (details.hasError() && !details.error().isEmpty()) { |
| 600 exceptionState.throwTypeError("Error value should be empty"); | 617 exceptionState.throwTypeError("Error value should be empty"); |
| 601 return; | 618 return; |
| 602 } | 619 } |
| 603 | 620 |
| 604 if (m_options.requestShipping()) { | 621 if (m_options.requestShipping()) { |
| 605 m_shippingOption = getSelectedShippingOption(fixedDetails); | 622 if (keepShippingOptions) |
| 623 m_shippingOption = getSelectedShippingOption(details); | |
| 606 m_shippingType = getValidShippingType(m_options.shippingType()); | 624 m_shippingType = getValidShippingType(m_options.shippingType()); |
| 607 } | 625 } |
| 608 | 626 |
| 609 scriptState->domWindow()->frame()->interfaceProvider()->getInterface( | 627 scriptState->domWindow()->frame()->interfaceProvider()->getInterface( |
| 610 mojo::GetProxy(&m_paymentProvider)); | 628 mojo::GetProxy(&m_paymentProvider)); |
| 611 m_paymentProvider.set_connection_error_handler(convertToBaseCallback( | 629 m_paymentProvider.set_connection_error_handler(convertToBaseCallback( |
| 612 WTF::bind(&PaymentRequest::OnError, wrapWeakPersistent(this), | 630 WTF::bind(&PaymentRequest::OnError, wrapWeakPersistent(this), |
| 613 mojom::blink::PaymentErrorReason::UNKNOWN))); | 631 mojom::blink::PaymentErrorReason::UNKNOWN))); |
| 614 m_paymentProvider->Init( | 632 m_paymentProvider->Init( |
| 615 m_clientBinding.CreateInterfacePtrAndBind(), | 633 m_clientBinding.CreateInterfacePtrAndBind(), |
| 616 mojo::WTFArray<mojom::blink::PaymentMethodDataPtr>::From( | 634 mojo::WTFArray<mojom::blink::PaymentMethodDataPtr>::From( |
| 617 validatedMethodData), | 635 validatedMethodData), |
| 618 mojom::blink::PaymentDetails::From(fixedDetails), | 636 maybeKeepShippingOptions(mojom::blink::PaymentDetails::From(details), |
| 637 keepShippingOptions), | |
| 619 mojom::blink::PaymentOptions::From(m_options)); | 638 mojom::blink::PaymentOptions::From(m_options)); |
| 620 } | 639 } |
| 621 | 640 |
| 622 void PaymentRequest::contextDestroyed() { | 641 void PaymentRequest::contextDestroyed() { |
| 623 clearResolversAndCloseMojoConnection(); | 642 clearResolversAndCloseMojoConnection(); |
| 624 } | 643 } |
| 625 | 644 |
| 626 void PaymentRequest::OnShippingAddressChange( | 645 void PaymentRequest::OnShippingAddressChange( |
| 627 mojom::blink::PaymentAddressPtr address) { | 646 mojom::blink::PaymentAddressPtr address) { |
| 628 DCHECK(m_showResolver); | 647 DCHECK(m_showResolver); |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 786 m_completeTimer.stop(); | 805 m_completeTimer.stop(); |
| 787 m_completeResolver.clear(); | 806 m_completeResolver.clear(); |
| 788 m_showResolver.clear(); | 807 m_showResolver.clear(); |
| 789 m_abortResolver.clear(); | 808 m_abortResolver.clear(); |
| 790 if (m_clientBinding.is_bound()) | 809 if (m_clientBinding.is_bound()) |
| 791 m_clientBinding.Close(); | 810 m_clientBinding.Close(); |
| 792 m_paymentProvider.reset(); | 811 m_paymentProvider.reset(); |
| 793 } | 812 } |
| 794 | 813 |
| 795 } // namespace blink | 814 } // namespace blink |
| OLD | NEW |