| // 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 "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_manager.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::Bind( |
| &PermissionSubscription::OnConnectionError, base::Unretained(this))); |
| } |
| |
| ~PermissionSubscription() { |
| DCHECK_NE(id_, 0); |
| BrowserContext* browser_context = context_->GetBrowserContext(); |
| DCHECK(browser_context); |
| if (browser_context->GetPermissionManager()) { |
| browser_context->GetPermissionManager() |
| ->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( |
| mojo::InterfaceRequest<blink::mojom::PermissionService> request) { |
| services_.push_back( |
| base::MakeUnique<PermissionServiceImpl>(this, std::move(request))); |
| } |
| |
| void PermissionServiceContext::CreateSubscription( |
| PermissionType permission_type, |
| const url::Origin& origin, |
| PermissionObserverPtr observer) { |
| BrowserContext* browser_context = GetBrowserContext(); |
| DCHECK(browser_context); |
| if (!browser_context->GetPermissionManager()) |
| return; |
| |
| auto subscription = |
| base::MakeUnique<PermissionSubscription>(this, std::move(observer)); |
| GURL requesting_origin(origin.Serialize()); |
| GURL embedding_origin = GetEmbeddingOrigin(); |
| int subscription_id = |
| browser_context->GetPermissionManager()->SubscribePermissionStatusChange( |
| permission_type, requesting_origin, |
| // If the embedding_origin is empty, we'll use the |origin| instead. |
| embedding_origin.is_empty() ? requesting_origin : embedding_origin, |
| base::Bind(&PermissionSubscription::OnPermissionStatusChanged, |
| base::Unretained(subscription.get()))); |
| subscription->set_id(subscription_id); |
| subscriptions_[subscription_id] = std::move(subscription); |
| } |
| |
| void PermissionServiceContext::ServiceHadConnectionError( |
| PermissionServiceImpl* service) { |
| auto it = std::find_if( |
| services_.begin(), services_.end(), |
| [service](const std::unique_ptr<PermissionServiceImpl>& this_service) { |
| return service == this_service.get(); |
| }); |
| DCHECK(it != services_.end()); |
| services_.erase(it); |
| } |
| |
| 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) { |
| CancelPendingOperations(old_host); |
| } |
| |
| void PermissionServiceContext::FrameDeleted( |
| RenderFrameHost* render_frame_host) { |
| CancelPendingOperations(render_frame_host); |
| } |
| |
| void PermissionServiceContext::DidFinishNavigation( |
| NavigationHandle* navigation_handle) { |
| if (!navigation_handle->HasCommitted() || navigation_handle->IsSameDocument()) |
| return; |
| |
| CancelPendingOperations(navigation_handle->GetRenderFrameHost()); |
| } |
| |
| void PermissionServiceContext::CancelPendingOperations( |
| RenderFrameHost* render_frame_host) { |
| DCHECK(render_frame_host_); |
| if (render_frame_host != render_frame_host_) |
| return; |
| |
| for (const auto& service : services_) |
| service->CancelPendingOperations(); |
| |
| subscriptions_.clear(); |
| } |
| |
| BrowserContext* PermissionServiceContext::GetBrowserContext() const { |
| if (!web_contents()) { |
| DCHECK(render_process_host_); |
| return render_process_host_->GetBrowserContext(); |
| } |
| return web_contents()->GetBrowserContext(); |
| } |
| |
| GURL PermissionServiceContext::GetEmbeddingOrigin() const { |
| return web_contents() ? web_contents()->GetLastCommittedURL().GetOrigin() |
| : GURL(); |
| } |
| |
| RenderFrameHost* PermissionServiceContext::render_frame_host() const { |
| return render_frame_host_; |
| } |
| |
| } // namespace content |