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::onTimerFired(TimerBase*) |
| 490 { |
| 491 m_completeTimer.stop(); |
| 492 m_paymentProvider->Complete(mojom::blink::PaymentComplete(Fail)); |
| 493 clearResolversAndCloseMojoConnection(); |
| 494 } |
| 495 |
480 PaymentRequest::PaymentRequest(ScriptState* scriptState, const HeapVector<Paymen
tMethodData>& methodData, const PaymentDetails& details, const PaymentOptions& o
ptions, ExceptionState& exceptionState) | 496 PaymentRequest::PaymentRequest(ScriptState* scriptState, const HeapVector<Paymen
tMethodData>& methodData, const PaymentDetails& details, const PaymentOptions& o
ptions, ExceptionState& exceptionState) |
481 : ContextLifecycleObserver(scriptState->getExecutionContext()) | 497 : ContextLifecycleObserver(scriptState->getExecutionContext()) |
482 , ActiveScriptWrappable(this) | 498 , ActiveScriptWrappable(this) |
483 , m_options(options) | 499 , m_options(options) |
484 , m_clientBinding(this) | 500 , m_clientBinding(this) |
| 501 , m_completeTimer(this, &PaymentRequest::onTimerFired) |
485 { | 502 { |
486 validateAndConvertPaymentMethodData(methodData, &m_methodData, exceptionStat
e); | 503 validateAndConvertPaymentMethodData(methodData, &m_methodData, exceptionStat
e); |
487 if (exceptionState.hadException()) | 504 if (exceptionState.hadException()) |
488 return; | 505 return; |
489 | 506 |
490 if (!scriptState->getExecutionContext()->isSecureContext()) { | 507 if (!scriptState->getExecutionContext()->isSecureContext()) { |
491 exceptionState.throwSecurityError("Must be in a secure context"); | 508 exceptionState.throwSecurityError("Must be in a secure context"); |
492 return; | 509 return; |
493 } | 510 } |
494 | 511 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
547 event->setPaymentDetailsUpdater(this); | 564 event->setPaymentDetailsUpdater(this); |
548 bool success = getExecutionContext()->getEventQueue()->enqueueEvent(event); | 565 bool success = getExecutionContext()->getEventQueue()->enqueueEvent(event); |
549 DCHECK(success); | 566 DCHECK(success); |
550 ALLOW_UNUSED_LOCAL(success); | 567 ALLOW_UNUSED_LOCAL(success); |
551 } | 568 } |
552 | 569 |
553 void PaymentRequest::OnPaymentResponse(mojom::blink::PaymentResponsePtr response
) | 570 void PaymentRequest::OnPaymentResponse(mojom::blink::PaymentResponsePtr response
) |
554 { | 571 { |
555 DCHECK(m_showResolver); | 572 DCHECK(m_showResolver); |
556 DCHECK(!m_completeResolver); | 573 DCHECK(!m_completeResolver); |
| 574 DCHECK(!m_completeTimer.isActive()); |
557 | 575 |
558 if (m_options.requestShipping()) { | 576 if (m_options.requestShipping()) { |
559 if (!response->shipping_address || response->shipping_option.isEmpty())
{ | 577 if (!response->shipping_address || response->shipping_option.isEmpty())
{ |
560 m_showResolver->reject(DOMException::create(SyntaxError)); | 578 m_showResolver->reject(DOMException::create(SyntaxError)); |
561 clearResolversAndCloseMojoConnection(); | 579 clearResolversAndCloseMojoConnection(); |
562 return; | 580 return; |
563 } | 581 } |
564 | 582 |
565 String errorMessage; | 583 String errorMessage; |
566 if (!PaymentsValidators::isValidShippingAddress(response->shipping_addre
ss, &errorMessage)) { | 584 if (!PaymentsValidators::isValidShippingAddress(response->shipping_addre
ss, &errorMessage)) { |
(...skipping 14 matching lines...) Expand all Loading... |
581 | 599 |
582 if ((m_options.requestPayerEmail() && response->payer_email.isEmpty()) | 600 if ((m_options.requestPayerEmail() && response->payer_email.isEmpty()) |
583 || (m_options.requestPayerPhone() && response->payer_phone.isEmpty()) | 601 || (m_options.requestPayerPhone() && response->payer_phone.isEmpty()) |
584 || (!m_options.requestPayerEmail() && !response->payer_email.isNull()) | 602 || (!m_options.requestPayerEmail() && !response->payer_email.isNull()) |
585 || (!m_options.requestPayerPhone() && !response->payer_phone.isNull()))
{ | 603 || (!m_options.requestPayerPhone() && !response->payer_phone.isNull()))
{ |
586 m_showResolver->reject(DOMException::create(SyntaxError)); | 604 m_showResolver->reject(DOMException::create(SyntaxError)); |
587 clearResolversAndCloseMojoConnection(); | 605 clearResolversAndCloseMojoConnection(); |
588 return; | 606 return; |
589 } | 607 } |
590 | 608 |
| 609 m_completeTimer.startOneShot(completeTimeoutSeconds, BLINK_FROM_HERE); |
| 610 |
591 m_showResolver->resolve(new PaymentResponse(std::move(response), this)); | 611 m_showResolver->resolve(new PaymentResponse(std::move(response), this)); |
592 | 612 |
593 // Do not close the mojo connection here. The merchant website should call | 613 // Do not close the mojo connection here. The merchant website should call |
594 // PaymentResponse::complete(boolean), which will be forwarded over the mojo | 614 // PaymentResponse::complete(String), which will be forwarded over the mojo |
595 // connection to display a success or failure message to the user. | 615 // connection to display a success or failure message to the user. |
596 m_showResolver.clear(); | 616 m_showResolver.clear(); |
597 } | 617 } |
598 | 618 |
599 void PaymentRequest::OnError(mojo::PaymentErrorReason error) | 619 void PaymentRequest::OnError(mojo::PaymentErrorReason error) |
600 { | 620 { |
601 bool isError = false; | 621 bool isError = false; |
602 ExceptionCode ec = UnknownError; | 622 ExceptionCode ec = UnknownError; |
603 String message; | 623 String message; |
604 | 624 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
670 { | 690 { |
671 m_completeResolver.clear(); | 691 m_completeResolver.clear(); |
672 m_showResolver.clear(); | 692 m_showResolver.clear(); |
673 m_abortResolver.clear(); | 693 m_abortResolver.clear(); |
674 if (m_clientBinding.is_bound()) | 694 if (m_clientBinding.is_bound()) |
675 m_clientBinding.Close(); | 695 m_clientBinding.Close(); |
676 m_paymentProvider.reset(); | 696 m_paymentProvider.reset(); |
677 } | 697 } |
678 | 698 |
679 } // namespace blink | 699 } // namespace blink |
OLD | NEW |