Commit 13947ae3 authored by Rouslan Solomakhin's avatar Rouslan Solomakhin Committed by Commit Bot

[Web Payment][Desktop] Send abort event to payment handler.

Before this patch, aborting payment on desktop would succeed only before
the payment app has been invoked. The invoked payment app was not
consulted whether it could be aborted.

This patch delegates abort handling on desktop to the payment app.
This patch also removes the identity callback from the desktop
implementation of PaymentRequest, because aborting requires
ServiceWorkerPaymentApp to know the service worker registration ID,
which is also used for payment handler host logging, and
ServiceWorkerPaymentApp now has a reference to the payment handler
host.

After this patch, the invoked payment handler receives the abort event
and determines whether abort should be performed. (Android already does
that.)

Bug: 1083242
Change-Id: I267ad820ef06b17fb88bd8b948c22b0e07145fae
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2208105
Commit-Queue: Rouslan Solomakhin <rouslan@chromium.org>
Reviewed-by: default avatarLiquan (Max) Gu <maxlg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#771337}
parent 83710187
...@@ -12,6 +12,7 @@ source_set("browsertests") { ...@@ -12,6 +12,7 @@ source_set("browsertests") {
"has_enrolled_instrument_query_quota_browsertest.cc", "has_enrolled_instrument_query_quota_browsertest.cc",
"iframe_csp_browsertest.cc", "iframe_csp_browsertest.cc",
"ignore_payment_method_browsertest.cc", "ignore_payment_method_browsertest.cc",
"abort_payment_handler_browsertest.cc",
"journey_logger_browsertest.cc", "journey_logger_browsertest.cc",
"payment_handler_change_shipping_address_option_browsertest.cc", "payment_handler_change_shipping_address_option_browsertest.cc",
"payment_handler_enable_delegations_browsertest.cc", "payment_handler_enable_delegations_browsertest.cc",
......
// Copyright 2020 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 <string>
#include "build/build_config.h"
#include "chrome/test/payments/payment_request_platform_browsertest_base.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace payments {
namespace {
class AbortPaymentHandlerTest : public PaymentRequestPlatformBrowserTestBase {};
IN_PROC_BROWSER_TEST_F(AbortPaymentHandlerTest,
CanAbortInvokedInstalledPaymentHandler) {
std::string method_name = https_server()->GetURL("a.com", "/").spec();
method_name = method_name.substr(0, method_name.length() - 1);
ASSERT_NE('/', method_name[method_name.length() - 1]);
NavigateTo("a.com", "/payment_handler_installer.html");
ASSERT_EQ("success", content::EvalJs(
GetActiveWebContents(),
content::JsReplace(
"install('abort_responder_app.js', [$1], false)",
method_name)));
NavigateTo("b.com", "/payment_handler_aborter.html");
EXPECT_EQ(
"Abort completed",
content::EvalJs(GetActiveWebContents(),
content::JsReplace("launchAndAbort($1, $2)", method_name,
/*abortResponse=*/true)));
}
// TODO(crbug.com/1083242): Andorid implementation of
// ServiceWorkerPaymentApp.java is unable to abort payments for invoked
// just-in-time installed payment handlers. When ServiceWorkerPaymentApp.java is
// replaced with JniPaymentApp.java that owns an instance of the correctly
// working service_worker_payment_app.cc, this test should be enabled on
// Android.
#if defined(OS_ANDROID)
#define MAYBE_CanAbortInvokedJitPaymentHandler \
DISABLED_CanAbortInvokedJitPaymentHandler
#else
#define MAYBE_CanAbortInvokedJitPaymentHandler CanAbortInvokedJitPaymentHandler
#endif // OS_ANDROID
IN_PROC_BROWSER_TEST_F(AbortPaymentHandlerTest,
MAYBE_CanAbortInvokedJitPaymentHandler) {
std::string method_name =
https_server()->GetURL("a.com", "/abort_responder_app.json").spec();
ASSERT_NE('/', method_name[method_name.length() - 1]);
NavigateTo("b.com", "/payment_handler_aborter.html");
EXPECT_EQ(
"Abort completed",
content::EvalJs(GetActiveWebContents(),
content::JsReplace("launchAndAbort($1, $2)", method_name,
/*abortResponse=*/true)));
}
IN_PROC_BROWSER_TEST_F(AbortPaymentHandlerTest,
InstalledPaymentHandlerCanRefuseAbort) {
std::string method_name = https_server()->GetURL("a.com", "/").spec();
method_name = method_name.substr(0, method_name.length() - 1);
ASSERT_NE('/', method_name[method_name.length() - 1]);
NavigateTo("a.com", "/payment_handler_installer.html");
ASSERT_EQ("success", content::EvalJs(
GetActiveWebContents(),
content::JsReplace(
"install('abort_responder_app.js', [$1], false)",
method_name)));
NavigateTo("b.com", "/payment_handler_aborter.html");
EXPECT_EQ(
"Unable to abort the payment",
content::EvalJs(GetActiveWebContents(),
content::JsReplace("launchAndAbort($1, $2)", method_name,
/*abortResponse=*/false)));
}
IN_PROC_BROWSER_TEST_F(AbortPaymentHandlerTest,
JitPaymentHandlerCanRefuseAbort) {
std::string method_name =
https_server()->GetURL("a.com", "/abort_responder_app.json").spec();
ASSERT_NE('/', method_name[method_name.length() - 1]);
NavigateTo("b.com", "/payment_handler_aborter.html");
EXPECT_EQ(
"Unable to abort the payment",
content::EvalJs(GetActiveWebContents(),
content::JsReplace("launchAndAbort($1, $2)", method_name,
/*abortResponse=*/false)));
}
} // namespace
} // namespace payments
...@@ -336,12 +336,6 @@ PaymentRequestSpec* PaymentAppServiceBridge::GetSpec() const { ...@@ -336,12 +336,6 @@ PaymentRequestSpec* PaymentAppServiceBridge::GetSpec() const {
return nullptr; return nullptr;
} }
void PaymentAppServiceBridge::OnPaymentAppInstalled(const url::Origin& origin,
int64_t registration_id) {
// PaymentAppService flow should have short-circuited before this point.
NOTREACHED();
}
void PaymentAppServiceBridge::OnPaymentAppCreated( void PaymentAppServiceBridge::OnPaymentAppCreated(
std::unique_ptr<PaymentApp> app) { std::unique_ptr<PaymentApp> app) {
// PaymentAppService flow should have short-circuited before this point. // PaymentAppService flow should have short-circuited before this point.
......
...@@ -75,8 +75,6 @@ class PaymentAppServiceBridge : public PaymentAppFactory::Delegate { ...@@ -75,8 +75,6 @@ class PaymentAppServiceBridge : public PaymentAppFactory::Delegate {
bool IsRequestedAutofillDataAvailable() override; bool IsRequestedAutofillDataAvailable() override;
ContentPaymentRequestDelegate* GetPaymentRequestDelegate() const override; ContentPaymentRequestDelegate* GetPaymentRequestDelegate() const override;
PaymentRequestSpec* GetSpec() const override; PaymentRequestSpec* GetSpec() const override;
void OnPaymentAppInstalled(const url::Origin& origin,
int64_t registration_id) override;
void OnPaymentAppCreated(std::unique_ptr<PaymentApp> app) override; void OnPaymentAppCreated(std::unique_ptr<PaymentApp> app) override;
void OnPaymentAppCreationError(const std::string& error_message) override; void OnPaymentAppCreationError(const std::string& error_message) override;
bool SkipCreatingNativePaymentApps() const override; bool SkipCreatingNativePaymentApps() const override;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <algorithm> #include <algorithm>
#include "base/callback.h"
#include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_clock.h"
#include "components/payments/content/autofill_payment_app.h" #include "components/payments/content/autofill_payment_app.h"
#include "components/payments/core/features.h" #include "components/payments/core/features.h"
...@@ -68,6 +69,11 @@ bool PaymentApp::IsWaitingForPaymentDetailsUpdate() const { ...@@ -68,6 +69,11 @@ bool PaymentApp::IsWaitingForPaymentDetailsUpdate() const {
return false; return false;
} }
void PaymentApp::AbortPaymentApp(
base::OnceCallback<void(bool)> abort_callback) {
std::move(abort_callback).Run(/*aborted=*/false);
}
// static // static
void PaymentApp::SortApps(std::vector<std::unique_ptr<PaymentApp>>* apps) { void PaymentApp::SortApps(std::vector<std::unique_ptr<PaymentApp>>* apps) {
DCHECK(apps); DCHECK(apps);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "base/callback_forward.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
...@@ -136,6 +137,10 @@ class PaymentApp { ...@@ -136,6 +137,10 @@ class PaymentApp {
// details are unchanged. // details are unchanged.
virtual void OnPaymentDetailsNotUpdated() {} virtual void OnPaymentDetailsNotUpdated() {}
// Requests the invoked payment app to abort if possible. Only called if this
// payment app is currently invoked.
virtual void AbortPaymentApp(base::OnceCallback<void(bool)> abort_callback);
protected: protected:
PaymentApp(int icon_resource_id, Type type); PaymentApp(int icon_resource_id, Type type);
......
...@@ -63,11 +63,6 @@ class PaymentAppFactory { ...@@ -63,11 +63,6 @@ class PaymentAppFactory {
const = 0; const = 0;
virtual PaymentRequestSpec* GetSpec() const = 0; virtual PaymentRequestSpec* GetSpec() const = 0;
// Called after an app is installed. Used for just-in-time installable
// payment handlers, for example.
virtual void OnPaymentAppInstalled(const url::Origin& origin,
int64_t registration_id) = 0;
// Called when an app is created. // Called when an app is created.
virtual void OnPaymentAppCreated(std::unique_ptr<PaymentApp> app) = 0; virtual void OnPaymentAppCreated(std::unique_ptr<PaymentApp> app) = 0;
......
...@@ -88,10 +88,7 @@ class PaymentAppTest : public testing::TestWithParam<RequiredPaymentOptions>, ...@@ -88,10 +88,7 @@ class PaymentAppTest : public testing::TestWithParam<RequiredPaymentOptions>,
&browser_context_, GURL("https://testmerchant.com"), &browser_context_, GURL("https://testmerchant.com"),
GURL("https://testmerchant.com/bobpay"), spec_.get(), GURL("https://testmerchant.com/bobpay"), spec_.get(),
std::move(stored_app), /*is_incognito=*/false, std::move(stored_app), /*is_incognito=*/false,
/*show_processing_spinner=*/base::DoNothing(), /*show_processing_spinner=*/base::DoNothing());
/*identity_callback=*/
base::BindRepeating([](const url::Origin&,
int64_t) { /* Intentionally left blank. */ }));
} }
std::unique_ptr<ServiceWorkerPaymentApp> std::unique_ptr<ServiceWorkerPaymentApp>
...@@ -120,10 +117,7 @@ class PaymentAppTest : public testing::TestWithParam<RequiredPaymentOptions>, ...@@ -120,10 +117,7 @@ class PaymentAppTest : public testing::TestWithParam<RequiredPaymentOptions>,
web_contents_, GURL("https://merchant.example"), web_contents_, GURL("https://merchant.example"),
GURL("https://merchant.example/iframe"), spec_.get(), GURL("https://merchant.example/iframe"), spec_.get(),
std::move(installable_app), "https://pay.example", std::move(installable_app), "https://pay.example",
/*is_incognito=*/false, /*show_processing_spinner=*/base::DoNothing(), /*is_incognito=*/false, /*show_processing_spinner=*/base::DoNothing());
/*identity_callback=*/
base::BindRepeating([](const url::Origin&,
int64_t) { /* Intentionally left blank. */ }));
} }
static void PopulateIcon(SkBitmap* icon) { static void PopulateIcon(SkBitmap* icon) {
......
...@@ -185,10 +185,7 @@ void PaymentRequest::Init( ...@@ -185,10 +185,7 @@ void PaymentRequest::Init(
web_contents_, initiator_frame, top_level_origin_, frame_origin_, web_contents_, initiator_frame, top_level_origin_, frame_origin_,
frame_security_origin_, spec_.get(), frame_security_origin_, spec_.get(),
/*delegate=*/this, delegate_->GetApplicationLocale(), /*delegate=*/this, delegate_->GetApplicationLocale(),
delegate_->GetPersonalDataManager(), delegate_.get(), delegate_->GetPersonalDataManager(), delegate_.get(), &journey_logger_);
base::BindRepeating(&PaymentRequest::SetInvokedServiceWorkerIdentity,
weak_ptr_factory_.GetWeakPtr()),
&journey_logger_);
journey_logger_.SetRequestedInformation( journey_logger_.SetRequestedInformation(
spec_->request_shipping(), spec_->request_payer_email(), spec_->request_shipping(), spec_->request_payer_email(),
...@@ -407,18 +404,16 @@ void PaymentRequest::Abort() { ...@@ -407,18 +404,16 @@ void PaymentRequest::Abort() {
// The abort is only successful if the payment app wasn't yet invoked. // The abort is only successful if the payment app wasn't yet invoked.
// TODO(crbug.com/716546): Add a merchant abort metric // TODO(crbug.com/716546): Add a merchant abort metric
bool accepting_abort = !state_->IsPaymentAppInvoked();
if (accepting_abort)
RecordFirstAbortReason(JourneyLogger::ABORT_REASON_ABORTED_BY_MERCHANT);
if (client_.is_bound())
client_->OnAbort(accepting_abort);
if (observer_for_testing_) if (observer_for_testing_)
observer_for_testing_->OnAbortCalled(); observer_for_testing_->OnAbortCalled();
if (accepting_abort) if (!state_->IsPaymentAppInvoked() || !state_->selected_app()) {
state_->OnAbort(); OnAbortResult(/*aborted=*/true);
return;
}
state_->selected_app()->AbortPaymentApp(base::BindOnce(
&PaymentRequest::OnAbortResult, weak_ptr_factory_.GetWeakPtr()));
} }
void PaymentRequest::Complete(mojom::PaymentComplete result) { void PaymentRequest::Complete(mojom::PaymentComplete result) {
...@@ -704,12 +699,6 @@ void PaymentRequest::OnPayerInfoSelected(mojom::PayerDetailPtr payer_info) { ...@@ -704,12 +699,6 @@ void PaymentRequest::OnPayerInfoSelected(mojom::PayerDetailPtr payer_info) {
client_->OnPayerDetailChange(std::move(payer_info)); client_->OnPayerDetailChange(std::move(payer_info));
} }
void PaymentRequest::SetInvokedServiceWorkerIdentity(const url::Origin& origin,
int64_t registration_id) {
payment_handler_host_.set_sw_origin_for_logs(origin);
payment_handler_host_.set_registration_id_for_logs(registration_id);
}
void PaymentRequest::UserCancelled() { void PaymentRequest::UserCancelled() {
// If |client_| is not bound, then the object is already being destroyed as // If |client_| is not bound, then the object is already being destroyed as
// a result of a renderer event. // a result of a renderer event.
...@@ -838,4 +827,14 @@ void PaymentRequest::RespondToHasEnrolledInstrumentQuery( ...@@ -838,4 +827,14 @@ void PaymentRequest::RespondToHasEnrolledInstrumentQuery(
journey_logger_.SetHasEnrolledInstrumentValue(has_enrolled_instrument); journey_logger_.SetHasEnrolledInstrumentValue(has_enrolled_instrument);
} }
void PaymentRequest::OnAbortResult(bool aborted) {
if (client_.is_bound())
client_->OnAbort(aborted);
if (aborted) {
RecordFirstAbortReason(JourneyLogger::ABORT_REASON_ABORTED_BY_MERCHANT);
state_->OnAbort();
}
}
} // namespace payments } // namespace payments
...@@ -101,9 +101,6 @@ class PaymentRequest : public mojom::PaymentRequest, ...@@ -101,9 +101,6 @@ class PaymentRequest : public mojom::PaymentRequest,
void OnShippingAddressSelected(mojom::PaymentAddressPtr address) override; void OnShippingAddressSelected(mojom::PaymentAddressPtr address) override;
void OnPayerInfoSelected(mojom::PayerDetailPtr payer_info) override; void OnPayerInfoSelected(mojom::PayerDetailPtr payer_info) override;
void SetInvokedServiceWorkerIdentity(const url::Origin& origin,
int64_t registration_id);
// Called when the user explicitly cancelled the flow. Will send a message // Called when the user explicitly cancelled the flow. Will send a message
// to the renderer which will indirectly destroy this object (through // to the renderer which will indirectly destroy this object (through
// OnConnectionTerminated). // OnConnectionTerminated).
...@@ -187,6 +184,8 @@ class PaymentRequest : public mojom::PaymentRequest, ...@@ -187,6 +184,8 @@ class PaymentRequest : public mojom::PaymentRequest,
void RespondToHasEnrolledInstrumentQuery(bool has_enrolled_instrument, void RespondToHasEnrolledInstrumentQuery(bool has_enrolled_instrument,
bool warn_localhost_or_file); bool warn_localhost_or_file);
void OnAbortResult(bool aborted);
content::WebContents* web_contents_; content::WebContents* web_contents_;
const content::GlobalFrameRoutingId initiator_frame_routing_id_; const content::GlobalFrameRoutingId initiator_frame_routing_id_;
DeveloperConsoleLogger log_; DeveloperConsoleLogger log_;
......
...@@ -66,7 +66,6 @@ PaymentRequestState::PaymentRequestState( ...@@ -66,7 +66,6 @@ PaymentRequestState::PaymentRequestState(
const std::string& app_locale, const std::string& app_locale,
autofill::PersonalDataManager* personal_data_manager, autofill::PersonalDataManager* personal_data_manager,
ContentPaymentRequestDelegate* payment_request_delegate, ContentPaymentRequestDelegate* payment_request_delegate,
const ServiceWorkerPaymentApp::IdentityCallback& sw_identity_callback,
JourneyLogger* journey_logger) JourneyLogger* journey_logger)
: web_contents_(web_contents), : web_contents_(web_contents),
initiator_render_frame_host_(initiator_render_frame_host), initiator_render_frame_host_(initiator_render_frame_host),
...@@ -81,7 +80,6 @@ PaymentRequestState::PaymentRequestState( ...@@ -81,7 +80,6 @@ PaymentRequestState::PaymentRequestState(
are_requested_methods_supported_( are_requested_methods_supported_(
!spec_->supported_card_networks().empty()), !spec_->supported_card_networks().empty()),
payment_request_delegate_(payment_request_delegate), payment_request_delegate_(payment_request_delegate),
sw_identity_callback_(sw_identity_callback),
profile_comparator_(app_locale, *spec) { profile_comparator_(app_locale, *spec) {
PopulateProfileCache(); PopulateProfileCache();
...@@ -151,11 +149,6 @@ bool PaymentRequestState::MayCrawlForInstallablePaymentApps() { ...@@ -151,11 +149,6 @@ bool PaymentRequestState::MayCrawlForInstallablePaymentApps() {
!spec_->supports_basic_card(); !spec_->supports_basic_card();
} }
void PaymentRequestState::OnPaymentAppInstalled(const url::Origin& origin,
int64_t registration_id) {
sw_identity_callback_.Run(origin, registration_id);
}
void PaymentRequestState::OnPaymentAppCreated(std::unique_ptr<PaymentApp> app) { void PaymentRequestState::OnPaymentAppCreated(std::unique_ptr<PaymentApp> app) {
if (app->type() == PaymentApp::Type::AUTOFILL) { if (app->type() == PaymentApp::Type::AUTOFILL) {
journey_logger_->SetEventOccurred( journey_logger_->SetEventOccurred(
......
...@@ -114,19 +114,17 @@ class PaymentRequestState : public PaymentAppFactory::Delegate, ...@@ -114,19 +114,17 @@ class PaymentRequestState : public PaymentAppFactory::Delegate,
base::OnceCallback<void(bool methods_supported, base::OnceCallback<void(bool methods_supported,
const std::string& error_message)>; const std::string& error_message)>;
PaymentRequestState( PaymentRequestState(content::WebContents* web_contents,
content::WebContents* web_contents, content::RenderFrameHost* initiator_render_frame_host,
content::RenderFrameHost* initiator_render_frame_host, const GURL& top_level_origin,
const GURL& top_level_origin, const GURL& frame_origin,
const GURL& frame_origin, const url::Origin& frame_security_origin,
const url::Origin& frame_security_origin, PaymentRequestSpec* spec,
PaymentRequestSpec* spec, Delegate* delegate,
Delegate* delegate, const std::string& app_locale,
const std::string& app_locale, autofill::PersonalDataManager* personal_data_manager,
autofill::PersonalDataManager* personal_data_manager, ContentPaymentRequestDelegate* payment_request_delegate,
ContentPaymentRequestDelegate* payment_request_delegate, JourneyLogger* journey_logger);
const ServiceWorkerPaymentApp::IdentityCallback& sw_identity_callback,
JourneyLogger* journey_logger);
~PaymentRequestState() override; ~PaymentRequestState() override;
// PaymentAppFactory::Delegate // PaymentAppFactory::Delegate
...@@ -144,8 +142,6 @@ class PaymentRequestState : public PaymentAppFactory::Delegate, ...@@ -144,8 +142,6 @@ class PaymentRequestState : public PaymentAppFactory::Delegate,
const std::vector<autofill::AutofillProfile*>& GetBillingProfiles() override; const std::vector<autofill::AutofillProfile*>& GetBillingProfiles() override;
bool IsRequestedAutofillDataAvailable() override; bool IsRequestedAutofillDataAvailable() override;
bool MayCrawlForInstallablePaymentApps() override; bool MayCrawlForInstallablePaymentApps() override;
void OnPaymentAppInstalled(const url::Origin& origin,
int64_t registration_id) override;
void OnPaymentAppCreated(std::unique_ptr<PaymentApp> app) override; void OnPaymentAppCreated(std::unique_ptr<PaymentApp> app) override;
void OnPaymentAppCreationError(const std::string& error_message) override; void OnPaymentAppCreationError(const std::string& error_message) override;
bool SkipCreatingNativePaymentApps() const override; bool SkipCreatingNativePaymentApps() const override;
...@@ -416,7 +412,6 @@ class PaymentRequestState : public PaymentAppFactory::Delegate, ...@@ -416,7 +412,6 @@ class PaymentRequestState : public PaymentAppFactory::Delegate,
std::vector<std::unique_ptr<PaymentApp>> available_apps_; std::vector<std::unique_ptr<PaymentApp>> available_apps_;
ContentPaymentRequestDelegate* payment_request_delegate_; ContentPaymentRequestDelegate* payment_request_delegate_;
ServiceWorkerPaymentApp::IdentityCallback sw_identity_callback_;
std::unique_ptr<PaymentResponseHelper> response_helper_; std::unique_ptr<PaymentResponseHelper> response_helper_;
......
...@@ -85,9 +85,6 @@ class PaymentRequestStateTest : public testing::Test, ...@@ -85,9 +85,6 @@ class PaymentRequestStateTest : public testing::Test,
GURL("https://example.com/pay"), GURL("https://example.com/pay"),
url::Origin::Create(GURL("https://example.com")), spec_.get(), this, url::Origin::Create(GURL("https://example.com")), spec_.get(), this,
"en-US", &test_personal_data_manager_, &test_payment_request_delegate_, "en-US", &test_personal_data_manager_, &test_payment_request_delegate_,
base::BindRepeating(
[](const url::Origin& origin,
int64_t registration_id) { /* Intentionally left blank. */ }),
&journey_logger_); &journey_logger_);
state_->AddObserver(this); state_->AddObserver(this);
} }
......
...@@ -37,8 +37,7 @@ ServiceWorkerPaymentApp::ServiceWorkerPaymentApp( ...@@ -37,8 +37,7 @@ ServiceWorkerPaymentApp::ServiceWorkerPaymentApp(
const PaymentRequestSpec* spec, const PaymentRequestSpec* spec,
std::unique_ptr<content::StoredPaymentApp> stored_payment_app_info, std::unique_ptr<content::StoredPaymentApp> stored_payment_app_info,
bool is_incognito, bool is_incognito,
const base::RepeatingClosure& show_processing_spinner, const base::RepeatingClosure& show_processing_spinner)
const IdentityCallback& identity_callback)
: PaymentApp(0, PaymentApp::Type::SERVICE_WORKER_APP), : PaymentApp(0, PaymentApp::Type::SERVICE_WORKER_APP),
browser_context_(browser_context), browser_context_(browser_context),
top_origin_(top_origin), top_origin_(top_origin),
...@@ -48,10 +47,10 @@ ServiceWorkerPaymentApp::ServiceWorkerPaymentApp( ...@@ -48,10 +47,10 @@ ServiceWorkerPaymentApp::ServiceWorkerPaymentApp(
delegate_(nullptr), delegate_(nullptr),
is_incognito_(is_incognito), is_incognito_(is_incognito),
show_processing_spinner_(show_processing_spinner), show_processing_spinner_(show_processing_spinner),
identity_callback_(identity_callback),
can_make_payment_result_(false), can_make_payment_result_(false),
has_enrolled_instrument_result_(false), has_enrolled_instrument_result_(false),
needs_installation_(false) { needs_installation_(false),
web_contents_(nullptr) {
DCHECK(browser_context_); DCHECK(browser_context_);
DCHECK(top_origin_.is_valid()); DCHECK(top_origin_.is_valid());
DCHECK(frame_origin_.is_valid()); DCHECK(frame_origin_.is_valid());
...@@ -80,22 +79,22 @@ ServiceWorkerPaymentApp::ServiceWorkerPaymentApp( ...@@ -80,22 +79,22 @@ ServiceWorkerPaymentApp::ServiceWorkerPaymentApp(
std::unique_ptr<WebAppInstallationInfo> installable_payment_app_info, std::unique_ptr<WebAppInstallationInfo> installable_payment_app_info,
const std::string& enabled_method, const std::string& enabled_method,
bool is_incognito, bool is_incognito,
const base::RepeatingClosure& show_processing_spinner, const base::RepeatingClosure& show_processing_spinner)
const IdentityCallback& identity_callback)
: PaymentApp(0, PaymentApp::Type::SERVICE_WORKER_APP), : PaymentApp(0, PaymentApp::Type::SERVICE_WORKER_APP),
browser_context_(web_contents->GetBrowserContext()),
top_origin_(top_origin), top_origin_(top_origin),
frame_origin_(frame_origin), frame_origin_(frame_origin),
spec_(spec), spec_(spec),
delegate_(nullptr), delegate_(nullptr),
is_incognito_(is_incognito), is_incognito_(is_incognito),
show_processing_spinner_(show_processing_spinner), show_processing_spinner_(show_processing_spinner),
identity_callback_(identity_callback),
can_make_payment_result_(false), can_make_payment_result_(false),
has_enrolled_instrument_result_(false), has_enrolled_instrument_result_(false),
needs_installation_(true), needs_installation_(true),
web_contents_(web_contents), web_contents_(web_contents),
installable_web_app_info_(std::move(installable_payment_app_info)), installable_web_app_info_(std::move(installable_payment_app_info)),
installable_enabled_method_(enabled_method) { installable_enabled_method_(enabled_method) {
DCHECK(browser_context_);
DCHECK(web_contents_); DCHECK(web_contents_);
DCHECK(top_origin_.is_valid()); DCHECK(top_origin_.is_valid());
DCHECK(frame_origin_.is_valid()); DCHECK(frame_origin_.is_valid());
...@@ -114,14 +113,11 @@ ServiceWorkerPaymentApp::ServiceWorkerPaymentApp( ...@@ -114,14 +113,11 @@ ServiceWorkerPaymentApp::ServiceWorkerPaymentApp(
} }
ServiceWorkerPaymentApp::~ServiceWorkerPaymentApp() { ServiceWorkerPaymentApp::~ServiceWorkerPaymentApp() {
if (delegate_ && !needs_installation_) { if (delegate_) {
// If there's a payment in progress, abort it before destroying this so that // If there's a payment in progress, abort it before destroying this so that
// it can update its internal state. Since the PaymentRequest will be // it can update its internal state. Since the PaymentRequest will be
// destroyed, pass an empty callback to the payment app. // destroyed, pass an empty callback to the payment app.
content::PaymentAppProvider::GetInstance()->AbortPayment( AbortPaymentApp(/*abort_callback=*/base::DoNothing());
browser_context_, stored_payment_app_info_->registration_id,
url::Origin::Create(stored_payment_app_info_->scope),
*spec_->details().id, base::DoNothing());
} }
} }
...@@ -533,7 +529,11 @@ bool ServiceWorkerPaymentApp::HandlesPayerPhone() const { ...@@ -533,7 +529,11 @@ bool ServiceWorkerPaymentApp::HandlesPayerPhone() const {
void ServiceWorkerPaymentApp::OnPaymentAppIdentity(const url::Origin& origin, void ServiceWorkerPaymentApp::OnPaymentAppIdentity(const url::Origin& origin,
int64_t registration_id) { int64_t registration_id) {
identity_callback_.Run(origin, registration_id); registration_id_ = registration_id;
if (payment_handler_host_) {
payment_handler_host_->set_sw_origin_for_logs(origin);
payment_handler_host_->set_registration_id_for_logs(registration_id_);
}
} }
ukm::SourceId ServiceWorkerPaymentApp::UkmSourceId() { ukm::SourceId ServiceWorkerPaymentApp::UkmSourceId() {
...@@ -578,4 +578,14 @@ void ServiceWorkerPaymentApp::OnPaymentDetailsNotUpdated() { ...@@ -578,4 +578,14 @@ void ServiceWorkerPaymentApp::OnPaymentDetailsNotUpdated() {
payment_handler_host_->OnPaymentDetailsNotUpdated(); payment_handler_host_->OnPaymentDetailsNotUpdated();
} }
void ServiceWorkerPaymentApp::AbortPaymentApp(
base::OnceCallback<void(bool)> abort_callback) {
content::PaymentAppProvider::GetInstance()->AbortPayment(
browser_context_, registration_id_,
stored_payment_app_info_
? url::Origin::Create(stored_payment_app_info_->scope)
: url::Origin::Create(GURL(installable_web_app_info_->sw_scope)),
*spec_->details().id, std::move(abort_callback));
}
} // namespace payments } // namespace payments
...@@ -34,9 +34,6 @@ class PaymentHandlerHost; ...@@ -34,9 +34,6 @@ class PaymentHandlerHost;
// Represents a service worker based payment app. // Represents a service worker based payment app.
class ServiceWorkerPaymentApp : public PaymentApp { class ServiceWorkerPaymentApp : public PaymentApp {
public: public:
using IdentityCallback =
base::RepeatingCallback<void(const url::Origin&, int64_t)>;
// This constructor is used for a payment app that has been installed in // This constructor is used for a payment app that has been installed in
// Chrome. // Chrome.
ServiceWorkerPaymentApp( ServiceWorkerPaymentApp(
...@@ -46,8 +43,7 @@ class ServiceWorkerPaymentApp : public PaymentApp { ...@@ -46,8 +43,7 @@ class ServiceWorkerPaymentApp : public PaymentApp {
const PaymentRequestSpec* spec, const PaymentRequestSpec* spec,
std::unique_ptr<content::StoredPaymentApp> stored_payment_app_info, std::unique_ptr<content::StoredPaymentApp> stored_payment_app_info,
bool is_incognito, bool is_incognito,
const base::RepeatingClosure& show_processing_spinner, const base::RepeatingClosure& show_processing_spinner);
const IdentityCallback& identity_callback);
// This constructor is used for a payment app that has not been installed in // This constructor is used for a payment app that has not been installed in
// Chrome but can be installed when paying with it. // Chrome but can be installed when paying with it.
...@@ -59,8 +55,7 @@ class ServiceWorkerPaymentApp : public PaymentApp { ...@@ -59,8 +55,7 @@ class ServiceWorkerPaymentApp : public PaymentApp {
std::unique_ptr<WebAppInstallationInfo> installable_payment_app_info, std::unique_ptr<WebAppInstallationInfo> installable_payment_app_info,
const std::string& enabled_method, const std::string& enabled_method,
bool is_incognito, bool is_incognito,
const base::RepeatingClosure& show_processing_spinner, const base::RepeatingClosure& show_processing_spinner);
const IdentityCallback& identity_callback);
~ServiceWorkerPaymentApp() override; ~ServiceWorkerPaymentApp() override;
// The callback for ValidateCanMakePayment. // The callback for ValidateCanMakePayment.
...@@ -105,6 +100,7 @@ class ServiceWorkerPaymentApp : public PaymentApp { ...@@ -105,6 +100,7 @@ class ServiceWorkerPaymentApp : public PaymentApp {
bool IsWaitingForPaymentDetailsUpdate() const override; bool IsWaitingForPaymentDetailsUpdate() const override;
void UpdateWith(const mojom::PaymentDetailsPtr& details) override; void UpdateWith(const mojom::PaymentDetailsPtr& details) override;
void OnPaymentDetailsNotUpdated() override; void OnPaymentDetailsNotUpdated() override;
void AbortPaymentApp(base::OnceCallback<void(bool)> abort_callback) override;
private: private:
friend class ServiceWorkerPaymentAppTest; friend class ServiceWorkerPaymentAppTest;
...@@ -142,13 +138,12 @@ class ServiceWorkerPaymentApp : public PaymentApp { ...@@ -142,13 +138,12 @@ class ServiceWorkerPaymentApp : public PaymentApp {
// invoked. // invoked.
base::RepeatingClosure show_processing_spinner_; base::RepeatingClosure show_processing_spinner_;
// The callback that is notified of service worker registration identifier
// after the service worker is installed.
IdentityCallback identity_callback_;
base::WeakPtr<PaymentHandlerHost> payment_handler_host_; base::WeakPtr<PaymentHandlerHost> payment_handler_host_;
mojo::PendingRemote<mojom::PaymentHandlerHost> payment_handler_host_remote_; mojo::PendingRemote<mojom::PaymentHandlerHost> payment_handler_host_remote_;
// Service worker registration identifier. Used for aborting the payment app.
int64_t registration_id_ = 0;
// PaymentAppProvider::CanMakePayment result of this payment app. // PaymentAppProvider::CanMakePayment result of this payment app.
bool can_make_payment_result_; bool can_make_payment_result_;
bool has_enrolled_instrument_result_; bool has_enrolled_instrument_result_;
......
...@@ -74,9 +74,7 @@ class ServiceWorkerPaymentAppCreator { ...@@ -74,9 +74,7 @@ class ServiceWorkerPaymentAppCreator {
delegate_->GetTopOrigin(), delegate_->GetFrameOrigin(), delegate_->GetTopOrigin(), delegate_->GetFrameOrigin(),
delegate_->GetSpec(), std::move(installed_app.second), delegate_->GetSpec(), std::move(installed_app.second),
delegate_->GetPaymentRequestDelegate()->IsOffTheRecord(), delegate_->GetPaymentRequestDelegate()->IsOffTheRecord(),
show_processing_spinner, show_processing_spinner);
base::BindRepeating(
&PaymentAppFactory::Delegate::OnPaymentAppInstalled, delegate_));
app->ValidateCanMakePayment(base::BindOnce( app->ValidateCanMakePayment(base::BindOnce(
&ServiceWorkerPaymentAppCreator::OnSWPaymentAppValidated, &ServiceWorkerPaymentAppCreator::OnSWPaymentAppValidated,
weak_ptr_factory_.GetWeakPtr())); weak_ptr_factory_.GetWeakPtr()));
...@@ -90,9 +88,7 @@ class ServiceWorkerPaymentAppCreator { ...@@ -90,9 +88,7 @@ class ServiceWorkerPaymentAppCreator {
delegate_->GetFrameOrigin(), delegate_->GetSpec(), delegate_->GetFrameOrigin(), delegate_->GetSpec(),
std::move(installable_app.second), installable_app.first.spec(), std::move(installable_app.second), installable_app.first.spec(),
delegate_->GetPaymentRequestDelegate()->IsOffTheRecord(), delegate_->GetPaymentRequestDelegate()->IsOffTheRecord(),
show_processing_spinner, show_processing_spinner);
base::BindRepeating(
&PaymentAppFactory::Delegate::OnPaymentAppInstalled, delegate_));
app->ValidateCanMakePayment(base::BindOnce( app->ValidateCanMakePayment(base::BindOnce(
&ServiceWorkerPaymentAppCreator::OnSWPaymentAppValidated, &ServiceWorkerPaymentAppCreator::OnSWPaymentAppValidated,
weak_ptr_factory_.GetWeakPtr())); weak_ptr_factory_.GetWeakPtr()));
......
...@@ -115,10 +115,7 @@ class ServiceWorkerPaymentAppTest : public testing::Test, ...@@ -115,10 +115,7 @@ class ServiceWorkerPaymentAppTest : public testing::Test,
&browser_context_, GURL("https://testmerchant.com"), &browser_context_, GURL("https://testmerchant.com"),
GURL("https://testmerchant.com/bobpay"), spec_.get(), GURL("https://testmerchant.com/bobpay"), spec_.get(),
std::move(stored_app), /*is_incognito=*/false, std::move(stored_app), /*is_incognito=*/false,
/*show_processing_spinner=*/base::DoNothing(), /*show_processing_spinner=*/base::DoNothing());
base::BindRepeating(
[](const url::Origin& origin,
int64_t registration_id) { /* Intentionally left blank. */ }));
} }
ServiceWorkerPaymentApp* GetApp() { return app_.get(); } ServiceWorkerPaymentApp* GetApp() { return app_.get(); }
......
/*
* Copyright 2019 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.
*/
// An app that notifies the merchant that it was invoked, so it can be aborted.
// Should be used in conjunction with payment_handler_aborter.js.
let abortResponse = true;
self.addEventListener('canmakepayment', (event) => {
event.respondWith(true);
});
self.addEventListener('abortpayment', (event) => {
event.respondWith(abortResponse);
});
self.addEventListener('paymentrequest', (event) => {
abortResponse = event.methodData[0].data.abortResponse;
event.respondWith(new Promise(function() {
event.changePaymentMethod(
event.methodData[0].supportedMethods, {status: 'ready for abort'});
}));
});
{
"default_applications": ["abort_responder_app.json"],
"name": "Abort Responder App",
"icons": [{
"src": "icon.png",
"sizes": "40x40",
"type": "image/png"
}],
"serviceworker": {
"src": "abort_responder_app.js"
}
}
<!DOCTYPE html>
<!--
Copyright 2020 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.
-->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">
<title>Payment Method Change Event Waiter</title>
</head>
<body>
<script src="payment_handler_aborter.js"></script>
</body>
</html>
/*
* Copyright 2020 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.
*/
/**
* Launches a payment handler, waits for the payment handler to issue a payment
* method change event with 'status': 'ready for abort' (as, for example, done
* in abort_repsonder_app.js), then aborts it.
* @param {string} method - The payment method identifier to use.
* @param {boolean} abortResponse - Whether the app should be abortable.
* @return {string} - Either 'Abort completed' or an error message.
*/
async function launchAndAbort(method, abortResponse) { // eslint-disable-line no-unused-vars, max-len
try {
const details = {
total: {label: 'TEST', amount: {currency: 'USD', value: '0.01'}},
};
const request = new PaymentRequest(
[{supportedMethods: method, data: {abortResponse}}], details);
const eventPromise = new Promise((resolveEventPromise) => {
request.addEventListener('paymentmethodchange', (event) => {
event.updateWith(details);
resolveEventPromise(event);
});
});
const showRejectPromise = new Promise((resolveShowRejectPromise) => {
request.show().catch(resolveShowRejectPromise);
});
const event = await eventPromise;
if (event.methodDetails.status !== 'ready for abort') {
return event.methodDetails.status;
}
await request.abort();
await showRejectPromise;
return 'Abort completed';
} catch (e) {
return e.message;
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment