1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/permissions/permission_service_context.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "content/browser/permissions/permission_controller_impl.h"
11 #include "content/browser/permissions/permission_service_impl.h"
12 #include "content/public/browser/browser_context.h"
13 #include "content/public/browser/navigation_handle.h"
14 #include "content/public/browser/permission_controller.h"
15 #include "content/public/browser/render_frame_host.h"
16 #include "content/public/browser/render_process_host.h"
17 #include "content/public/browser/web_contents.h"
18 #include "mojo/public/cpp/bindings/remote.h"
19
20 namespace content {
21
22 class PermissionServiceContext::PermissionSubscription {
23 public:
PermissionSubscription(PermissionServiceContext * context,mojo::PendingRemote<blink::mojom::PermissionObserver> observer)24 PermissionSubscription(
25 PermissionServiceContext* context,
26 mojo::PendingRemote<blink::mojom::PermissionObserver> observer)
27 : context_(context), observer_(std::move(observer)) {
28 observer_.set_disconnect_handler(base::BindOnce(
29 &PermissionSubscription::OnConnectionError, base::Unretained(this)));
30 }
31 PermissionSubscription(const PermissionSubscription&) = delete;
32 PermissionSubscription& operator=(const PermissionSubscription&) = delete;
33
~PermissionSubscription()34 ~PermissionSubscription() {
35 DCHECK_NE(id_, 0);
36 BrowserContext* browser_context = context_->GetBrowserContext();
37 if (browser_context) {
38 PermissionControllerImpl::FromBrowserContext(browser_context)
39 ->UnsubscribePermissionStatusChange(id_);
40 }
41 }
42
OnConnectionError()43 void OnConnectionError() {
44 DCHECK_NE(id_, 0);
45 context_->ObserverHadConnectionError(id_);
46 }
47
OnPermissionStatusChanged(blink::mojom::PermissionStatus status)48 void OnPermissionStatusChanged(blink::mojom::PermissionStatus status) {
49 observer_->OnPermissionStatusChange(status);
50 }
51
set_id(int id)52 void set_id(int id) { id_ = id; }
53
54 private:
55 PermissionServiceContext* const context_;
56 mojo::Remote<blink::mojom::PermissionObserver> observer_;
57 int id_ = 0;
58 };
59
PermissionServiceContext(RenderFrameHost * render_frame_host)60 PermissionServiceContext::PermissionServiceContext(
61 RenderFrameHost* render_frame_host)
62 : WebContentsObserver(WebContents::FromRenderFrameHost(render_frame_host)),
63 render_frame_host_(render_frame_host),
64 render_process_host_(nullptr) {
65 }
66
PermissionServiceContext(RenderProcessHost * render_process_host)67 PermissionServiceContext::PermissionServiceContext(
68 RenderProcessHost* render_process_host)
69 : WebContentsObserver(nullptr),
70 render_frame_host_(nullptr),
71 render_process_host_(render_process_host) {
72 }
73
~PermissionServiceContext()74 PermissionServiceContext::~PermissionServiceContext() {
75 }
76
CreateService(mojo::PendingReceiver<blink::mojom::PermissionService> receiver)77 void PermissionServiceContext::CreateService(
78 mojo::PendingReceiver<blink::mojom::PermissionService> receiver) {
79 DCHECK(render_frame_host_);
80 services_.Add(std::make_unique<PermissionServiceImpl>(
81 this, render_frame_host_->GetLastCommittedOrigin()),
82 std::move(receiver));
83 }
84
CreateServiceForWorker(const url::Origin & origin,mojo::PendingReceiver<blink::mojom::PermissionService> receiver)85 void PermissionServiceContext::CreateServiceForWorker(
86 const url::Origin& origin,
87 mojo::PendingReceiver<blink::mojom::PermissionService> receiver) {
88 services_.Add(std::make_unique<PermissionServiceImpl>(this, origin),
89 std::move(receiver));
90 }
91
CreateSubscription(PermissionType permission_type,const url::Origin & origin,blink::mojom::PermissionStatus current_status,blink::mojom::PermissionStatus last_known_status,mojo::PendingRemote<blink::mojom::PermissionObserver> observer)92 void PermissionServiceContext::CreateSubscription(
93 PermissionType permission_type,
94 const url::Origin& origin,
95 blink::mojom::PermissionStatus current_status,
96 blink::mojom::PermissionStatus last_known_status,
97 mojo::PendingRemote<blink::mojom::PermissionObserver> observer) {
98 BrowserContext* browser_context = GetBrowserContext();
99 if (!browser_context)
100 return;
101
102 auto subscription =
103 std::make_unique<PermissionSubscription>(this, std::move(observer));
104
105 if (current_status != last_known_status) {
106 subscription->OnPermissionStatusChanged(current_status);
107 last_known_status = current_status;
108 }
109
110 GURL requesting_origin(origin.Serialize());
111 int subscription_id =
112 PermissionControllerImpl::FromBrowserContext(browser_context)
113 ->SubscribePermissionStatusChange(
114 permission_type, render_frame_host_, requesting_origin,
115 base::BindRepeating(
116 &PermissionSubscription::OnPermissionStatusChanged,
117 base::Unretained(subscription.get())));
118 subscription->set_id(subscription_id);
119 subscriptions_[subscription_id] = std::move(subscription);
120 }
121
ObserverHadConnectionError(int subscription_id)122 void PermissionServiceContext::ObserverHadConnectionError(int subscription_id) {
123 size_t erased = subscriptions_.erase(subscription_id);
124 DCHECK_EQ(1u, erased);
125 }
126
RenderFrameHostChanged(RenderFrameHost * old_host,RenderFrameHost * new_host)127 void PermissionServiceContext::RenderFrameHostChanged(
128 RenderFrameHost* old_host,
129 RenderFrameHost* new_host) {
130 CloseBindings(old_host);
131 }
132
FrameDeleted(RenderFrameHost * render_frame_host)133 void PermissionServiceContext::FrameDeleted(
134 RenderFrameHost* render_frame_host) {
135 CloseBindings(render_frame_host);
136 }
137
DidFinishNavigation(NavigationHandle * navigation_handle)138 void PermissionServiceContext::DidFinishNavigation(
139 NavigationHandle* navigation_handle) {
140 if (!navigation_handle->HasCommitted() || navigation_handle->IsSameDocument())
141 return;
142
143 CloseBindings(navigation_handle->GetRenderFrameHost());
144 }
145
CloseBindings(RenderFrameHost * render_frame_host)146 void PermissionServiceContext::CloseBindings(
147 RenderFrameHost* render_frame_host) {
148 DCHECK(render_frame_host_);
149 if (render_frame_host != render_frame_host_)
150 return;
151
152 services_.Clear();
153 subscriptions_.clear();
154 }
155
GetBrowserContext() const156 BrowserContext* PermissionServiceContext::GetBrowserContext() const {
157 // web_contents() may return nullptr during teardown, or when showing
158 // an interstitial.
159 if (web_contents())
160 return web_contents()->GetBrowserContext();
161
162 if (render_process_host_)
163 return render_process_host_->GetBrowserContext();
164
165 return nullptr;
166 }
167
GetEmbeddingOrigin() const168 GURL PermissionServiceContext::GetEmbeddingOrigin() const {
169 return web_contents() ? web_contents()->GetLastCommittedURL().GetOrigin()
170 : GURL();
171 }
172
173 } // namespace content
174