| 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 |