Commit 1875cc10 authored by gogerald's avatar gogerald Committed by Commit Bot

[Payments] Only close opened window for payment handler

Only allow one payment handler window is opened at any moment in
a browser context.

Bug: 753078
Change-Id: Ibba3694eab85be4a4f87d6d638286e0e1d969353
Reviewed-on: https://chromium-review.googlesource.com/963501
Commit-Queue: Ganggui Tang <gogerald@chromium.org>
Reviewed-by: default avatarMarijn Kruisselbrink <mek@chromium.org>
Reviewed-by: default avatarPavel Feldman <pfeldman@chromium.org>
Reviewed-by: default avatarRouslan Solomakhin <rouslan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#544217}
parent 10125460
......@@ -37,10 +37,12 @@ class RespondWithCallbacks
: public payments::mojom::PaymentHandlerResponseCallback {
public:
RespondWithCallbacks(
BrowserContext* browser_context,
ServiceWorkerMetrics::EventType event_type,
scoped_refptr<ServiceWorkerVersion> service_worker_version,
PaymentAppProvider::InvokePaymentAppCallback callback)
: service_worker_version_(service_worker_version),
: browser_context_(browser_context),
service_worker_version_(service_worker_version),
invoke_payment_app_callback_(std::move(callback)),
binding_(this),
weak_ptr_factory_(this) {
......@@ -80,7 +82,9 @@ class RespondWithCallbacks
base::BindOnce(std::move(invoke_payment_app_callback_),
std::move(response)));
CloseClientWindows();
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::BindOnce(&CloseClientWindowOnUIThread, browser_context_));
delete this;
}
......@@ -106,7 +110,9 @@ class RespondWithCallbacks
base::BindOnce(std::move(payment_event_result_callback_),
payment_aborted));
CloseClientWindows();
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::BindOnce(&CloseClientWindowOnUIThread, browser_context_));
delete this;
}
......@@ -129,7 +135,9 @@ class RespondWithCallbacks
if (event_type_ == ServiceWorkerMetrics::EventType::PAYMENT_REQUEST ||
event_type_ == ServiceWorkerMetrics::EventType::ABORT_PAYMENT) {
CloseClientWindows();
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::BindOnce(&CloseClientWindowOnUIThread, browser_context_));
}
delete this;
}
......@@ -139,51 +147,14 @@ class RespondWithCallbacks
private:
~RespondWithCallbacks() override {}
// Close all the windows in the payment handler service worker scope.
// Note that this will close not only the windows opened through
// PaymentRequestEvent.openWindow and Clients.openWindow(), but also the
// windows opened through typing the url in the ominibox only if they are in
// the payment handler service worker scope.
void CloseClientWindows() {
std::vector<std::pair<int, int>> ids;
for (const auto& controllee : service_worker_version_->controllee_map()) {
if (controllee.second->provider_type() ==
blink::mojom::ServiceWorkerProviderType::kForWindow) {
ids.emplace_back(std::make_pair(controllee.second->process_id(),
controllee.second->frame_id()));
}
}
if (ids.size() == 0)
return;
static void CloseClientWindowOnUIThread(BrowserContext* browser_context) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::BindOnce(&RespondWithCallbacks::CloseClientWindowsOnUIThread,
ids));
}
static void CloseClientWindowsOnUIThread(
const std::vector<std::pair<int, int>>& ids) {
for (const auto& id : ids) {
RenderFrameHost* frame_host =
RenderFrameHost::FromID(id.first, id.second);
if (frame_host == nullptr)
continue;
// Don't close windows that embed iframes with the payment app scope. Only
// top level contexts with the payment app scope should be closed.
if (frame_host->GetParent() != nullptr)
continue;
WebContents* web_contents = WebContents::FromRenderFrameHost(frame_host);
if (web_contents == nullptr)
continue;
web_contents->Close();
}
PaymentAppProvider::GetInstance()->CloseOpenedWindow(browser_context);
}
int request_id_;
BrowserContext* browser_context_;
ServiceWorkerMetrics::EventType event_type_;
scoped_refptr<ServiceWorkerVersion> service_worker_version_;
PaymentAppProvider::InvokePaymentAppCallback invoke_payment_app_callback_;
......@@ -269,6 +240,7 @@ void DispatchCanMakePaymentEvent(
}
void DispatchPaymentRequestEvent(
BrowserContext* browser_context,
payments::mojom::PaymentRequestEventDataPtr event_data,
PaymentAppProvider::InvokePaymentAppCallback callback,
scoped_refptr<ServiceWorkerVersion> active_version,
......@@ -289,9 +261,9 @@ void DispatchPaymentRequestEvent(
ServiceWorkerMetrics::EventType::PAYMENT_REQUEST, base::DoNothing());
// This object self-deletes after either success or error callback is invoked.
RespondWithCallbacks* invocation_callbacks =
new RespondWithCallbacks(ServiceWorkerMetrics::EventType::PAYMENT_REQUEST,
active_version, std::move(callback));
RespondWithCallbacks* invocation_callbacks = new RespondWithCallbacks(
browser_context, ServiceWorkerMetrics::EventType::PAYMENT_REQUEST,
active_version, std::move(callback));
active_version->event_dispatcher()->DispatchPaymentRequestEvent(
invocation_callbacks->request_id(), std::move(event_data),
......@@ -431,8 +403,8 @@ void PaymentAppProviderImpl::InvokePaymentApp(
StartServiceWorkerForDispatch(
browser_context, registration_id,
base::BindOnce(&DispatchPaymentRequestEvent, std::move(event_data),
std::move(callback)));
base::BindOnce(&DispatchPaymentRequestEvent, browser_context,
std::move(event_data), std::move(callback)));
}
void PaymentAppProviderImpl::InstallAndInvokePaymentApp(
......@@ -499,8 +471,36 @@ void PaymentAppProviderImpl::AbortPayment(BrowserContext* browser_context,
base::BindOnce(&DispatchAbortPaymentEvent, std::move(callback)));
}
PaymentAppProviderImpl::PaymentAppProviderImpl() {}
void PaymentAppProviderImpl::SetOpenedWindow(WebContents* web_contents) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
CloseOpenedWindow(web_contents->GetBrowserContext());
payment_handler_windows_[web_contents->GetBrowserContext()] =
std::make_unique<PaymentHandlerWindowObserver>(web_contents);
}
void PaymentAppProviderImpl::CloseOpenedWindow(
BrowserContext* browser_context) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto it = payment_handler_windows_.find(browser_context);
if (it != payment_handler_windows_.end()) {
if (it->second->web_contents() != nullptr) {
it->second->web_contents()->Close();
}
payment_handler_windows_.erase(it);
}
}
PaymentAppProviderImpl::PaymentAppProviderImpl() = default;
PaymentAppProviderImpl::~PaymentAppProviderImpl() = default;
PaymentAppProviderImpl::~PaymentAppProviderImpl() {}
PaymentAppProviderImpl::PaymentHandlerWindowObserver::
PaymentHandlerWindowObserver(WebContents* web_contents)
: WebContentsObserver(web_contents) {}
PaymentAppProviderImpl::PaymentHandlerWindowObserver::
~PaymentHandlerWindowObserver() = default;
} // namespace content
......@@ -9,6 +9,7 @@
#include "base/memory/singleton.h"
#include "content/common/content_export.h"
#include "content/public/browser/payment_app_provider.h"
#include "content/public/browser/web_contents_observer.h"
namespace content {
......@@ -41,6 +42,8 @@ class CONTENT_EXPORT PaymentAppProviderImpl : public PaymentAppProvider {
void AbortPayment(BrowserContext* browser_context,
int64_t registration_id,
PaymentEventResultCallback callback) override;
void SetOpenedWindow(WebContents* web_contents) override;
void CloseOpenedWindow(BrowserContext* browser_context) override;
private:
PaymentAppProviderImpl();
......@@ -48,6 +51,17 @@ class CONTENT_EXPORT PaymentAppProviderImpl : public PaymentAppProvider {
friend struct base::DefaultSingletonTraits<PaymentAppProviderImpl>;
// Note that constructor of WebContentsObserver is protected.
class PaymentHandlerWindowObserver : public WebContentsObserver {
public:
explicit PaymentHandlerWindowObserver(WebContents* web_contents);
~PaymentHandlerWindowObserver() override;
};
// Map to maintain at most one opened window per browser context.
std::map<BrowserContext*, std::unique_ptr<PaymentHandlerWindowObserver>>
payment_handler_windows_;
DISALLOW_COPY_AND_ASSIGN(PaymentAppProviderImpl);
};
......
......@@ -25,6 +25,7 @@
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/page_navigator.h"
#include "content/public/browser/payment_app_provider.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
......@@ -32,6 +33,7 @@
#include "content/public/common/child_process_host.h"
#include "services/network/public/mojom/request_context_frame_type.mojom.h"
#include "third_party/WebKit/public/mojom/page/page_visibility_state.mojom.h"
#include "ui/base/mojo/window_open_disposition.mojom.h"
#include "url/gurl.h"
namespace content {
......@@ -160,7 +162,9 @@ blink::mojom::ServiceWorkerClientInfoPtr FocusOnUI(
}
// This is only called for main frame navigations in OpenWindowOnUI().
void DidOpenURLOnUI(OpenURLCallback callback, WebContents* web_contents) {
void DidOpenURLOnUI(WindowType type,
OpenURLCallback callback,
WebContents* web_contents) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!web_contents) {
......@@ -183,6 +187,12 @@ void DidOpenURLOnUI(OpenURLCallback callback, WebContents* web_contents) {
new OpenURLObserver(web_contents,
rfhi->frame_tree_node()->frame_tree_node_id(),
std::move(callback));
if (type == WindowType::PAYMENT_HANDLER_WINDOW) {
// Set the opened web_contents to payment app provider to manage its life
// cycle.
PaymentAppProvider::GetInstance()->SetOpenedWindow(web_contents);
}
}
void OpenWindowOnUI(
......@@ -190,7 +200,7 @@ void OpenWindowOnUI(
const GURL& script_url,
int worker_process_id,
const scoped_refptr<ServiceWorkerContextWrapper>& context_wrapper,
WindowOpenDisposition disposition,
WindowType type,
OpenURLCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
......@@ -216,13 +226,15 @@ void OpenWindowOnUI(
url,
Referrer::SanitizeForRequest(
url, Referrer(script_url, blink::kWebReferrerPolicyDefault)),
disposition, ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
true /* is_renderer_initiated */);
type == WindowType::PAYMENT_HANDLER_WINDOW
? WindowOpenDisposition::NEW_POPUP
: WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui::PAGE_TRANSITION_AUTO_TOPLEVEL, true /* is_renderer_initiated */);
GetContentClient()->browser()->OpenURL(
browser_context, params,
base::AdaptCallbackForRepeating(
base::BindOnce(&DidOpenURLOnUI, std::move(callback))));
base::BindOnce(&DidOpenURLOnUI, type, std::move(callback))));
}
void NavigateClientOnUI(const GURL& url,
......@@ -446,14 +458,14 @@ void OpenWindow(const GURL& url,
const GURL& script_url,
int worker_process_id,
const base::WeakPtr<ServiceWorkerContextCore>& context,
WindowOpenDisposition disposition,
WindowType type,
NavigationCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::BindOnce(
&OpenWindowOnUI, url, script_url, worker_process_id,
base::WrapRefCounted(context->wrapper()), disposition,
base::WrapRefCounted(context->wrapper()), type,
base::BindOnce(&DidNavigate, context, script_url.GetOrigin(),
std::move(callback))));
}
......
......@@ -12,7 +12,6 @@
#include "base/memory/weak_ptr.h"
#include "content/common/service_worker/service_worker_status_code.h"
#include "third_party/WebKit/public/mojom/service_worker/service_worker_client.mojom.h"
#include "ui/base/mojo/window_open_disposition.mojom.h"
class GURL;
......@@ -34,6 +33,12 @@ using ServiceWorkerClientPtrs =
using ClientsCallback =
base::OnceCallback<void(std::unique_ptr<ServiceWorkerClientPtrs> clients)>;
// The type of an opened window.
enum class WindowType {
NEW_TAB_WINDOW = 0,
PAYMENT_HANDLER_WINDOW,
};
// Focuses the window client associated with |provider_host|. |callback| is
// called with the client information on completion.
void FocusWindowClient(ServiceWorkerProviderHost* provider_host,
......@@ -45,7 +50,7 @@ void OpenWindow(const GURL& url,
const GURL& script_url,
int worker_process_id,
const base::WeakPtr<ServiceWorkerContextCore>& context,
WindowOpenDisposition disposition,
WindowType type,
NavigationCallback callback);
// Navigates the client specified by |process_id| and |frame_id| to |url|.
......
......@@ -26,7 +26,6 @@
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/service_worker/embedded_worker_registry.h"
#include "content/browser/service_worker/payment_handler_support.h"
#include "content/browser/service_worker/service_worker_client_utils.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_installed_scripts_sender.h"
......@@ -1122,7 +1121,7 @@ void ServiceWorkerVersion::GetClient(const std::string& client_uuid,
void ServiceWorkerVersion::OpenNewTab(const GURL& url,
OpenNewTabCallback callback) {
OpenWindow(url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
OpenWindow(url, service_worker_client_utils::WindowType::NEW_TAB_WINDOW,
std::move(callback));
}
......@@ -1140,9 +1139,9 @@ void ServiceWorkerVersion::OpenPaymentHandlerWindow(
PaymentHandlerSupport::ShowPaymentHandlerWindow(
url, context_.get(),
base::BindOnce(&DidShowPaymentHandlerWindow, url, context_),
base::BindOnce(&ServiceWorkerVersion::OpenWindow,
weak_factory_.GetWeakPtr(), url,
WindowOpenDisposition::NEW_POPUP),
base::BindOnce(
&ServiceWorkerVersion::OpenWindow, weak_factory_.GetWeakPtr(), url,
service_worker_client_utils::WindowType::PAYMENT_HANDLER_WINDOW),
std::move(callback));
}
......@@ -1316,9 +1315,10 @@ void ServiceWorkerVersion::OnClearCachedMetadataFinished(int64_t callback_id,
listener.OnCachedMetadataUpdated(this, 0);
}
void ServiceWorkerVersion::OpenWindow(GURL url,
WindowOpenDisposition disposition,
OpenNewTabCallback callback) {
void ServiceWorkerVersion::OpenWindow(
GURL url,
service_worker_client_utils::WindowType type,
OpenNewTabCallback callback) {
// Just respond failure if we are shutting down.
if (!context_) {
std::move(callback).Run(
......@@ -1351,7 +1351,7 @@ void ServiceWorkerVersion::OpenWindow(GURL url,
}
service_worker_client_utils::OpenWindow(
url, script_url_, embedded_worker_->process_id(), context_, disposition,
url, script_url_, embedded_worker_->process_id(), context_, type,
base::BindOnce(&OnOpenWindowFinished, std::move(callback)));
}
......
......@@ -30,6 +30,7 @@
#include "base/timer/timer.h"
#include "content/browser/service_worker/embedded_worker_instance.h"
#include "content/browser/service_worker/embedded_worker_status.h"
#include "content/browser/service_worker/service_worker_client_utils.h"
#include "content/browser/service_worker/service_worker_context_request_handler.h"
#include "content/browser/service_worker/service_worker_metrics.h"
#include "content/browser/service_worker/service_worker_script_cache_map.h"
......@@ -46,7 +47,6 @@
#include "third_party/WebKit/public/mojom/service_worker/service_worker_client.mojom.h"
#include "third_party/WebKit/public/mojom/service_worker/service_worker_event_status.mojom.h"
#include "third_party/WebKit/public/platform/web_feature.mojom.h"
#include "ui/base/mojo/window_open_disposition.mojom.h"
#include "url/gurl.h"
#include "url/origin.h"
......@@ -650,7 +650,7 @@ class CONTENT_EXPORT ServiceWorkerVersion
int result);
void OnClearCachedMetadataFinished(int64_t callback_id, int result);
void OpenWindow(GURL url,
WindowOpenDisposition disposition,
service_worker_client_utils::WindowType type,
OpenNewTabCallback callback);
void OnPongFromWorker();
......
......@@ -68,6 +68,13 @@ class CONTENT_EXPORT PaymentAppProvider {
int64_t registration_id,
PaymentEventResultCallback callback) = 0;
// Set opened window for payment handler. Note that we maintain at most one
// opened window for payment handler at any moment in a browser context. The
// previously opened window in the same browser context will be closed after
// calling this interface.
virtual void SetOpenedWindow(WebContents* web_contents) = 0;
virtual void CloseOpenedWindow(BrowserContext* browser_context) = 0;
protected:
virtual ~PaymentAppProvider() {}
};
......
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