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/permissions/permission_context.h" | 8 #include "chrome/browser/permissions/permission_context.h" |
9 #include "chrome/browser/permissions/permission_context_base.h" | 9 #include "chrome/browser/permissions/permission_context_base.h" |
10 #include "chrome/browser/permissions/permission_request_id.h" | 10 #include "chrome/browser/permissions/permission_request_id.h" |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
66 case PermissionType::NUM: | 66 case PermissionType::NUM: |
67 // This will hit the NOTREACHED below. | 67 // This will hit the NOTREACHED below. |
68 break; | 68 break; |
69 } | 69 } |
70 | 70 |
71 NOTREACHED() << "Unknown content setting for permission " | 71 NOTREACHED() << "Unknown content setting for permission " |
72 << static_cast<int>(permission); | 72 << static_cast<int>(permission); |
73 return CONTENT_SETTINGS_TYPE_DEFAULT; | 73 return CONTENT_SETTINGS_TYPE_DEFAULT; |
74 } | 74 } |
75 | 75 |
76 // Helper method that wraps a callback a void(PermissionStatus) | 76 void PermissionRequestResponseCallbackWrapper( |
77 // callback into a void(ContentSetting) callback. | |
78 void PermissionStatusCallbackWrapper( | |
79 const base::Callback<void(PermissionStatus)>& callback, | 77 const base::Callback<void(PermissionStatus)>& callback, |
80 ContentSetting content_setting) { | 78 const std::vector<PermissionStatus>& vector) { |
81 callback.Run(ContentSettingToPermissionStatus(content_setting)); | 79 DCHECK(vector.size() == 1); |
| 80 callback.Run(vector[0]); |
82 } | 81 } |
83 | 82 |
84 // Returns whether the permission has a constant PermissionStatus value (i.e. | 83 // Returns whether the permission has a constant PermissionStatus value (i.e. |
85 // always approved or always denied) | 84 // always approved or always denied) |
86 // The PermissionTypes for which true is returned should be exactly those which | 85 // The PermissionTypes for which true is returned should be exactly those which |
87 // return nullptr in PermissionContext::Get since they don't have a context. | 86 // return nullptr in PermissionContext::Get since they don't have a context. |
88 bool IsConstantPermission(PermissionType type) { | 87 bool IsConstantPermission(PermissionType type) { |
89 switch (type) { | 88 switch (type) { |
90 case PermissionType::MIDI: | 89 case PermissionType::MIDI: |
91 return true; | 90 return true; |
(...skipping 17 matching lines...) Expand all Loading... |
109 } | 108 } |
110 } | 109 } |
111 | 110 |
112 PermissionStatus GetPermissionStatusForConstantPermission(PermissionType type) { | 111 PermissionStatus GetPermissionStatusForConstantPermission(PermissionType type) { |
113 return ContentSettingToPermissionStatus( | 112 return ContentSettingToPermissionStatus( |
114 GetContentSettingForConstantPermission(type)); | 113 GetContentSettingForConstantPermission(type)); |
115 } | 114 } |
116 | 115 |
117 } // anonymous namespace | 116 } // anonymous namespace |
118 | 117 |
| 118 struct PermissionManager::PendingResponse { |
| 119 PermissionType type; |
| 120 PermissionStatus status; |
| 121 |
| 122 PendingResponse(PermissionType type, PermissionStatus status) |
| 123 : type(type), status(status) { |
| 124 } |
| 125 }; |
| 126 |
| 127 struct PermissionManager::PendingResponses { |
| 128 GURL requesting_origin; |
| 129 size_t count; |
| 130 size_t pending; |
| 131 std::vector<PendingResponse> responses; |
| 132 }; |
| 133 |
119 struct PermissionManager::Subscription { | 134 struct PermissionManager::Subscription { |
120 PermissionType permission; | 135 PermissionType permission; |
121 GURL requesting_origin; | 136 GURL requesting_origin; |
122 GURL embedding_origin; | 137 GURL embedding_origin; |
123 base::Callback<void(PermissionStatus)> callback; | 138 base::Callback<void(PermissionStatus)> callback; |
124 ContentSetting current_value; | 139 ContentSetting current_value; |
125 }; | 140 }; |
126 | 141 |
127 PermissionManager::PermissionManager(Profile* profile) | 142 PermissionManager::PermissionManager(Profile* profile) |
128 : profile_(profile) { | 143 : profile_(profile), |
| 144 weak_ptr_factory_(this) { |
129 } | 145 } |
130 | 146 |
131 PermissionManager::~PermissionManager() { | 147 PermissionManager::~PermissionManager() { |
132 if (!subscriptions_.IsEmpty()) | 148 if (!subscriptions_.IsEmpty()) |
133 profile_->GetHostContentSettingsMap()->RemoveObserver(this); | 149 profile_->GetHostContentSettingsMap()->RemoveObserver(this); |
134 } | 150 } |
135 | 151 |
136 void PermissionManager::RequestPermission( | 152 void PermissionManager::RequestPermission( |
137 PermissionType permission, | 153 PermissionType permission, |
138 content::RenderFrameHost* render_frame_host, | 154 content::RenderFrameHost* render_frame_host, |
139 int request_id, | 155 int request_id, |
140 const GURL& requesting_origin, | 156 const GURL& requesting_origin, |
141 bool user_gesture, | 157 bool user_gesture, |
142 const base::Callback<void(PermissionStatus)>& callback) { | 158 const RequestCallback& callback) { |
143 if (IsConstantPermission(permission)) { | 159 RequestPermissionInternal( |
144 callback.Run(GetPermissionStatusForConstantPermission(permission)); | 160 std::vector<PermissionType>(1, permission), |
145 return; | 161 render_frame_host, |
146 } | 162 request_id, |
| 163 requesting_origin, |
| 164 user_gesture, |
| 165 base::Bind(&PermissionRequestResponseCallbackWrapper, callback)); |
| 166 } |
147 | 167 |
148 PermissionContextBase* context = PermissionContext::Get(profile_, permission); | 168 void PermissionManager::RequestPermission( |
149 if (!context) { | 169 const std::vector<PermissionType>& permissions, |
150 callback.Run(content::PERMISSION_STATUS_DENIED); | 170 content::RenderFrameHost* render_frame_host, |
151 return; | 171 int request_id, |
152 } | 172 const GURL& requesting_origin, |
| 173 bool user_gesture, |
| 174 const BatchRequestCallback& callback) { |
| 175 RequestPermissionInternal(permissions, render_frame_host, request_id, |
| 176 requesting_origin, user_gesture, callback); |
| 177 } |
153 | 178 |
| 179 void PermissionManager::RequestPermissionInternal( |
| 180 const std::vector<PermissionType>& permissions, |
| 181 content::RenderFrameHost* render_frame_host, |
| 182 int request_id, |
| 183 const GURL& requesting_origin, |
| 184 bool user_gesture, |
| 185 const BatchRequestCallback& callback) { |
154 int render_process_id = render_frame_host->GetProcess()->GetID(); | 186 int render_process_id = render_frame_host->GetProcess()->GetID(); |
155 int render_frame_id = render_frame_host->GetRoutingID(); | 187 int render_frame_id = render_frame_host->GetRoutingID(); |
156 const PermissionRequestID request(render_process_id, | 188 const PermissionRequestID request(render_process_id, |
157 render_frame_id, | 189 render_frame_id, |
158 request_id, | 190 request_id, |
159 requesting_origin); | 191 requesting_origin); |
160 | 192 |
161 context->RequestPermission( | 193 // Pass complete control of the scoped pointer to the map. |
162 content::WebContents::FromRenderFrameHost(render_frame_host), | 194 // Locally we will use the raw pointer and the response will be removed from |
163 request, requesting_origin, user_gesture, | 195 // the map once all the responses return. |
164 base::Bind(&PermissionStatusCallbackWrapper, | 196 scoped_ptr<PendingResponses> scoped_response(new PendingResponses()); |
165 callback)); | 197 PendingResponses* pending_responses = scoped_response.get(); |
| 198 pending_responses_.add(request_id, scoped_response.Pass()); |
| 199 |
| 200 pending_responses->requesting_origin = requesting_origin; |
| 201 pending_responses->count = permissions.size(); |
| 202 pending_responses->pending = permissions.size(); |
| 203 |
| 204 for (size_t i = 0; i < permissions.size(); ++i) { |
| 205 pending_responses->responses.emplace_back( |
| 206 permissions[i], |
| 207 content::PERMISSION_STATUS_DENIED); |
| 208 } |
| 209 |
| 210 // The pending responses should all be added to the vector before running |
| 211 // this loop so duplicate permissions are handled properly. |
| 212 bool seen_types[static_cast<int>(PermissionType::NUM)] = { false }; |
| 213 for (size_t i = 0; i < permissions.size(); ++i) { |
| 214 const PermissionType current_type = permissions[i]; |
| 215 const int current_type_index = static_cast<int>(current_type); |
| 216 if (seen_types[current_type_index]) |
| 217 continue; |
| 218 seen_types[current_type_index] = true; |
| 219 |
| 220 if (IsConstantPermission(current_type)) { |
| 221 OnRequestResponse(callback, request, pending_responses, i, |
| 222 GetContentSettingForConstantPermission(current_type)); |
| 223 continue; |
| 224 } |
| 225 |
| 226 PermissionContextBase* context = |
| 227 PermissionContext::Get(profile_, current_type); |
| 228 if (!context) { |
| 229 OnRequestResponse(callback, request, pending_responses, i, |
| 230 CONTENT_SETTING_BLOCK); |
| 231 continue; |
| 232 } |
| 233 context->RequestPermission( |
| 234 content::WebContents::FromRenderFrameHost(render_frame_host), |
| 235 request, requesting_origin, user_gesture, |
| 236 base::Bind(&PermissionManager::OnRequestResponse, |
| 237 weak_ptr_factory_.GetWeakPtr(), |
| 238 callback, |
| 239 request, |
| 240 pending_responses, |
| 241 i)); |
| 242 } |
| 243 } |
| 244 |
| 245 void PermissionManager::OnRequestResponse(const BatchRequestCallback& callback, |
| 246 const PermissionRequestID request, |
| 247 PendingResponses* pending_responses, |
| 248 int index, |
| 249 ContentSetting content_setting) { |
| 250 PendingResponse& response = pending_responses->responses[index]; |
| 251 response.status = ContentSettingToPermissionStatus(content_setting); |
| 252 |
| 253 for (size_t i = index + 1; i < pending_responses->responses.size(); ++i) { |
| 254 if (pending_responses->responses[i].type == response.type) { |
| 255 pending_responses->responses[i].status = response.status; |
| 256 --pending_responses->pending; |
| 257 } |
| 258 } |
| 259 |
| 260 if (pending_responses->pending == 1) { |
| 261 std::vector<PermissionStatus> status; |
| 262 for (auto response : pending_responses->responses) |
| 263 status.push_back(response.status); |
| 264 pending_responses_.erase(request.request_id()); |
| 265 callback.Run(status); |
| 266 } |
166 } | 267 } |
167 | 268 |
168 void PermissionManager::CancelPermissionRequest( | 269 void PermissionManager::CancelPermissionRequest( |
169 PermissionType permission, | |
170 content::RenderFrameHost* render_frame_host, | 270 content::RenderFrameHost* render_frame_host, |
171 int request_id, | 271 int request_id) { |
172 const GURL& requesting_origin) { | 272 PendingResponses* pending_responses = |
173 PermissionContextBase* context = PermissionContext::Get(profile_, permission); | 273 pending_responses_.get(request_id); |
174 if (!context) | |
175 return; | |
176 | 274 |
177 int render_process_id = render_frame_host->GetProcess()->GetID(); | 275 int render_process_id = render_frame_host->GetProcess()->GetID(); |
178 int render_frame_id = render_frame_host->GetRoutingID(); | 276 int render_frame_id = render_frame_host->GetRoutingID(); |
179 const PermissionRequestID request(render_process_id, | 277 const PermissionRequestID request(render_process_id, |
180 render_frame_id, | 278 render_frame_id, |
181 request_id, | 279 request_id, |
182 requesting_origin); | 280 pending_responses->requesting_origin); |
183 | 281 |
184 context->CancelPermissionRequest( | 282 for (size_t i = 0; i < pending_responses->count; ++i) { |
185 content::WebContents::FromRenderFrameHost(render_frame_host), request); | 283 PermissionType type = pending_responses->responses[i].type; |
| 284 PermissionContextBase* context = PermissionContext::Get(profile_, type); |
| 285 if (!context) continue; |
| 286 |
| 287 context->CancelPermissionRequest( |
| 288 content::WebContents::FromRenderFrameHost(render_frame_host), request); |
| 289 } |
| 290 pending_responses_.erase(request_id); |
186 } | 291 } |
187 | 292 |
188 void PermissionManager::ResetPermission(PermissionType permission, | 293 void PermissionManager::ResetPermission(PermissionType permission, |
189 const GURL& requesting_origin, | 294 const GURL& requesting_origin, |
190 const GURL& embedding_origin) { | 295 const GURL& embedding_origin) { |
191 PermissionContextBase* context = PermissionContext::Get(profile_, permission); | 296 PermissionContextBase* context = PermissionContext::Get(profile_, permission); |
192 if (!context) | 297 if (!context) |
193 return; | 298 return; |
194 | 299 |
195 context->ResetPermission(requesting_origin.GetOrigin(), | 300 context->ResetPermission(requesting_origin.GetOrigin(), |
(...skipping 27 matching lines...) Expand all Loading... |
223 profile_->GetHostContentSettingsMap()->UpdateLastUsage( | 328 profile_->GetHostContentSettingsMap()->UpdateLastUsage( |
224 requesting_origin, | 329 requesting_origin, |
225 embedding_origin, | 330 embedding_origin, |
226 PermissionTypeToContentSetting(permission)); | 331 PermissionTypeToContentSetting(permission)); |
227 } | 332 } |
228 | 333 |
229 int PermissionManager::SubscribePermissionStatusChange( | 334 int PermissionManager::SubscribePermissionStatusChange( |
230 PermissionType permission, | 335 PermissionType permission, |
231 const GURL& requesting_origin, | 336 const GURL& requesting_origin, |
232 const GURL& embedding_origin, | 337 const GURL& embedding_origin, |
233 const base::Callback<void(PermissionStatus)>& callback) { | 338 const RequestCallback& callback) { |
234 if (subscriptions_.IsEmpty()) | 339 if (subscriptions_.IsEmpty()) |
235 profile_->GetHostContentSettingsMap()->AddObserver(this); | 340 profile_->GetHostContentSettingsMap()->AddObserver(this); |
236 | 341 |
237 Subscription* subscription = new Subscription(); | 342 Subscription* subscription = new Subscription(); |
238 subscription->permission = permission; | 343 subscription->permission = permission; |
239 subscription->requesting_origin = requesting_origin; | 344 subscription->requesting_origin = requesting_origin; |
240 subscription->embedding_origin = embedding_origin; | 345 subscription->embedding_origin = embedding_origin; |
241 subscription->callback = callback; | 346 subscription->callback = callback; |
242 | 347 |
243 if (IsConstantPermission(permission)) { | 348 if (IsConstantPermission(permission)) { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
294 // Add the callback to |callbacks| which will be run after the loop to | 399 // Add the callback to |callbacks| which will be run after the loop to |
295 // prevent re-entrance issues. | 400 // prevent re-entrance issues. |
296 callbacks.push_back( | 401 callbacks.push_back( |
297 base::Bind(subscription->callback, | 402 base::Bind(subscription->callback, |
298 ContentSettingToPermissionStatus(new_value))); | 403 ContentSettingToPermissionStatus(new_value))); |
299 } | 404 } |
300 | 405 |
301 for (const auto& callback : callbacks) | 406 for (const auto& callback : callbacks) |
302 callback.Run(); | 407 callback.Run(); |
303 } | 408 } |
OLD | NEW |