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 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
152 } | 152 } |
153 return output; | 153 return output; |
154 } | 154 } |
155 }; | 155 }; |
156 | 156 |
157 } // namespace mojo | 157 } // namespace mojo |
158 | 158 |
159 namespace blink { | 159 namespace blink { |
160 namespace { | 160 namespace { |
161 | 161 |
| 162 // If the website does not call complete() 60 seconds after show() has been reso
lved, then behave as if |
| 163 // the website called complete("fail"). |
| 164 static const int completeTimeoutSeconds = 60; |
| 165 |
162 // Validates ShippingOption or PaymentItem, which happen to have identical field
s, | 166 // Validates ShippingOption or PaymentItem, which happen to have identical field
s, |
163 // except for "id", which is present only in ShippingOption. | 167 // except for "id", which is present only in ShippingOption. |
164 template <typename T> | 168 template <typename T> |
165 void validateShippingOptionOrPaymentItem(const T& item, ExceptionState& exceptio
nState) | 169 void validateShippingOptionOrPaymentItem(const T& item, ExceptionState& exceptio
nState) |
166 { | 170 { |
167 if (!item.hasLabel() || item.label().isEmpty()) { | 171 if (!item.hasLabel() || item.label().isEmpty()) { |
168 exceptionState.throwTypeError("Item label required"); | 172 exceptionState.throwTypeError("Item label required"); |
169 return; | 173 return; |
170 } | 174 } |
171 | 175 |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
411 ExecutionContext* PaymentRequest::getExecutionContext() const | 415 ExecutionContext* PaymentRequest::getExecutionContext() const |
412 { | 416 { |
413 return ContextLifecycleObserver::getExecutionContext(); | 417 return ContextLifecycleObserver::getExecutionContext(); |
414 } | 418 } |
415 | 419 |
416 ScriptPromise PaymentRequest::complete(ScriptState* scriptState, PaymentComplete
result) | 420 ScriptPromise PaymentRequest::complete(ScriptState* scriptState, PaymentComplete
result) |
417 { | 421 { |
418 if (m_completeResolver) | 422 if (m_completeResolver) |
419 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "Already called complete() once")); | 423 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "Already called complete() once")); |
420 | 424 |
| 425 if (!m_completeTimer.isActive()) |
| 426 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "Timed out after 60 seconds, complete() called too lat
e")); |
| 427 |
421 // User has cancelled the transaction while the website was processing it. | 428 // User has cancelled the transaction while the website was processing it. |
422 if (!m_paymentProvider) | 429 if (!m_paymentProvider) |
423 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "Request cancelled")); | 430 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "Request cancelled")); |
424 | 431 |
| 432 m_completeTimer.stop(); |
| 433 |
425 // The payment provider should respond in PaymentRequest::OnComplete(). | 434 // The payment provider should respond in PaymentRequest::OnComplete(). |
426 m_paymentProvider->Complete(mojom::blink::PaymentComplete(result)); | 435 m_paymentProvider->Complete(mojom::blink::PaymentComplete(result)); |
427 | 436 |
428 m_completeResolver = ScriptPromiseResolver::create(scriptState); | 437 m_completeResolver = ScriptPromiseResolver::create(scriptState); |
429 return m_completeResolver->promise(); | 438 return m_completeResolver->promise(); |
430 } | 439 } |
431 | 440 |
432 void PaymentRequest::onUpdatePaymentDetails(const ScriptValue& detailsScriptValu
e) | 441 void PaymentRequest::onUpdatePaymentDetails(const ScriptValue& detailsScriptValu
e) |
433 { | 442 { |
434 if (!m_showResolver || !m_paymentProvider) | 443 if (!m_showResolver || !m_paymentProvider) |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
470 visitor->trace(m_details); | 479 visitor->trace(m_details); |
471 visitor->trace(m_options); | 480 visitor->trace(m_options); |
472 visitor->trace(m_shippingAddress); | 481 visitor->trace(m_shippingAddress); |
473 visitor->trace(m_showResolver); | 482 visitor->trace(m_showResolver); |
474 visitor->trace(m_completeResolver); | 483 visitor->trace(m_completeResolver); |
475 visitor->trace(m_abortResolver); | 484 visitor->trace(m_abortResolver); |
476 EventTargetWithInlineData::trace(visitor); | 485 EventTargetWithInlineData::trace(visitor); |
477 ContextLifecycleObserver::trace(visitor); | 486 ContextLifecycleObserver::trace(visitor); |
478 } | 487 } |
479 | 488 |
| 489 void PaymentRequest::onCompleteTimeoutForTesting() |
| 490 { |
| 491 onCompleteTimeout(0); |
| 492 } |
| 493 |
480 PaymentRequest::PaymentRequest(ScriptState* scriptState, const HeapVector<Paymen
tMethodData>& methodData, const PaymentDetails& details, const PaymentOptions& o
ptions, ExceptionState& exceptionState) | 494 PaymentRequest::PaymentRequest(ScriptState* scriptState, const HeapVector<Paymen
tMethodData>& methodData, const PaymentDetails& details, const PaymentOptions& o
ptions, ExceptionState& exceptionState) |
481 : ContextLifecycleObserver(scriptState->getExecutionContext()) | 495 : ContextLifecycleObserver(scriptState->getExecutionContext()) |
482 , ActiveScriptWrappable(this) | 496 , ActiveScriptWrappable(this) |
483 , m_options(options) | 497 , m_options(options) |
484 , m_clientBinding(this) | 498 , m_clientBinding(this) |
| 499 , m_completeTimer(this, &PaymentRequest::onCompleteTimeout) |
485 { | 500 { |
486 validateAndConvertPaymentMethodData(methodData, &m_methodData, exceptionStat
e); | 501 validateAndConvertPaymentMethodData(methodData, &m_methodData, exceptionStat
e); |
487 if (exceptionState.hadException()) | 502 if (exceptionState.hadException()) |
488 return; | 503 return; |
489 | 504 |
490 if (!scriptState->getExecutionContext()->isSecureContext()) { | 505 if (!scriptState->getExecutionContext()->isSecureContext()) { |
491 exceptionState.throwSecurityError("Must be in a secure context"); | 506 exceptionState.throwSecurityError("Must be in a secure context"); |
492 return; | 507 return; |
493 } | 508 } |
494 | 509 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
547 event->setPaymentDetailsUpdater(this); | 562 event->setPaymentDetailsUpdater(this); |
548 bool success = getExecutionContext()->getEventQueue()->enqueueEvent(event); | 563 bool success = getExecutionContext()->getEventQueue()->enqueueEvent(event); |
549 DCHECK(success); | 564 DCHECK(success); |
550 ALLOW_UNUSED_LOCAL(success); | 565 ALLOW_UNUSED_LOCAL(success); |
551 } | 566 } |
552 | 567 |
553 void PaymentRequest::OnPaymentResponse(mojom::blink::PaymentResponsePtr response
) | 568 void PaymentRequest::OnPaymentResponse(mojom::blink::PaymentResponsePtr response
) |
554 { | 569 { |
555 DCHECK(m_showResolver); | 570 DCHECK(m_showResolver); |
556 DCHECK(!m_completeResolver); | 571 DCHECK(!m_completeResolver); |
| 572 DCHECK(!m_completeTimer.isActive()); |
557 | 573 |
558 if (m_options.requestShipping()) { | 574 if (m_options.requestShipping()) { |
559 if (!response->shipping_address || response->shipping_option.isEmpty())
{ | 575 if (!response->shipping_address || response->shipping_option.isEmpty())
{ |
560 m_showResolver->reject(DOMException::create(SyntaxError)); | 576 m_showResolver->reject(DOMException::create(SyntaxError)); |
561 clearResolversAndCloseMojoConnection(); | 577 clearResolversAndCloseMojoConnection(); |
562 return; | 578 return; |
563 } | 579 } |
564 | 580 |
565 String errorMessage; | 581 String errorMessage; |
566 if (!PaymentsValidators::isValidShippingAddress(response->shipping_addre
ss, &errorMessage)) { | 582 if (!PaymentsValidators::isValidShippingAddress(response->shipping_addre
ss, &errorMessage)) { |
(...skipping 14 matching lines...) Expand all Loading... |
581 | 597 |
582 if ((m_options.requestPayerEmail() && response->payer_email.isEmpty()) | 598 if ((m_options.requestPayerEmail() && response->payer_email.isEmpty()) |
583 || (m_options.requestPayerPhone() && response->payer_phone.isEmpty()) | 599 || (m_options.requestPayerPhone() && response->payer_phone.isEmpty()) |
584 || (!m_options.requestPayerEmail() && !response->payer_email.isNull()) | 600 || (!m_options.requestPayerEmail() && !response->payer_email.isNull()) |
585 || (!m_options.requestPayerPhone() && !response->payer_phone.isNull()))
{ | 601 || (!m_options.requestPayerPhone() && !response->payer_phone.isNull()))
{ |
586 m_showResolver->reject(DOMException::create(SyntaxError)); | 602 m_showResolver->reject(DOMException::create(SyntaxError)); |
587 clearResolversAndCloseMojoConnection(); | 603 clearResolversAndCloseMojoConnection(); |
588 return; | 604 return; |
589 } | 605 } |
590 | 606 |
| 607 m_completeTimer.startOneShot(completeTimeoutSeconds, BLINK_FROM_HERE); |
| 608 |
591 m_showResolver->resolve(new PaymentResponse(std::move(response), this)); | 609 m_showResolver->resolve(new PaymentResponse(std::move(response), this)); |
592 | 610 |
593 // Do not close the mojo connection here. The merchant website should call | 611 // Do not close the mojo connection here. The merchant website should call |
594 // PaymentResponse::complete(boolean), which will be forwarded over the mojo | 612 // PaymentResponse::complete(String), which will be forwarded over the mojo |
595 // connection to display a success or failure message to the user. | 613 // connection to display a success or failure message to the user. |
596 m_showResolver.clear(); | 614 m_showResolver.clear(); |
597 } | 615 } |
598 | 616 |
599 void PaymentRequest::OnError(mojo::PaymentErrorReason error) | 617 void PaymentRequest::OnError(mojo::PaymentErrorReason error) |
600 { | 618 { |
601 bool isError = false; | 619 bool isError = false; |
602 ExceptionCode ec = UnknownError; | 620 ExceptionCode ec = UnknownError; |
603 String message; | 621 String message; |
604 | 622 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
659 m_abortResolver->reject(DOMException::create(InvalidStateError)); | 677 m_abortResolver->reject(DOMException::create(InvalidStateError)); |
660 m_abortResolver.clear(); | 678 m_abortResolver.clear(); |
661 return; | 679 return; |
662 } | 680 } |
663 | 681 |
664 m_showResolver->reject(DOMException::create(AbortError)); | 682 m_showResolver->reject(DOMException::create(AbortError)); |
665 m_abortResolver->resolve(); | 683 m_abortResolver->resolve(); |
666 clearResolversAndCloseMojoConnection(); | 684 clearResolversAndCloseMojoConnection(); |
667 } | 685 } |
668 | 686 |
| 687 void PaymentRequest::onCompleteTimeout(TimerBase*) |
| 688 { |
| 689 m_completeTimer.stop(); |
| 690 m_paymentProvider->Complete(mojom::blink::PaymentComplete(Fail)); |
| 691 clearResolversAndCloseMojoConnection(); |
| 692 } |
| 693 |
669 void PaymentRequest::clearResolversAndCloseMojoConnection() | 694 void PaymentRequest::clearResolversAndCloseMojoConnection() |
670 { | 695 { |
671 m_completeResolver.clear(); | 696 m_completeResolver.clear(); |
672 m_showResolver.clear(); | 697 m_showResolver.clear(); |
673 m_abortResolver.clear(); | 698 m_abortResolver.clear(); |
674 if (m_clientBinding.is_bound()) | 699 if (m_clientBinding.is_bound()) |
675 m_clientBinding.Close(); | 700 m_clientBinding.Close(); |
676 m_paymentProvider.reset(); | 701 m_paymentProvider.reset(); |
677 } | 702 } |
678 | 703 |
679 } // namespace blink | 704 } // namespace blink |
OLD | NEW |