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

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

Powered by Google App Engine
This is Rietveld 408576698