blob: 8a4e881750bc50b941ce1e61740d95f12ba3f857 [file] [log] [blame]
// Copyright 2014 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 "content/browser/permissions/permission_service_context.h"
#include <utility>
#include "base/bind.h"
#include "content/browser/permissions/permission_controller_impl.h"
#include "content/browser/permissions/permission_service_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/permission_controller.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
using blink::mojom::PermissionObserverPtr;
namespace content {
class PermissionServiceContext::PermissionSubscription {
public:
PermissionSubscription(PermissionServiceContext* context,
PermissionObserverPtr observer)
: context_(context), observer_(std::move(observer)) {
observer_.set_connection_error_handler(base::BindOnce(
&PermissionSubscription::OnConnectionError, base::Unretained(this)));
}
~PermissionSubscription() {
DCHECK_NE(id_, 0);
BrowserContext* browser_context = context_->GetBrowserContext();
if (browser_context) {
PermissionControllerImpl::FromBrowserContext(browser_context)
->UnsubscribePermissionStatusChange(id_);
}
}
void OnConnectionError() {
DCHECK_NE(id_, 0);
context_->ObserverHadConnectionError(id_);
}
void OnPermissionStatusChanged(blink::mojom::PermissionStatus status) {
observer_->OnPermissionStatusChange(status);
}
void set_id(int id) { id_ = id; }
private:
PermissionServiceContext* context_;
PermissionObserverPtr observer_;
int id_ = 0;
};
PermissionServiceContext::PermissionServiceContext(
RenderFrameHost* render_frame_host)
: WebContentsObserver(WebContents::FromRenderFrameHost(render_frame_host)),
render_frame_host_(render_frame_host),
render_process_host_(nullptr) {
}
PermissionServiceContext::PermissionServiceContext(
RenderProcessHost* render_process_host)
: WebContentsObserver(nullptr),
render_frame_host_(nullptr),
render_process_host_(render_process_host) {
}
PermissionServiceContext::~PermissionServiceContext() {
}
void PermissionServiceContext::CreateService(
blink::mojom::PermissionServiceRequest request) {
DCHECK(render_frame_host_);
services_.AddBinding(std::make_unique<PermissionServiceImpl>(
this, render_frame_host_->GetLastCommittedOrigin()),
std::move(request));
}
void PermissionServiceContext::CreateServiceForWorker(
blink::mojom::PermissionServiceRequest request,
const url::Origin& origin) {
services_.AddBinding(std::make_unique<PermissionServiceImpl>(this, origin),
std::move(request));
}
void PermissionServiceContext::CreateSubscription(
PermissionType permission_type,
const url::Origin& origin,
PermissionObserverPtr observer) {
BrowserContext* browser_context = GetBrowserContext();
if (!browser_context)
return;
auto subscription =
std::make_unique<PermissionSubscription>(this, std::move(observer));
GURL requesting_origin(origin.Serialize());
int subscription_id =
PermissionControllerImpl::FromBrowserContext(browser_context)
->SubscribePermissionStatusChange(
permission_type, render_frame_host_, requesting_origin,
base::Bind(&PermissionSubscription::OnPermissionStatusChanged,
base::Unretained(subscription.get())));
subscription->set_id(subscription_id);
subscriptions_[subscription_id] = std::move(subscription);
}
void PermissionServiceContext::ObserverHadConnectionError(int subscription_id) {
auto it = subscriptions_.find(subscription_id);
DCHECK(it != subscriptions_.end());
subscriptions_.erase(it);
}
void PermissionServiceContext::RenderFrameHostChanged(
RenderFrameHost* old_host,
RenderFrameHost* new_host) {
CloseBindings(old_host);
}
void PermissionServiceContext::FrameDeleted(
RenderFrameHost* render_frame_host) {
CloseBindings(render_frame_host);
}
void PermissionServiceContext::DidFinishNavigation(
NavigationHandle* navigation_handle) {
if (!navigation_handle->HasCommitted() || navigation_handle->IsSameDocument())
return;
CloseBindings(navigation_handle->GetRenderFrameHost());
}
void PermissionServiceContext::CloseBindings(
RenderFrameHost* render_frame_host) {
DCHECK(render_frame_host_);
if (render_frame_host != render_frame_host_)
return;
services_.CloseAllBindings();
subscriptions_.clear();
}
BrowserContext* PermissionServiceContext::GetBrowserContext() const {
// web_contents() may return nullptr during teardown, or when showing
// an interstitial.
if (web_contents())
return web_contents()->GetBrowserContext();
if (render_process_host_)
return render_process_host_->GetBrowserContext();
return nullptr;
}
GURL PermissionServiceContext::GetEmbeddingOrigin() const {
return web_contents() ? web_contents()->GetLastCommittedURL().GetOrigin()
: GURL();
}
RenderFrameHost* PermissionServiceContext::render_frame_host() const {
return render_frame_host_;
}
} // namespace content