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

Side by Side Diff: chrome/browser/ui/website_settings/permission_bubble_manager.cc

Issue 292453009: Handles iframe permissions requests separately, in a subsequent bubble. (Closed) Base URL: https://chromium.googlesource.com/chromium/src
Patch Set: unit test edit Created 6 years, 7 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 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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/ui/website_settings/permission_bubble_manager.h" 5 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/metrics/user_metrics_action.h" 8 #include "base/metrics/user_metrics_action.h"
9 #include "chrome/browser/ui/website_settings/permission_bubble_request.h" 9 #include "chrome/browser/ui/website_settings/permission_bubble_request.h"
10 #include "chrome/common/chrome_switches.h" 10 #include "chrome/common/chrome_switches.h"
11 #include "content/public/browser/browser_thread.h" 11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/navigation_details.h"
12 #include "content/public/browser/user_metrics.h" 13 #include "content/public/browser/user_metrics.h"
13 14
14 namespace { 15 namespace {
15 16
16 class CancelledRequest : public PermissionBubbleRequest { 17 class CancelledRequest : public PermissionBubbleRequest {
17 public: 18 public:
18 explicit CancelledRequest(PermissionBubbleRequest* cancelled) 19 explicit CancelledRequest(PermissionBubbleRequest* cancelled)
19 : icon_(cancelled->GetIconID()), 20 : icon_(cancelled->GetIconID()),
20 message_text_(cancelled->GetMessageText()), 21 message_text_(cancelled->GetMessageText()),
21 message_fragment_(cancelled->GetMessageTextFragment()), 22 message_fragment_(cancelled->GetMessageTextFragment()),
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 95
95 void PermissionBubbleManager::AddRequest(PermissionBubbleRequest* request) { 96 void PermissionBubbleManager::AddRequest(PermissionBubbleRequest* request) {
96 content::RecordAction(base::UserMetricsAction("PermissionBubbleRequest")); 97 content::RecordAction(base::UserMetricsAction("PermissionBubbleRequest"));
97 // TODO(gbillock): is there a race between an early request on a 98 // TODO(gbillock): is there a race between an early request on a
98 // newly-navigated page and the to-be-cleaned-up requests on the previous 99 // newly-navigated page and the to-be-cleaned-up requests on the previous
99 // page? We should maybe listen to DidStartNavigationToPendingEntry (and 100 // page? We should maybe listen to DidStartNavigationToPendingEntry (and
100 // any other renderer-side nav initiations?). Double-check this for 101 // any other renderer-side nav initiations?). Double-check this for
101 // correct behavior on interstitials -- we probably want to basically queue 102 // correct behavior on interstitials -- we probably want to basically queue
102 // any request for which GetVisibleURL != GetLastCommittedURL. 103 // any request for which GetVisibleURL != GetLastCommittedURL.
103 request_url_ = web_contents()->GetLastCommittedURL(); 104 request_url_ = web_contents()->GetLastCommittedURL();
105 bool is_main_frame =
106 request->GetRequestingHostname().GetOrigin() == request_url_.GetOrigin();
104 107
105 // Don't re-add an existing request or one with a duplicate text request. 108 // Don't re-add an existing request or one with a duplicate text request.
106 std::vector<PermissionBubbleRequest*>::iterator requests_iter; 109 bool same_object = false;
107 for (requests_iter = requests_.begin(); 110 if (ExistingRequest(request, requests_, &same_object) ||
108 requests_iter != requests_.end(); 111 ExistingRequest(request, queued_requests_, &same_object) ||
109 requests_iter++) { 112 ExistingRequest(request, queued_frame_requests_, &same_object)) {
110 if (*requests_iter == request) 113 if (!same_object)
111 return;
112 // TODO(gbillock): worry about the requesting host name as well.
113 if ((*requests_iter)->GetMessageTextFragment() ==
114 request->GetMessageTextFragment()) {
115 request->RequestFinished(); 114 request->RequestFinished();
116 return; 115 return;
117 }
118 }
119 for (requests_iter = queued_requests_.begin();
120 requests_iter != queued_requests_.end();
121 requests_iter++) {
122 if (*requests_iter == request)
123 return;
124 if ((*requests_iter)->GetMessageTextFragment() ==
125 request->GetMessageTextFragment()) {
126 request->RequestFinished();
127 return;
128 }
129 } 116 }
130 117
131 if (bubble_showing_) { 118 if (bubble_showing_) {
132 content::RecordAction( 119 content::RecordAction(
133 base::UserMetricsAction("PermissionBubbleRequestQueued")); 120 base::UserMetricsAction("PermissionBubbleRequestQueued"));
134 queued_requests_.push_back(request); 121 if (is_main_frame)
122 queued_requests_.push_back(request);
123 else
124 queued_frame_requests_.push_back(request);
135 return; 125 return;
136 } 126 }
137 127
138 requests_.push_back(request); 128 if (is_main_frame) {
139 // TODO(gbillock): do we need to make default state a request property? 129 requests_.push_back(request);
140 accept_states_.push_back(true); 130 // TODO(gbillock): do we need to make default state a request property?
131 accept_states_.push_back(true);
132 } else {
133 queued_frame_requests_.push_back(request);
134 }
141 135
142 if (request->HasUserGesture()) 136 if (request->HasUserGesture())
143 ShowBubble(); 137 ScheduleShowBubble();
144 } 138 }
145 139
146 void PermissionBubbleManager::CancelRequest(PermissionBubbleRequest* request) { 140 void PermissionBubbleManager::CancelRequest(PermissionBubbleRequest* request) {
147 // First look in the queued requests, where we can simply delete the request 141 // First look in the queued requests, where we can simply delete the request
148 // and go on. 142 // and go on.
149 std::vector<PermissionBubbleRequest*>::iterator requests_iter; 143 std::vector<PermissionBubbleRequest*>::iterator requests_iter;
150 for (requests_iter = queued_requests_.begin(); 144 for (requests_iter = queued_requests_.begin();
151 requests_iter != queued_requests_.end(); 145 requests_iter != queued_requests_.end();
152 requests_iter++) { 146 requests_iter++) {
153 if (*requests_iter == request) { 147 if (*requests_iter == request) {
(...skipping 11 matching lines...) Expand all
165 continue; 159 continue;
166 160
167 // We can simply erase the current entry in the request table if we aren't 161 // We can simply erase the current entry in the request table if we aren't
168 // showing the dialog, or if we are showing it and it can accept the update. 162 // showing the dialog, or if we are showing it and it can accept the update.
169 bool can_erase = !bubble_showing_ || 163 bool can_erase = !bubble_showing_ ||
170 !view_ || view_->CanAcceptRequestUpdate(); 164 !view_ || view_->CanAcceptRequestUpdate();
171 if (can_erase) { 165 if (can_erase) {
172 (*requests_iter)->RequestFinished(); 166 (*requests_iter)->RequestFinished();
173 requests_.erase(requests_iter); 167 requests_.erase(requests_iter);
174 accept_states_.erase(accepts_iter); 168 accept_states_.erase(accepts_iter);
175 ShowBubble(); // Will redraw the bubble if it is being shown. 169 TriggerShowBubble(); // Will redraw the bubble if it is being shown.
176 return; 170 return;
177 } 171 }
178 172
179 // Cancel the existing request and replace it with a dummy. 173 // Cancel the existing request and replace it with a dummy.
180 PermissionBubbleRequest* cancelled_request = 174 PermissionBubbleRequest* cancelled_request =
181 new CancelledRequest(*requests_iter); 175 new CancelledRequest(*requests_iter);
182 (*requests_iter)->RequestFinished(); 176 (*requests_iter)->RequestFinished();
183 *requests_iter = cancelled_request; 177 *requests_iter = cancelled_request;
184 return; 178 return;
185 } 179 }
(...skipping 10 matching lines...) Expand all
196 view_->SetDelegate(NULL); 190 view_->SetDelegate(NULL);
197 view_->Hide(); 191 view_->Hide();
198 bubble_showing_ = false; 192 bubble_showing_ = false;
199 } 193 }
200 194
201 view_ = view; 195 view_ = view;
202 if (!view) 196 if (!view)
203 return; 197 return;
204 198
205 view->SetDelegate(this); 199 view->SetDelegate(this);
206 ShowBubble(); 200 TriggerShowBubble();
207 } 201 }
208 202
209 void PermissionBubbleManager::DocumentOnLoadCompletedInMainFrame() { 203 void PermissionBubbleManager::DocumentOnLoadCompletedInMainFrame() {
210 request_url_has_loaded_ = true; 204 request_url_has_loaded_ = true;
211 // This is scheduled because while all calls to the browser have been 205 // This is scheduled because while all calls to the browser have been
212 // issued at DOMContentLoaded, they may be bouncing around in scheduled 206 // issued at DOMContentLoaded, they may be bouncing around in scheduled
213 // callbacks finding the UI thread still. This makes sure we allow those 207 // callbacks finding the UI thread still. This makes sure we allow those
214 // scheduled calls to AddRequest to complete before we show the page-load 208 // scheduled calls to AddRequest to complete before we show the page-load
215 // permissions bubble. 209 // permissions bubble.
216 // TODO(gbillock): make this bind safe with a weak ptr. 210 ScheduleShowBubble();
217 content::BrowserThread::PostTask( 211 }
218 content::BrowserThread::UI, FROM_HERE, 212
219 base::Bind(&PermissionBubbleManager::ShowBubble, 213 void PermissionBubbleManager::DocumentLoadedInFrame(
220 weak_factory_.GetWeakPtr())); 214 int64 frame_id,
215 content::RenderViewHost* render_view_host) {
216 if (request_url_has_loaded_)
217 ScheduleShowBubble();
221 } 218 }
222 219
223 void PermissionBubbleManager::NavigationEntryCommitted( 220 void PermissionBubbleManager::NavigationEntryCommitted(
224 const content::LoadCommittedDetails& details) { 221 const content::LoadCommittedDetails& details) {
225 // No permissions requests pending. 222 // No permissions requests pending.
226 if (request_url_.is_empty()) 223 if (request_url_.is_empty())
227 return; 224 return;
228 225
229 // If we have navigated to a new url... 226 // If we have navigated to a new url or reloaded the page...
230 if (request_url_ != web_contents()->GetLastCommittedURL()) { 227 if (request_url_ != web_contents()->GetLastCommittedURL() ||
228 details.type == content::NAVIGATION_TYPE_EXISTING_PAGE) {
231 // Kill off existing bubble and cancel any pending requests. 229 // Kill off existing bubble and cancel any pending requests.
232 CancelPendingQueue(); 230 CancelPendingQueue();
233 FinalizeBubble(); 231 FinalizeBubble();
234 } 232 }
235 } 233 }
236 234
237 void PermissionBubbleManager::WebContentsDestroyed() { 235 void PermissionBubbleManager::WebContentsDestroyed() {
238 // If the web contents has been destroyed, treat the bubble as cancelled. 236 // If the web contents has been destroyed, treat the bubble as cancelled.
239 CancelPendingQueue(); 237 CancelPendingQueue();
240 FinalizeBubble(); 238 FinalizeBubble();
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
285 void PermissionBubbleManager::Closing() { 283 void PermissionBubbleManager::Closing() {
286 std::vector<PermissionBubbleRequest*>::iterator requests_iter; 284 std::vector<PermissionBubbleRequest*>::iterator requests_iter;
287 for (requests_iter = requests_.begin(); 285 for (requests_iter = requests_.begin();
288 requests_iter != requests_.end(); 286 requests_iter != requests_.end();
289 requests_iter++) { 287 requests_iter++) {
290 (*requests_iter)->Cancelled(); 288 (*requests_iter)->Cancelled();
291 } 289 }
292 FinalizeBubble(); 290 FinalizeBubble();
293 } 291 }
294 292
295 // TODO(gbillock): find a better name for this method. 293 void PermissionBubbleManager::ScheduleShowBubble() {
296 void PermissionBubbleManager::ShowBubble() { 294 content::BrowserThread::PostTask(
295 content::BrowserThread::UI,
296 FROM_HERE,
297 base::Bind(&PermissionBubbleManager::TriggerShowBubble,
298 weak_factory_.GetWeakPtr()));
299 }
300
301 void PermissionBubbleManager::TriggerShowBubble() {
297 if (!view_) 302 if (!view_)
298 return; 303 return;
299 if (requests_.empty())
300 return;
301 if (bubble_showing_) 304 if (bubble_showing_)
302 return; 305 return;
303 if (!request_url_has_loaded_) 306 if (!request_url_has_loaded_)
304 return; 307 return;
308 if (requests_.empty() && queued_requests_.empty() &&
309 queued_frame_requests_.empty())
310 return;
311
312 if (requests_.empty()) {
313 // Queues containing a user-gesture-generated request have priority.
314 if (HasUserGestureRequest(queued_requests_))
315 requests_.swap(queued_requests_);
316 else if (HasUserGestureRequest(queued_frame_requests_))
317 requests_.swap(queued_frame_requests_);
318 else if (queued_requests_.size())
319 requests_.swap(queued_requests_);
320 else
321 requests_.swap(queued_frame_requests_);
322
323 // Sets the default value for each request to be 'accept'.
324 // TODO(leng): Currently all requests default to true. If that changes:
325 // a) Add additional accept_state queues to store default values.
326 // b) Change the request API to provide the default value.
327 accept_states_.resize(requests_.size(), true);
328 }
305 329
306 // Note: this should appear above Show() for testing, since in that 330 // Note: this should appear above Show() for testing, since in that
307 // case we may do in-line calling of finalization. 331 // case we may do in-line calling of finalization.
308 bubble_showing_ = true; 332 bubble_showing_ = true;
309 view_->Show(requests_, accept_states_, customization_mode_); 333 view_->Show(requests_, accept_states_, customization_mode_);
310 } 334 }
311 335
312 void PermissionBubbleManager::FinalizeBubble() { 336 void PermissionBubbleManager::FinalizeBubble() {
313 if (view_) 337 if (view_)
314 view_->Hide(); 338 view_->Hide();
315 bubble_showing_ = false; 339 bubble_showing_ = false;
316 340
317 std::vector<PermissionBubbleRequest*>::iterator requests_iter; 341 std::vector<PermissionBubbleRequest*>::iterator requests_iter;
318 for (requests_iter = requests_.begin(); 342 for (requests_iter = requests_.begin();
319 requests_iter != requests_.end(); 343 requests_iter != requests_.end();
320 requests_iter++) { 344 requests_iter++) {
321 (*requests_iter)->RequestFinished(); 345 (*requests_iter)->RequestFinished();
322 } 346 }
323 requests_.clear(); 347 requests_.clear();
324 accept_states_.clear(); 348 accept_states_.clear();
325 if (queued_requests_.size()) { 349 if (queued_requests_.size() || queued_frame_requests_.size()) {
326 requests_ = queued_requests_; 350 TriggerShowBubble();
327 accept_states_.resize(requests_.size(), true);
328 queued_requests_.clear();
329 ShowBubble();
330 } else { 351 } else {
331 request_url_ = GURL(); 352 request_url_ = GURL();
332 } 353 }
333 } 354 }
334 355
335 void PermissionBubbleManager::CancelPendingQueue() { 356 void PermissionBubbleManager::CancelPendingQueue() {
336 std::vector<PermissionBubbleRequest*>::iterator requests_iter; 357 std::vector<PermissionBubbleRequest*>::iterator requests_iter;
337 for (requests_iter = queued_requests_.begin(); 358 for (requests_iter = queued_requests_.begin();
338 requests_iter != queued_requests_.end(); 359 requests_iter != queued_requests_.end();
339 requests_iter++) { 360 requests_iter++) {
340 (*requests_iter)->RequestFinished(); 361 (*requests_iter)->RequestFinished();
341 } 362 }
342 } 363 }
364
365 bool PermissionBubbleManager::ExistingRequest(
366 PermissionBubbleRequest* request,
367 const std::vector<PermissionBubbleRequest*>& queue,
368 bool* same_object) {
369 CHECK(same_object);
370 *same_object = false;
371 std::vector<PermissionBubbleRequest*>::const_iterator iter;
372 for (iter = queue.begin(); iter != queue.end(); iter++) {
373 if (*iter == request) {
374 *same_object = true;
375 return true;
376 }
377 if ((*iter)->GetMessageTextFragment() ==
378 request->GetMessageTextFragment() &&
379 (*iter)->GetRequestingHostname() == request->GetRequestingHostname()) {
380 return true;
381 }
382 }
383 return false;
384 }
385
386 bool PermissionBubbleManager::HasUserGestureRequest(
387 const std::vector<PermissionBubbleRequest*>& queue) {
388 std::vector<PermissionBubbleRequest*>::const_iterator iter;
389 for (iter = queue.begin(); iter != queue.end(); iter++) {
390 if ((*iter)->HasUserGesture())
391 return true;
392 }
393 return false;
394 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698