OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/permissions/permission_manager.h" | 5 #include "chrome/browser/permissions/permission_manager.h" |
6 | 6 |
7 #include "base/callback.h" | 7 #include "base/callback.h" |
8 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" | 8 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" |
9 #include "chrome/browser/permissions/permission_context.h" | 9 #include "chrome/browser/permissions/permission_context.h" |
10 #include "chrome/browser/permissions/permission_context_base.h" | 10 #include "chrome/browser/permissions/permission_context_base.h" |
(...skipping 28 matching lines...) Expand all Loading... |
39 case CONTENT_SETTING_DETECT_IMPORTANT_CONTENT: | 39 case CONTENT_SETTING_DETECT_IMPORTANT_CONTENT: |
40 case CONTENT_SETTING_DEFAULT: | 40 case CONTENT_SETTING_DEFAULT: |
41 case CONTENT_SETTING_NUM_SETTINGS: | 41 case CONTENT_SETTING_NUM_SETTINGS: |
42 break; | 42 break; |
43 } | 43 } |
44 | 44 |
45 NOTREACHED(); | 45 NOTREACHED(); |
46 return content::PERMISSION_STATUS_DENIED; | 46 return content::PERMISSION_STATUS_DENIED; |
47 } | 47 } |
48 | 48 |
| 49 // Wrap a callback taking a PermissionStatus to pass it as a callback taking a |
| 50 // ContentSetting. |
| 51 void ContentSettingToPermissionStatusCallbackWrapper( |
| 52 const base::Callback<void(PermissionStatus)>& callback, |
| 53 ContentSetting setting) { |
| 54 callback.Run(ContentSettingToPermissionStatus(setting)); |
| 55 } |
| 56 |
49 // Helper method to convert PermissionType to ContentSettingType. | 57 // Helper method to convert PermissionType to ContentSettingType. |
50 ContentSettingsType PermissionTypeToContentSetting(PermissionType permission) { | 58 ContentSettingsType PermissionTypeToContentSetting(PermissionType permission) { |
51 switch (permission) { | 59 switch (permission) { |
52 case PermissionType::MIDI_SYSEX: | 60 case PermissionType::MIDI_SYSEX: |
53 return CONTENT_SETTINGS_TYPE_MIDI_SYSEX; | 61 return CONTENT_SETTINGS_TYPE_MIDI_SYSEX; |
54 case PermissionType::PUSH_MESSAGING: | 62 case PermissionType::PUSH_MESSAGING: |
55 return CONTENT_SETTINGS_TYPE_PUSH_MESSAGING; | 63 return CONTENT_SETTINGS_TYPE_PUSH_MESSAGING; |
56 case PermissionType::NOTIFICATIONS: | 64 case PermissionType::NOTIFICATIONS: |
57 return CONTENT_SETTINGS_TYPE_NOTIFICATIONS; | 65 return CONTENT_SETTINGS_TYPE_NOTIFICATIONS; |
58 case PermissionType::GEOLOCATION: | 66 case PermissionType::GEOLOCATION: |
(...skipping 30 matching lines...) Expand all Loading... |
89 // return nullptr in PermissionContext::Get since they don't have a context. | 97 // return nullptr in PermissionContext::Get since they don't have a context. |
90 bool IsConstantPermission(PermissionType type) { | 98 bool IsConstantPermission(PermissionType type) { |
91 switch (type) { | 99 switch (type) { |
92 case PermissionType::MIDI: | 100 case PermissionType::MIDI: |
93 return true; | 101 return true; |
94 default: | 102 default: |
95 return false; | 103 return false; |
96 } | 104 } |
97 } | 105 } |
98 | 106 |
| 107 void PermissionRequestResponseCallbackWrapper( |
| 108 const base::Callback<void(PermissionStatus)>& callback, |
| 109 const std::vector<PermissionStatus>& vector) { |
| 110 DCHECK_EQ(vector.size(), 1ul); |
| 111 callback.Run(vector[0]); |
| 112 } |
| 113 |
99 // Function used for handling permission types which do not change their | 114 // Function used for handling permission types which do not change their |
100 // value i.e. they are always approved or always denied etc. | 115 // value i.e. they are always approved or always denied etc. |
101 // CONTENT_SETTING_DEFAULT is returned if the permission needs further handling. | 116 // CONTENT_SETTING_DEFAULT is returned if the permission needs further handling. |
102 // This function should only be called when IsConstantPermission has returned | 117 // This function should only be called when IsConstantPermission has returned |
103 // true for the PermissionType. | 118 // true for the PermissionType. |
104 ContentSetting GetContentSettingForConstantPermission(PermissionType type) { | 119 ContentSetting GetContentSettingForConstantPermission(PermissionType type) { |
105 DCHECK(IsConstantPermission(type)); | 120 DCHECK(IsConstantPermission(type)); |
106 switch (type) { | 121 switch (type) { |
107 case PermissionType::MIDI: | 122 case PermissionType::MIDI: |
108 return CONTENT_SETTING_ALLOW; | 123 return CONTENT_SETTING_ALLOW; |
109 default: | 124 default: |
110 return CONTENT_SETTING_DEFAULT; | 125 return CONTENT_SETTING_DEFAULT; |
111 } | 126 } |
112 } | 127 } |
113 | 128 |
114 PermissionStatus GetPermissionStatusForConstantPermission(PermissionType type) { | 129 PermissionStatus GetPermissionStatusForConstantPermission(PermissionType type) { |
115 return ContentSettingToPermissionStatus( | 130 return ContentSettingToPermissionStatus( |
116 GetContentSettingForConstantPermission(type)); | 131 GetContentSettingForConstantPermission(type)); |
117 } | 132 } |
118 | 133 |
119 } // anonymous namespace | 134 } // anonymous namespace |
120 | 135 |
121 struct PermissionManager::PendingRequest { | 136 class PermissionManager::PendingRequest { |
122 PendingRequest(PermissionType permission, | 137 public: |
123 content::RenderFrameHost* render_frame_host) | 138 PendingRequest(content::RenderFrameHost* render_frame_host, |
124 : permission(permission), | 139 const std::vector<PermissionType> permissions, |
125 render_process_id(render_frame_host->GetProcess()->GetID()), | 140 const base::Callback<void( |
126 render_frame_id(render_frame_host->GetRoutingID()) { | 141 const std::vector<PermissionStatus>&)>& callback) |
| 142 : render_process_id_(render_frame_host->GetProcess()->GetID()), |
| 143 render_frame_id_(render_frame_host->GetRoutingID()), |
| 144 callback_(callback), |
| 145 permissions_(permissions), |
| 146 results_(permissions.size(), content::PERMISSION_STATUS_DENIED), |
| 147 remaining_results_(permissions.size()) { |
127 } | 148 } |
128 | 149 |
129 PermissionType permission; | 150 void SetPermissionStatus(int permission_id, PermissionStatus status) { |
130 int render_process_id; | 151 DCHECK(!IsComplete()); |
131 int render_frame_id; | 152 |
| 153 results_[permission_id] = status; |
| 154 --remaining_results_; |
| 155 } |
| 156 |
| 157 bool IsComplete() const { |
| 158 return remaining_results_ == 0; |
| 159 } |
| 160 |
| 161 int render_process_id() const { return render_process_id_; } |
| 162 int render_frame_id() const { return render_frame_id_; } |
| 163 |
| 164 const base::Callback<void(const std::vector<PermissionStatus>&)> |
| 165 callback() const { |
| 166 return callback_; |
| 167 } |
| 168 |
| 169 std::vector<PermissionType> permissions() const { |
| 170 return permissions_; |
| 171 } |
| 172 |
| 173 std::vector<PermissionStatus> results() const { |
| 174 return results_; |
| 175 } |
| 176 |
| 177 private: |
| 178 int render_process_id_; |
| 179 int render_frame_id_; |
| 180 const base::Callback<void(const std::vector<PermissionStatus>&)> callback_; |
| 181 std::vector<PermissionType> permissions_; |
| 182 std::vector<PermissionStatus> results_; |
| 183 size_t remaining_results_; |
132 }; | 184 }; |
133 | 185 |
134 struct PermissionManager::Subscription { | 186 struct PermissionManager::Subscription { |
135 PermissionType permission; | 187 PermissionType permission; |
136 GURL requesting_origin; | 188 GURL requesting_origin; |
137 GURL embedding_origin; | 189 GURL embedding_origin; |
138 base::Callback<void(PermissionStatus)> callback; | 190 base::Callback<void(PermissionStatus)> callback; |
139 ContentSetting current_value; | 191 ContentSetting current_value; |
140 }; | 192 }; |
141 | 193 |
142 PermissionManager::PermissionManager(Profile* profile) | 194 PermissionManager::PermissionManager(Profile* profile) |
143 : profile_(profile), | 195 : profile_(profile), |
144 weak_ptr_factory_(this) { | 196 weak_ptr_factory_(this) { |
145 } | 197 } |
146 | 198 |
147 PermissionManager::~PermissionManager() { | 199 PermissionManager::~PermissionManager() { |
148 if (!subscriptions_.IsEmpty()) | 200 if (!subscriptions_.IsEmpty()) |
149 HostContentSettingsMapFactory::GetForProfile(profile_) | 201 HostContentSettingsMapFactory::GetForProfile(profile_) |
150 ->RemoveObserver(this); | 202 ->RemoveObserver(this); |
151 } | 203 } |
152 | 204 |
153 int PermissionManager::RequestPermission( | 205 int PermissionManager::RequestPermission( |
154 PermissionType permission, | 206 PermissionType permission, |
155 content::RenderFrameHost* render_frame_host, | 207 content::RenderFrameHost* render_frame_host, |
156 const GURL& requesting_origin, | 208 const GURL& requesting_origin, |
157 bool user_gesture, | 209 bool user_gesture, |
158 const base::Callback<void(PermissionStatus)>& callback) { | 210 const base::Callback<void(PermissionStatus)>& callback) { |
159 if (IsConstantPermission(permission)) { | 211 return RequestPermissions( |
160 callback.Run(GetPermissionStatusForConstantPermission(permission)); | 212 std::vector<PermissionType>(1, permission), |
161 return kNoPendingOperation; | 213 render_frame_host, |
162 } | 214 requesting_origin, |
| 215 user_gesture, |
| 216 base::Bind(&PermissionRequestResponseCallbackWrapper, callback)); |
| 217 } |
163 | 218 |
164 PermissionContextBase* context = PermissionContext::Get(profile_, permission); | 219 int PermissionManager::RequestPermissions( |
165 if (!context) { | 220 const std::vector<PermissionType>& permissions, |
166 callback.Run(content::PERMISSION_STATUS_DENIED); | 221 content::RenderFrameHost* render_frame_host, |
| 222 const GURL& requesting_origin, |
| 223 bool user_gesture, |
| 224 const base::Callback<void( |
| 225 const std::vector<PermissionStatus>&)>& callback) { |
| 226 if (permissions.empty()) { |
| 227 callback.Run(std::vector<PermissionStatus>()); |
167 return kNoPendingOperation; | 228 return kNoPendingOperation; |
168 } | 229 } |
169 | 230 |
170 content::WebContents* web_contents = | 231 content::WebContents* web_contents = |
171 content::WebContents::FromRenderFrameHost(render_frame_host); | 232 content::WebContents::FromRenderFrameHost(render_frame_host); |
172 if (IsPermissionBubbleManagerMissing(web_contents)) { | 233 GURL embedding_origin = web_contents->GetLastCommittedURL().GetOrigin(); |
173 callback.Run( | 234 |
174 GetPermissionStatus(permission, requesting_origin, | 235 PendingRequest* pending_request = new PendingRequest( |
175 web_contents->GetLastCommittedURL().GetOrigin())); | 236 render_frame_host, permissions, callback); |
176 return kNoPendingOperation; | 237 int request_id = pending_requests_.Add(pending_request); |
| 238 |
| 239 const PermissionRequestID request(render_frame_host, request_id); |
| 240 |
| 241 for (size_t i = 0; i < permissions.size(); ++i) { |
| 242 const PermissionType permission = permissions[i]; |
| 243 |
| 244 if (IsConstantPermission(permission) || |
| 245 IsPermissionBubbleManagerMissing(web_contents) || |
| 246 !PermissionContext::Get(profile_, permission)) { |
| 247 OnPermissionsRequestResponseStatus(request_id, i, |
| 248 GetPermissionStatus(permission, requesting_origin, embedding_origin)); |
| 249 continue; |
| 250 } |
| 251 |
| 252 PermissionContextBase* context = PermissionContext::Get( |
| 253 profile_, permission); |
| 254 context->RequestPermission( |
| 255 web_contents, request, requesting_origin, user_gesture, |
| 256 base::Bind(&ContentSettingToPermissionStatusCallbackWrapper, |
| 257 base::Bind(&PermissionManager::OnPermissionsRequestResponseStatus, |
| 258 weak_ptr_factory_.GetWeakPtr(), request_id, i))); |
177 } | 259 } |
178 | 260 |
179 PendingRequest* pending_request = new PendingRequest( | 261 // The request might have been resolved already. |
180 permission, render_frame_host); | 262 if (!pending_requests_.Lookup(request_id)) |
181 int request_id = pending_requests_.Add(pending_request); | 263 return kNoPendingOperation; |
182 const PermissionRequestID request(pending_request->render_process_id, | |
183 pending_request->render_frame_id, | |
184 request_id); | |
185 | 264 |
186 context->RequestPermission( | |
187 web_contents, request, requesting_origin, user_gesture, | |
188 base::Bind(&PermissionManager::OnPermissionRequestResponse, | |
189 weak_ptr_factory_.GetWeakPtr(), | |
190 request_id, | |
191 callback)); | |
192 return request_id; | 265 return request_id; |
193 } | 266 } |
194 | 267 |
195 void PermissionManager::OnPermissionRequestResponse( | 268 void PermissionManager::OnPermissionsRequestResponseStatus( |
196 int request_id, | 269 int request_id, |
197 const base::Callback<void(PermissionStatus)>& callback, | 270 int permission_id, |
198 ContentSetting content_setting) { | 271 PermissionStatus status) { |
| 272 PendingRequest* pending_request = pending_requests_.Lookup(request_id); |
| 273 pending_request->SetPermissionStatus(permission_id, status); |
| 274 |
| 275 if (!pending_request->IsComplete()) |
| 276 return; |
| 277 |
| 278 pending_request->callback().Run(pending_request->results()); |
199 pending_requests_.Remove(request_id); | 279 pending_requests_.Remove(request_id); |
200 callback.Run(ContentSettingToPermissionStatus(content_setting)); | |
201 } | 280 } |
202 | 281 |
203 void PermissionManager::CancelPermissionRequest(int request_id) { | 282 void PermissionManager::CancelPermissionRequest(int request_id) { |
204 PendingRequest* pending_request = pending_requests_.Lookup(request_id); | 283 PendingRequest* pending_request = pending_requests_.Lookup(request_id); |
205 if (!pending_request) | 284 if (!pending_request) |
206 return; | 285 return; |
207 | 286 |
208 PermissionContextBase* context = PermissionContext::Get( | |
209 profile_, pending_request->permission); | |
210 if (!context) | |
211 return; | |
212 | |
213 content::WebContents* web_contents = tab_util::GetWebContentsByFrameID( | 287 content::WebContents* web_contents = tab_util::GetWebContentsByFrameID( |
214 pending_request->render_process_id, pending_request->render_frame_id); | 288 pending_request->render_process_id(), pending_request->render_frame_id()); |
215 DCHECK(web_contents); | 289 DCHECK(web_contents); |
216 if (IsPermissionBubbleManagerMissing(web_contents)) { | 290 if (IsPermissionBubbleManagerMissing(web_contents)) { |
217 pending_requests_.Remove(request_id); | 291 pending_requests_.Remove(request_id); |
218 return; | 292 return; |
219 } | 293 } |
220 | 294 |
221 const PermissionRequestID request(pending_request->render_process_id, | 295 const PermissionRequestID request(pending_request->render_process_id(), |
222 pending_request->render_frame_id, | 296 pending_request->render_frame_id(), |
223 request_id); | 297 request_id); |
224 context->CancelPermissionRequest(web_contents, request); | 298 for (PermissionType permission : pending_request->permissions()) { |
| 299 PermissionContextBase* context = PermissionContext::Get( |
| 300 profile_, permission); |
| 301 if (!context) |
| 302 continue; |
| 303 context->CancelPermissionRequest(web_contents, request); |
| 304 } |
225 pending_requests_.Remove(request_id); | 305 pending_requests_.Remove(request_id); |
226 } | 306 } |
227 | 307 |
228 void PermissionManager::ResetPermission(PermissionType permission, | 308 void PermissionManager::ResetPermission(PermissionType permission, |
229 const GURL& requesting_origin, | 309 const GURL& requesting_origin, |
230 const GURL& embedding_origin) { | 310 const GURL& embedding_origin) { |
231 PermissionContextBase* context = PermissionContext::Get(profile_, permission); | 311 PermissionContextBase* context = PermissionContext::Get(profile_, permission); |
232 if (!context) | 312 if (!context) |
233 return; | 313 return; |
234 | 314 |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
341 // Add the callback to |callbacks| which will be run after the loop to | 421 // Add the callback to |callbacks| which will be run after the loop to |
342 // prevent re-entrance issues. | 422 // prevent re-entrance issues. |
343 callbacks.push_back( | 423 callbacks.push_back( |
344 base::Bind(subscription->callback, | 424 base::Bind(subscription->callback, |
345 ContentSettingToPermissionStatus(new_value))); | 425 ContentSettingToPermissionStatus(new_value))); |
346 } | 426 } |
347 | 427 |
348 for (const auto& callback : callbacks) | 428 for (const auto& callback : callbacks) |
349 callback.Run(); | 429 callback.Run(); |
350 } | 430 } |
OLD | NEW |