1 // Copyright 2015 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.
5 #include "chrome/browser/permissions/permission_manager.h"
7 #include "base/callback.h"
8 #include "chrome/browser/content_settings/permission_context_base.h"
9 #include "chrome/browser/permissions/permission_context.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "components/content_settings/core/browser/host_content_settings_map.h"
12 #include "components/content_settings/core/common/permission_request_id.h"
13 #include "content/public/browser/permission_type.h"
14 #include "content/public/browser/render_process_host.h"
15 #include "content/public/browser/render_view_host.h"
16 #include "content/public/browser/web_contents.h"
20 // Helper method to convert ContentSetting to content::PermissionStatus.
21 content::PermissionStatus
22 ContentSettingToPermissionStatus(ContentSetting setting
) {
24 case CONTENT_SETTING_ALLOW
:
25 case CONTENT_SETTING_SESSION_ONLY
:
26 return content::PERMISSION_STATUS_GRANTED
;
27 case CONTENT_SETTING_BLOCK
:
28 return content::PERMISSION_STATUS_DENIED
;
29 case CONTENT_SETTING_ASK
:
30 return content::PERMISSION_STATUS_ASK
;
31 case CONTENT_SETTING_DETECT_IMPORTANT_CONTENT
:
32 case CONTENT_SETTING_DEFAULT
:
33 case CONTENT_SETTING_NUM_SETTINGS
:
38 return content::PERMISSION_STATUS_DENIED
;
41 // Helper method to convert content::PermissionType to ContentSettingType.
42 ContentSettingsType
PermissionTypeToContentSetting(
43 content::PermissionType permission
) {
45 case content::PermissionType::MIDI_SYSEX
:
46 return CONTENT_SETTINGS_TYPE_MIDI_SYSEX
;
47 case content::PermissionType::PUSH_MESSAGING
:
48 return CONTENT_SETTINGS_TYPE_PUSH_MESSAGING
;
49 case content::PermissionType::NOTIFICATIONS
:
50 return CONTENT_SETTINGS_TYPE_NOTIFICATIONS
;
51 case content::PermissionType::GEOLOCATION
:
52 return CONTENT_SETTINGS_TYPE_GEOLOCATION
;
53 case content::PermissionType::PROTECTED_MEDIA_IDENTIFIER
:
54 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
55 return CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER
;
60 case content::PermissionType::NUM
:
61 // This will hit the NOTREACHED below.
65 NOTREACHED() << "Unknown content setting for permission "
66 << static_cast<int>(permission
);
67 return CONTENT_SETTINGS_TYPE_DEFAULT
;
70 // Helper method that wraps a callback a void(content::PermissionStatus)
71 // callback into a void(ContentSetting) callback.
72 void PermissionStatusCallbackWrapper(
73 const base::Callback
<void(content::PermissionStatus
)>& callback
,
74 ContentSetting content_setting
) {
75 callback
.Run(ContentSettingToPermissionStatus(content_setting
));
78 } // anonymous namespace
80 struct PermissionManager::Subscription
{
81 content::PermissionType permission
;
82 GURL requesting_origin
;
83 GURL embedding_origin
;
84 base::Callback
<void(content::PermissionStatus
)> callback
;
85 ContentSetting current_value
;
88 PermissionManager::PermissionManager(Profile
* profile
)
92 PermissionManager::~PermissionManager() {
93 if (!subscriptions_
.IsEmpty())
94 profile_
->GetHostContentSettingsMap()->RemoveObserver(this);
97 void PermissionManager::RequestPermission(
98 content::PermissionType permission
,
99 content::WebContents
* web_contents
,
101 const GURL
& requesting_origin
,
103 const base::Callback
<void(content::PermissionStatus
)>& callback
) {
104 PermissionContextBase
* context
= PermissionContext::Get(profile_
, permission
);
106 callback
.Run(content::PERMISSION_STATUS_DENIED
);
110 int render_process_id
= web_contents
->GetRenderProcessHost()->GetID();
111 int render_view_id
= web_contents
->GetRenderViewHost()->GetRoutingID();
112 const PermissionRequestID
request(render_process_id
,
117 context
->RequestPermission(web_contents
, request
, requesting_origin
,
119 base::Bind(&PermissionStatusCallbackWrapper
,
123 void PermissionManager::CancelPermissionRequest(
124 content::PermissionType permission
,
125 content::WebContents
* web_contents
,
127 const GURL
& requesting_origin
) {
128 PermissionContextBase
* context
= PermissionContext::Get(profile_
, permission
);
132 int render_process_id
= web_contents
->GetRenderProcessHost()->GetID();
133 int render_view_id
= web_contents
->GetRenderViewHost()->GetRoutingID();
134 const PermissionRequestID
request(render_process_id
,
139 context
->CancelPermissionRequest(web_contents
, request
);
142 void PermissionManager::ResetPermission(
143 content::PermissionType permission
,
144 const GURL
& requesting_origin
,
145 const GURL
& embedding_origin
) {
146 PermissionContextBase
* context
= PermissionContext::Get(profile_
, permission
);
150 context
->ResetPermission(requesting_origin
.GetOrigin(),
151 embedding_origin
.GetOrigin());
154 content::PermissionStatus
PermissionManager::GetPermissionStatus(
155 content::PermissionType permission
,
156 const GURL
& requesting_origin
,
157 const GURL
& embedding_origin
) {
158 PermissionContextBase
* context
= PermissionContext::Get(profile_
, permission
);
160 return content::PERMISSION_STATUS_DENIED
;
162 return ContentSettingToPermissionStatus(
163 context
->GetPermissionStatus(requesting_origin
.GetOrigin(),
164 embedding_origin
.GetOrigin()));
167 void PermissionManager::RegisterPermissionUsage(
168 content::PermissionType permission
,
169 const GURL
& requesting_origin
,
170 const GURL
& embedding_origin
) {
171 profile_
->GetHostContentSettingsMap()->UpdateLastUsage(
174 PermissionTypeToContentSetting(permission
));
177 int PermissionManager::SubscribePermissionStatusChange(
178 content::PermissionType permission
,
179 const GURL
& requesting_origin
,
180 const GURL
& embedding_origin
,
181 const base::Callback
<void(content::PermissionStatus
)>& callback
) {
182 if (subscriptions_
.IsEmpty())
183 profile_
->GetHostContentSettingsMap()->AddObserver(this);
185 Subscription
* subscription
= new Subscription();
186 subscription
->permission
= permission
;
187 subscription
->requesting_origin
= requesting_origin
;
188 subscription
->embedding_origin
= embedding_origin
;
189 subscription
->callback
= callback
;
190 subscription
->current_value
= PermissionContext::Get(profile_
, permission
)
191 ->GetPermissionStatus(subscription
->requesting_origin
,
192 subscription
->embedding_origin
);
194 return subscriptions_
.Add(subscription
);
197 void PermissionManager::UnsubscribePermissionStatusChange(int subscription_id
) {
198 // Whether |subscription_id| is known will be checked by the Remove() call.
199 subscriptions_
.Remove(subscription_id
);
201 if (subscriptions_
.IsEmpty())
202 profile_
->GetHostContentSettingsMap()->RemoveObserver(this);
205 void PermissionManager::OnContentSettingChanged(
206 const ContentSettingsPattern
& primary_pattern
,
207 const ContentSettingsPattern
& secondary_pattern
,
208 ContentSettingsType content_type
,
209 std::string resource_identifier
) {
210 std::list
<base::Closure
> callbacks
;
212 for (SubscriptionsMap::iterator
iter(&subscriptions_
);
213 !iter
.IsAtEnd(); iter
.Advance()) {
214 Subscription
* subscription
= iter
.GetCurrentValue();
215 if (PermissionTypeToContentSetting(subscription
->permission
) !=
220 if (primary_pattern
.IsValid() &&
221 !primary_pattern
.Matches(subscription
->requesting_origin
))
223 if (secondary_pattern
.IsValid() &&
224 !secondary_pattern
.Matches(subscription
->embedding_origin
))
227 ContentSetting new_value
=
228 PermissionContext::Get(profile_
, subscription
->permission
)
229 ->GetPermissionStatus(subscription
->requesting_origin
,
230 subscription
->embedding_origin
);
231 if (subscription
->current_value
== new_value
)
234 subscription
->current_value
= new_value
;
236 // Add the callback to |callbacks| which will be run after the loop to
237 // prevent re-entrance issues.
239 base::Bind(subscription
->callback
,
240 ContentSettingToPermissionStatus(new_value
)));
243 for (const auto& callback
: callbacks
)