blob: 080fc25b6477d23b17778446afd4428861b1f65e [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/payments/payment_request_update_event.h"
#include "base/location.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/modules/payments/payment_updater.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
namespace {
// Reject the payment request if the page does not resolve the promise from
// updateWith within 60 seconds.
constexpr TimeDelta kAbortTimeout = TimeDelta::FromSeconds(60);
class UpdatePaymentDetailsFunction : public ScriptFunction {
public:
static v8::Local<v8::Function> CreateFunction(
ScriptState* script_state,
PaymentRequestUpdateEvent* update_event) {
UpdatePaymentDetailsFunction* self =
new UpdatePaymentDetailsFunction(script_state, update_event);
return self->BindToV8Function();
}
void Trace(blink::Visitor* visitor) override {
visitor->Trace(update_event_);
ScriptFunction::Trace(visitor);
}
private:
UpdatePaymentDetailsFunction(ScriptState* script_state,
PaymentRequestUpdateEvent* update_event)
: ScriptFunction(script_state), update_event_(update_event) {
DCHECK(update_event_);
}
ScriptValue Call(ScriptValue value) override {
update_event_->OnUpdatePaymentDetails(update_event_->type(), value);
return ScriptValue();
}
Member<PaymentRequestUpdateEvent> update_event_;
};
class UpdatePaymentDetailsErrorFunction : public ScriptFunction {
public:
static v8::Local<v8::Function> CreateFunction(ScriptState* script_state,
PaymentUpdater* updater) {
UpdatePaymentDetailsErrorFunction* self =
new UpdatePaymentDetailsErrorFunction(script_state, updater);
return self->BindToV8Function();
}
void Trace(blink::Visitor* visitor) override {
visitor->Trace(updater_);
ScriptFunction::Trace(visitor);
}
private:
UpdatePaymentDetailsErrorFunction(ScriptState* script_state,
PaymentUpdater* updater)
: ScriptFunction(script_state), updater_(updater) {
DCHECK(updater_);
}
ScriptValue Call(ScriptValue value) override {
updater_->OnUpdatePaymentDetailsFailure(
ToCoreString(value.V8Value()
->ToString(GetScriptState()->GetContext())
.ToLocalChecked()));
return ScriptValue();
}
Member<PaymentUpdater> updater_;
};
} // namespace
PaymentRequestUpdateEvent::~PaymentRequestUpdateEvent() = default;
PaymentRequestUpdateEvent* PaymentRequestUpdateEvent::Create(
ExecutionContext* execution_context,
const AtomicString& type,
const PaymentRequestUpdateEventInit* init) {
return MakeGarbageCollected<PaymentRequestUpdateEvent>(execution_context,
type, init);
}
void PaymentRequestUpdateEvent::SetPaymentDetailsUpdater(
PaymentUpdater* updater) {
updater_ = updater;
}
void PaymentRequestUpdateEvent::updateWith(ScriptState* script_state,
ScriptPromise promise,
ExceptionState& exception_state) {
if (!isTrusted()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
"Cannot update details when the event is not trusted");
return;
}
if (!updater_)
return;
if (wait_for_update_) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"Cannot update details twice");
return;
}
stopPropagation();
stopImmediatePropagation();
wait_for_update_ = true;
DCHECK(!abort_timer_.IsActive());
abort_timer_.StartOneShot(kAbortTimeout, FROM_HERE);
promise.Then(
UpdatePaymentDetailsFunction::CreateFunction(script_state, this),
UpdatePaymentDetailsErrorFunction::CreateFunction(script_state, this));
}
void PaymentRequestUpdateEvent::OnUpdatePaymentDetails(
const AtomicString& event_type,
const ScriptValue& details_script_value) {
if (!updater_)
return;
abort_timer_.Stop();
updater_->OnUpdatePaymentDetails(event_type, details_script_value);
updater_ = nullptr;
}
void PaymentRequestUpdateEvent::OnUpdatePaymentDetailsFailure(
const String& error) {
if (!updater_)
return;
abort_timer_.Stop();
updater_->OnUpdatePaymentDetailsFailure(error);
updater_ = nullptr;
}
void PaymentRequestUpdateEvent::Trace(blink::Visitor* visitor) {
visitor->Trace(updater_);
Event::Trace(visitor);
}
void PaymentRequestUpdateEvent::OnUpdateEventTimeoutForTesting() {
OnUpdateEventTimeout(nullptr);
}
PaymentRequestUpdateEvent::PaymentRequestUpdateEvent(
ExecutionContext* execution_context,
const AtomicString& type,
const PaymentRequestUpdateEventInit* init)
: Event(type, init),
wait_for_update_(false),
abort_timer_(execution_context->GetTaskRunner(TaskType::kUserInteraction),
this,
&PaymentRequestUpdateEvent::OnUpdateEventTimeout) {}
void PaymentRequestUpdateEvent::OnUpdateEventTimeout(TimerBase*) {
OnUpdatePaymentDetailsFailure("Timed out waiting for a response to a '" +
type() + "' event");
}
} // namespace blink