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/permissions/permission_context.h"
9 #include "chrome/browser/permissions/permission_context_base.h"
10 #include "chrome/browser/permissions/permission_request_id.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "components/content_settings/core/browser/host_content_settings_map.h"
13 #include "content/public/browser/permission_type.h"
14 #include "content/public/browser/render_frame_host.h"
15 #include "content/public/browser/render_process_host.h"
16 #include "content/public/browser/web_contents.h"
18 using content::PermissionStatus
;
19 using content::PermissionType
;
23 // Helper method to convert ContentSetting to PermissionStatus.
24 PermissionStatus
ContentSettingToPermissionStatus(ContentSetting setting
) {
26 case CONTENT_SETTING_ALLOW
:
27 case CONTENT_SETTING_SESSION_ONLY
:
28 return content::PERMISSION_STATUS_GRANTED
;
29 case CONTENT_SETTING_BLOCK
:
30 return content::PERMISSION_STATUS_DENIED
;
31 case CONTENT_SETTING_ASK
:
32 return content::PERMISSION_STATUS_ASK
;
33 case CONTENT_SETTING_DETECT_IMPORTANT_CONTENT
:
34 case CONTENT_SETTING_DEFAULT
:
35 case CONTENT_SETTING_NUM_SETTINGS
:
40 return content::PERMISSION_STATUS_DENIED
;
43 // Helper method to convert PermissionType to ContentSettingType.
44 ContentSettingsType
PermissionTypeToContentSetting(PermissionType permission
) {
46 case PermissionType::MIDI_SYSEX
:
47 return CONTENT_SETTINGS_TYPE_MIDI_SYSEX
;
48 case PermissionType::PUSH_MESSAGING
:
49 return CONTENT_SETTINGS_TYPE_PUSH_MESSAGING
;
50 case PermissionType::NOTIFICATIONS
:
51 return CONTENT_SETTINGS_TYPE_NOTIFICATIONS
;
52 case PermissionType::GEOLOCATION
:
53 return CONTENT_SETTINGS_TYPE_GEOLOCATION
;
54 case PermissionType::PROTECTED_MEDIA_IDENTIFIER
:
55 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
56 return CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER
;
61 case PermissionType::NUM
:
62 // This will hit the NOTREACHED below.
66 NOTREACHED() << "Unknown content setting for permission "
67 << static_cast<int>(permission
);
68 return CONTENT_SETTINGS_TYPE_DEFAULT
;
71 // Helper method that wraps a callback a void(PermissionStatus)
72 // callback into a void(ContentSetting) callback.
73 void PermissionStatusCallbackWrapper(
74 const base::Callback
<void(PermissionStatus
)>& callback
,
75 ContentSetting content_setting
) {
76 callback
.Run(ContentSettingToPermissionStatus(content_setting
));
79 } // anonymous namespace
81 struct PermissionManager::Subscription
{
82 PermissionType permission
;
83 GURL requesting_origin
;
84 GURL embedding_origin
;
85 base::Callback
<void(PermissionStatus
)> callback
;
86 ContentSetting current_value
;
89 PermissionManager::PermissionManager(Profile
* profile
)
93 PermissionManager::~PermissionManager() {
94 if (!subscriptions_
.IsEmpty())
95 profile_
->GetHostContentSettingsMap()->RemoveObserver(this);
98 void PermissionManager::RequestPermission(
99 PermissionType permission
,
100 content::RenderFrameHost
* render_frame_host
,
102 const GURL
& requesting_origin
,
104 const base::Callback
<void(PermissionStatus
)>& callback
) {
105 PermissionContextBase
* context
= PermissionContext::Get(profile_
, permission
);
107 callback
.Run(content::PERMISSION_STATUS_DENIED
);
111 int render_process_id
= render_frame_host
->GetProcess()->GetID();
112 int render_frame_id
= render_frame_host
->GetRoutingID();
113 const PermissionRequestID
request(render_process_id
,
118 context
->RequestPermission(
119 content::WebContents::FromRenderFrameHost(render_frame_host
),
120 request
, requesting_origin
, user_gesture
,
121 base::Bind(&PermissionStatusCallbackWrapper
,
125 void PermissionManager::CancelPermissionRequest(
126 PermissionType permission
,
127 content::RenderFrameHost
* render_frame_host
,
129 const GURL
& requesting_origin
) {
130 PermissionContextBase
* context
= PermissionContext::Get(profile_
, permission
);
134 int render_process_id
= render_frame_host
->GetProcess()->GetID();
135 int render_frame_id
= render_frame_host
->GetRoutingID();
136 const PermissionRequestID
request(render_process_id
,
141 context
->CancelPermissionRequest(
142 content::WebContents::FromRenderFrameHost(render_frame_host
), request
);
145 void PermissionManager::ResetPermission(PermissionType permission
,
146 const GURL
& requesting_origin
,
147 const GURL
& embedding_origin
) {
148 PermissionContextBase
* context
= PermissionContext::Get(profile_
, permission
);
152 context
->ResetPermission(requesting_origin
.GetOrigin(),
153 embedding_origin
.GetOrigin());
156 PermissionStatus
PermissionManager::GetPermissionStatus(
157 PermissionType permission
,
158 const GURL
& requesting_origin
,
159 const GURL
& embedding_origin
) {
160 PermissionContextBase
* context
= PermissionContext::Get(profile_
, permission
);
162 return content::PERMISSION_STATUS_DENIED
;
164 return ContentSettingToPermissionStatus(
165 context
->GetPermissionStatus(requesting_origin
.GetOrigin(),
166 embedding_origin
.GetOrigin()));
169 void PermissionManager::RegisterPermissionUsage(PermissionType permission
,
170 const GURL
& requesting_origin
,
171 const GURL
& embedding_origin
) {
172 profile_
->GetHostContentSettingsMap()->UpdateLastUsage(
175 PermissionTypeToContentSetting(permission
));
178 int PermissionManager::SubscribePermissionStatusChange(
179 PermissionType permission
,
180 const GURL
& requesting_origin
,
181 const GURL
& embedding_origin
,
182 const base::Callback
<void(PermissionStatus
)>& callback
) {
183 if (subscriptions_
.IsEmpty())
184 profile_
->GetHostContentSettingsMap()->AddObserver(this);
186 Subscription
* subscription
= new Subscription();
187 subscription
->permission
= permission
;
188 subscription
->requesting_origin
= requesting_origin
;
189 subscription
->embedding_origin
= embedding_origin
;
190 subscription
->callback
= callback
;
191 subscription
->current_value
= PermissionContext::Get(profile_
, permission
)
192 ->GetPermissionStatus(subscription
->requesting_origin
,
193 subscription
->embedding_origin
);
195 return subscriptions_
.Add(subscription
);
198 void PermissionManager::UnsubscribePermissionStatusChange(int subscription_id
) {
199 // Whether |subscription_id| is known will be checked by the Remove() call.
200 subscriptions_
.Remove(subscription_id
);
202 if (subscriptions_
.IsEmpty())
203 profile_
->GetHostContentSettingsMap()->RemoveObserver(this);
206 void PermissionManager::OnContentSettingChanged(
207 const ContentSettingsPattern
& primary_pattern
,
208 const ContentSettingsPattern
& secondary_pattern
,
209 ContentSettingsType content_type
,
210 std::string resource_identifier
) {
211 std::list
<base::Closure
> callbacks
;
213 for (SubscriptionsMap::iterator
iter(&subscriptions_
);
214 !iter
.IsAtEnd(); iter
.Advance()) {
215 Subscription
* subscription
= iter
.GetCurrentValue();
216 if (PermissionTypeToContentSetting(subscription
->permission
) !=
221 if (primary_pattern
.IsValid() &&
222 !primary_pattern
.Matches(subscription
->requesting_origin
))
224 if (secondary_pattern
.IsValid() &&
225 !secondary_pattern
.Matches(subscription
->embedding_origin
))
228 ContentSetting new_value
=
229 PermissionContext::Get(profile_
, subscription
->permission
)
230 ->GetPermissionStatus(subscription
->requesting_origin
,
231 subscription
->embedding_origin
);
232 if (subscription
->current_value
== new_value
)
235 subscription
->current_value
= new_value
;
237 // Add the callback to |callbacks| which will be run after the loop to
238 // prevent re-entrance issues.
240 base::Bind(subscription
->callback
,
241 ContentSettingToPermissionStatus(new_value
)));
244 for (const auto& callback
: callbacks
)