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