Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(133)

Side by Side Diff: chrome/browser/permissions/permission_manager.cc

Issue 1316863010: browser: implement multiple permission requesting (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@request-multiple-content
Patch Set: Fix memory leak in permission_manager Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 // 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.
87 bool IsConstantPermission(PermissionType type) { 87 bool IsConstantPermission(PermissionType type) {
88 switch (type) { 88 switch (type) {
89 case PermissionType::MIDI: 89 case PermissionType::MIDI:
90 return true; 90 return true;
91 default: 91 default:
92 return false; 92 return false;
93 } 93 }
94 } 94 }
95 95
96 void PermissionRequestResponseCallbackWrapper(
97 const base::Callback<void(PermissionStatus)>& callback,
98 const std::vector<PermissionStatus>& vector) {
99 DCHECK(vector.size() == 1);
mlamouri (slow - plz ping) 2015/09/23 16:37:37 nit: DCHECK_EQ()
Lalit Maganti 2015/09/24 09:24:11 Done.
100 callback.Run(vector[0]);
101 }
102
96 // Function used for handling permission types which do not change their 103 // Function used for handling permission types which do not change their
97 // value i.e. they are always approved or always denied etc. 104 // value i.e. they are always approved or always denied etc.
98 // CONTENT_SETTING_DEFAULT is returned if the permission needs further handling. 105 // CONTENT_SETTING_DEFAULT is returned if the permission needs further handling.
99 // This function should only be called when IsConstantPermission has returned 106 // This function should only be called when IsConstantPermission has returned
100 // true for the PermissionType. 107 // true for the PermissionType.
101 ContentSetting GetContentSettingForConstantPermission(PermissionType type) { 108 ContentSetting GetContentSettingForConstantPermission(PermissionType type) {
102 DCHECK(IsConstantPermission(type)); 109 DCHECK(IsConstantPermission(type));
103 switch (type) { 110 switch (type) {
104 case PermissionType::MIDI: 111 case PermissionType::MIDI:
105 return CONTENT_SETTING_ALLOW; 112 return CONTENT_SETTING_ALLOW;
106 default: 113 default:
107 return CONTENT_SETTING_DEFAULT; 114 return CONTENT_SETTING_DEFAULT;
108 } 115 }
109 } 116 }
110 117
111 PermissionStatus GetPermissionStatusForConstantPermission(PermissionType type) { 118 PermissionStatus GetPermissionStatusForConstantPermission(PermissionType type) {
112 return ContentSettingToPermissionStatus( 119 return ContentSettingToPermissionStatus(
113 GetContentSettingForConstantPermission(type)); 120 GetContentSettingForConstantPermission(type));
114 } 121 }
115 122
116 } // anonymous namespace 123 } // anonymous namespace
117 124
118 struct PermissionManager::PendingRequest { 125 struct PermissionManager::PendingRequest {
119 PermissionType permission; 126 PendingRequest(content::RenderFrameHost* render_frame_host,
127 const GURL& requesting_origin,
128 const std::vector<PermissionType> types,
129 const base::Callback<void(
130 const std::vector<PermissionStatus>&)>& callback)
131 : render_process_id(render_frame_host->GetProcess()->GetID()),
132 render_frame_id(render_frame_host->GetRoutingID()),
133 requesting_origin(requesting_origin),
134 pending(types.size()),
135 callback(callback),
136 permissions(types),
137 result(permissions.size(), content::PERMISSION_STATUS_DENIED) {
138 // TODO(miguelg, peter) This special case for should go away once
139 // push -> notifications mapping goes away/is changed.
140 bool push_seen = false;
141 for (const PermissionType& type : permissions) {
142 if (type == PermissionType::PUSH_MESSAGING)
143 push_seen = true;
144 }
145 if (!push_seen)
146 return;
147 for (size_t i = 0; i < permissions.size(); ++i) {
148 if (permissions[i] == PermissionType::NOTIFICATIONS)
149 permissions[i] = PermissionType::PUSH_MESSAGING;
150 }
151 }
152
153 // Returns if there are no further pending sub-requests.
154 bool SetPermission(int index, PermissionStatus status) {
155 PermissionType current = permissions[index];
156 for (size_t i = index; i < permissions.size(); ++i) {
157 if (permissions[i] == current) {
158 result[i] = status;
159 pending -= 1;
mlamouri (slow - plz ping) 2015/09/23 16:37:37 nit: --pending;
Lalit Maganti 2015/09/24 09:24:11 All changed.
160 }
161 }
162 if (pending == 0)
163 callback.Run(result);
164 return pending == 0;
165 }
166
120 int render_process_id; 167 int render_process_id;
121 int render_frame_id; 168 int render_frame_id;
169 const GURL requesting_origin;
170 size_t pending;
mlamouri (slow - plz ping) 2015/09/23 16:37:37 nit: pending_results?
Lalit Maganti 2015/09/24 09:24:11 Gone.
171 const base::Callback<void(
172 const std::vector<PermissionStatus>&)> callback;
173
174 std::vector<PermissionType> permissions;
175 std::vector<PermissionStatus> result;
122 }; 176 };
123 177
124 struct PermissionManager::Subscription { 178 struct PermissionManager::Subscription {
125 PermissionType permission; 179 PermissionType permission;
126 GURL requesting_origin; 180 GURL requesting_origin;
127 GURL embedding_origin; 181 GURL embedding_origin;
128 base::Callback<void(PermissionStatus)> callback; 182 base::Callback<void(PermissionStatus)> callback;
129 ContentSetting current_value; 183 ContentSetting current_value;
130 }; 184 };
131 185
132 PermissionManager::PermissionManager(Profile* profile) 186 PermissionManager::PermissionManager(Profile* profile)
133 : profile_(profile), 187 : profile_(profile),
134 weak_ptr_factory_(this) { 188 weak_ptr_factory_(this) {
135 } 189 }
136 190
137 PermissionManager::~PermissionManager() { 191 PermissionManager::~PermissionManager() {
138 if (!subscriptions_.IsEmpty()) 192 if (!subscriptions_.IsEmpty())
139 HostContentSettingsMapFactory::GetForProfile(profile_) 193 HostContentSettingsMapFactory::GetForProfile(profile_)
140 ->RemoveObserver(this); 194 ->RemoveObserver(this);
141 } 195 }
142 196
143 int PermissionManager::RequestPermission( 197 int PermissionManager::RequestPermission(
144 PermissionType permission, 198 PermissionType permission,
145 content::RenderFrameHost* render_frame_host, 199 content::RenderFrameHost* render_frame_host,
146 const GURL& requesting_origin, 200 const GURL& requesting_origin,
147 bool user_gesture, 201 bool user_gesture,
148 const base::Callback<void(PermissionStatus)>& callback) { 202 const base::Callback<void(PermissionStatus)>& callback) {
149 if (IsConstantPermission(permission)) { 203 return RequestPermissions(
150 callback.Run(GetPermissionStatusForConstantPermission(permission)); 204 std::vector<PermissionType>(1, permission),
151 return kNoPendingRequestOrSubscription; 205 render_frame_host,
152 } 206 requesting_origin,
207 user_gesture,
208 base::Bind(&PermissionRequestResponseCallbackWrapper, callback));
209 }
153 210
154 PermissionContextBase* context = PermissionContext::Get(profile_, permission); 211 int PermissionManager::RequestPermissions(
155 if (!context) { 212 const std::vector<PermissionType>& permissions,
156 callback.Run(content::PERMISSION_STATUS_DENIED); 213 content::RenderFrameHost* render_frame_host,
157 return kNoPendingRequestOrSubscription; 214 const GURL& requesting_origin,
158 } 215 bool user_gesture,
159 216 const base::Callback<void(
217 const std::vector<PermissionStatus>&)>& callback) {
160 content::WebContents* web_contents = 218 content::WebContents* web_contents =
161 content::WebContents::FromRenderFrameHost(render_frame_host); 219 content::WebContents::FromRenderFrameHost(render_frame_host);
162 if (IsPermissionBubbleManagerMissing(web_contents)) { 220 GURL embedding_origin = web_contents->GetLastCommittedURL().GetOrigin();
163 callback.Run( 221
164 GetPermissionStatus(permission, requesting_origin, 222 PendingRequest* pending_request = new PendingRequest(
165 web_contents->GetLastCommittedURL().GetOrigin())); 223 render_frame_host, requesting_origin, permissions, callback);
166 return kNoPendingRequestOrSubscription; 224 int request_id = pending_requests_.Add(pending_request);
225 const PermissionRequestID request(render_frame_host, request_id);
226
227 std::set<PermissionType> seen_permissions;
228 for (size_t i = 0; i < permissions.size(); ++i) {
229 // It is important that the pending request be used here as it can change
230 // the PermissionType from the vector that was passed in.
231 // TODO(peter, miguelg) Remove this when push and notifcations are unified.
232 const PermissionType permission = pending_request->permissions[i];
233 if (seen_permissions.find(permission) != seen_permissions.end())
234 continue;
235 seen_permissions.insert(permission);
236
237 if (IsConstantPermission(permission) ||
238 IsPermissionBubbleManagerMissing(web_contents) ||
239 !PermissionContext::Get(profile_, permission)) {
240 OnPermissionsRequestResponseStatus(request_id, i,
241 GetPermissionStatus(
242 permission, requesting_origin, embedding_origin));
243 continue;
244 }
245
246 PermissionContextBase* context = PermissionContext::Get(
247 profile_, permission);
248 context->RequestPermission(
249 web_contents, request, requesting_origin, user_gesture,
250 base::Bind(&PermissionManager::OnPermissionsRequestResponse,
251 weak_ptr_factory_.GetWeakPtr(), request_id, i));
167 } 252 }
168
169 int render_process_id = render_frame_host->GetProcess()->GetID();
170 int render_frame_id = render_frame_host->GetRoutingID();
171
172 PendingRequest* pending_request = new PendingRequest();
173 pending_request->render_process_id = render_process_id;
174 pending_request->render_frame_id = render_frame_id;
175 pending_request->permission = permission;
176
177 int request_id = pending_requests_.Add(pending_request);
178 const PermissionRequestID request(render_process_id,
179 render_frame_id,
180 request_id);
181
182 context->RequestPermission(
183 web_contents, request, requesting_origin, user_gesture,
184 base::Bind(&PermissionManager::OnPermissionRequestResponse,
185 weak_ptr_factory_.GetWeakPtr(),
186 request_id,
187 callback));
188 return request_id; 253 return request_id;
189 } 254 }
190 255
191 void PermissionManager::OnPermissionRequestResponse( 256 void PermissionManager::OnPermissionsRequestResponse(
192 int request_id, 257 int request_id,
193 const base::Callback<void(PermissionStatus)>& callback, 258 int request_index,
194 ContentSetting content_setting) { 259 ContentSetting content_setting) {
195 pending_requests_.Remove(request_id); 260 OnPermissionsRequestResponseStatus(request_id, request_index,
196 callback.Run(ContentSettingToPermissionStatus(content_setting)); 261 ContentSettingToPermissionStatus(content_setting));
262 }
263
264 void PermissionManager::OnPermissionsRequestResponseStatus(
265 int request_id,
266 int request_index,
267 PermissionStatus status) {
268 PendingRequest* pending_request = pending_requests_.Lookup(request_id);
269 if (pending_request->SetPermission(request_index, status))
270 pending_requests_.Remove(request_id);
197 } 271 }
198 272
199 void PermissionManager::CancelPermissionRequest(int request_id) { 273 void PermissionManager::CancelPermissionRequest(int request_id) {
200 PendingRequest* pending_request = pending_requests_.Lookup(request_id); 274 PendingRequest* pending_request = pending_requests_.Lookup(request_id);
201 if (!pending_request) 275 if (!pending_request)
202 return; 276 return;
203 277
204 PermissionContextBase* context = PermissionContext::Get(
205 profile_, pending_request->permission);
206 if (!context)
207 return;
208
209 content::WebContents* web_contents = tab_util::GetWebContentsByFrameID( 278 content::WebContents* web_contents = tab_util::GetWebContentsByFrameID(
210 pending_request->render_process_id, pending_request->render_frame_id); 279 pending_request->render_process_id, pending_request->render_frame_id);
211 DCHECK(web_contents); 280 DCHECK(web_contents);
212 if (IsPermissionBubbleManagerMissing(web_contents)) { 281 if (IsPermissionBubbleManagerMissing(web_contents)) {
213 pending_requests_.Remove(request_id); 282 pending_requests_.Remove(request_id);
214 return; 283 return;
215 } 284 }
216 285
217 const PermissionRequestID request(pending_request->render_process_id, 286 const PermissionRequestID request(pending_request->render_process_id,
218 pending_request->render_frame_id, 287 pending_request->render_frame_id,
219 request_id); 288 request_id);
220 context->CancelPermissionRequest(web_contents, request); 289 std::set<PermissionType> seen_permissions;
290 for (const PermissionType& permission : pending_request->permissions) {
291 if (seen_permissions.find(permission) != seen_permissions.end())
292 continue;
293 seen_permissions.insert(permission);
294
295 PermissionContextBase* context = PermissionContext::Get(
296 profile_, permission);
297 if (!context)
298 continue;
299 context->CancelPermissionRequest(web_contents, request);
300 }
221 pending_requests_.Remove(request_id); 301 pending_requests_.Remove(request_id);
222 } 302 }
223 303
224 void PermissionManager::ResetPermission(PermissionType permission, 304 void PermissionManager::ResetPermission(PermissionType permission,
225 const GURL& requesting_origin, 305 const GURL& requesting_origin,
226 const GURL& embedding_origin) { 306 const GURL& embedding_origin) {
227 PermissionContextBase* context = PermissionContext::Get(profile_, permission); 307 PermissionContextBase* context = PermissionContext::Get(profile_, permission);
228 if (!context) 308 if (!context)
229 return; 309 return;
230 310
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
339 // Add the callback to |callbacks| which will be run after the loop to 419 // Add the callback to |callbacks| which will be run after the loop to
340 // prevent re-entrance issues. 420 // prevent re-entrance issues.
341 callbacks.push_back( 421 callbacks.push_back(
342 base::Bind(subscription->callback, 422 base::Bind(subscription->callback,
343 ContentSettingToPermissionStatus(new_value))); 423 ContentSettingToPermissionStatus(new_value)));
344 } 424 }
345 425
346 for (const auto& callback : callbacks) 426 for (const auto& callback : callbacks)
347 callback.Run(); 427 callback.Run();
348 } 428 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698