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

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

Issue 1610753002: Fixes Permission Bubbles never responding to duplicate requests (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix typo Created 4 years, 11 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
« no previous file with comments | « chrome/browser/ui/website_settings/permission_bubble_manager.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "build/build_config.h" 9 #include "build/build_config.h"
10 #include "chrome/browser/ui/website_settings/permission_bubble_request.h" 10 #include "chrome/browser/ui/website_settings/permission_bubble_request.h"
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 view_(nullptr), 76 view_(nullptr),
77 main_frame_has_fully_loaded_(false), 77 main_frame_has_fully_loaded_(false),
78 auto_response_for_test_(NONE), 78 auto_response_for_test_(NONE),
79 weak_factory_(this) { 79 weak_factory_(this) {
80 } 80 }
81 81
82 PermissionBubbleManager::~PermissionBubbleManager() { 82 PermissionBubbleManager::~PermissionBubbleManager() {
83 if (view_ != NULL) 83 if (view_ != NULL)
84 view_->SetDelegate(NULL); 84 view_->SetDelegate(NULL);
85 85
86 std::vector<PermissionBubbleRequest*>::iterator requests_iter; 86 for (PermissionBubbleRequest* request : requests_)
87 for (requests_iter = requests_.begin(); 87 request->RequestFinished();
88 requests_iter != requests_.end(); 88 for (PermissionBubbleRequest* request : queued_requests_)
89 requests_iter++) { 89 request->RequestFinished();
90 (*requests_iter)->RequestFinished(); 90 for (PermissionBubbleRequest* request : queued_frame_requests_)
91 } 91 request->RequestFinished();
92 for (requests_iter = queued_requests_.begin(); 92 for (const auto& entry : duplicate_requests_)
93 requests_iter != queued_requests_.end(); 93 entry.second->RequestFinished();
94 requests_iter++) {
95 (*requests_iter)->RequestFinished();
96 }
97 } 94 }
98 95
99 void PermissionBubbleManager::AddRequest(PermissionBubbleRequest* request) { 96 void PermissionBubbleManager::AddRequest(PermissionBubbleRequest* request) {
100 content::RecordAction(base::UserMetricsAction("PermissionBubbleRequest")); 97 content::RecordAction(base::UserMetricsAction("PermissionBubbleRequest"));
101 // 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
102 // 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
103 // page? We should maybe listen to DidStartNavigationToPendingEntry (and 100 // page? We should maybe listen to DidStartNavigationToPendingEntry (and
104 // any other renderer-side nav initiations?). Double-check this for 101 // any other renderer-side nav initiations?). Double-check this for
105 // correct behavior on interstitials -- we probably want to basically queue 102 // correct behavior on interstitials -- we probably want to basically queue
106 // any request for which GetVisibleURL != GetLastCommittedURL. 103 // any request for which GetVisibleURL != GetLastCommittedURL.
107 request_url_ = web_contents()->GetLastCommittedURL(); 104 request_url_ = web_contents()->GetLastCommittedURL();
108 bool is_main_frame = 105 bool is_main_frame =
109 url::Origin(request_url_) 106 url::Origin(request_url_)
110 .IsSameOriginWith(url::Origin(request->GetRequestingHostname())); 107 .IsSameOriginWith(url::Origin(request->GetRequestingHostname()));
111 108
112 // Don't re-add an existing request or one with a duplicate text request. 109 // Don't re-add an existing request or one with a duplicate text request.
113 // TODO(johnme): Instead of dropping duplicate requests, we should queue them 110 PermissionBubbleRequest* existing_request = GetExistingRequest(request);
114 // and eventually run their PermissionGranted/PermissionDenied/Cancelled 111 if (existing_request) {
115 // callback (crbug.com/577313). 112 // |request| is a duplicate. Add it to |duplicate_requests_| unless it's the
116 bool same_object = false; 113 // same object as |existing_request| or an existing duplicate.
117 if (ExistingRequest(request, requests_, &same_object) || 114 if (request == existing_request)
118 ExistingRequest(request, queued_requests_, &same_object) || 115 return;
119 ExistingRequest(request, queued_frame_requests_, &same_object)) { 116 auto range = duplicate_requests_.equal_range(existing_request);
120 if (!same_object) 117 for (auto it = range.first; it != range.second; ++it) {
121 request->RequestFinished(); 118 if (request == it->second)
119 return;
120 }
121 duplicate_requests_.insert(std::make_pair(existing_request, request));
122 return; 122 return;
123 } 123 }
124 124
125 if (IsBubbleVisible()) { 125 if (IsBubbleVisible()) {
126 if (is_main_frame) { 126 if (is_main_frame) {
127 content::RecordAction( 127 content::RecordAction(
128 base::UserMetricsAction("PermissionBubbleRequestQueued")); 128 base::UserMetricsAction("PermissionBubbleRequestQueued"));
129 queued_requests_.push_back(request); 129 queued_requests_.push_back(request);
130 } else { 130 } else {
131 content::RecordAction( 131 content::RecordAction(
(...skipping 10 matching lines...) Expand all
142 } else { 142 } else {
143 content::RecordAction( 143 content::RecordAction(
144 base::UserMetricsAction("PermissionBubbleIFrameRequestQueued")); 144 base::UserMetricsAction("PermissionBubbleIFrameRequestQueued"));
145 queued_frame_requests_.push_back(request); 145 queued_frame_requests_.push_back(request);
146 } 146 }
147 147
148 ScheduleShowBubble(); 148 ScheduleShowBubble();
149 } 149 }
150 150
151 void PermissionBubbleManager::CancelRequest(PermissionBubbleRequest* request) { 151 void PermissionBubbleManager::CancelRequest(PermissionBubbleRequest* request) {
152 // First look in the queued requests, where we can simply delete the request 152 // First look in the queued requests, where we can simply finish the request
153 // and go on. 153 // and go on.
154 std::vector<PermissionBubbleRequest*>::iterator requests_iter; 154 std::vector<PermissionBubbleRequest*>::iterator requests_iter;
155 for (requests_iter = queued_requests_.begin(); 155 for (requests_iter = queued_requests_.begin();
156 requests_iter != queued_requests_.end(); 156 requests_iter != queued_requests_.end();
157 requests_iter++) { 157 requests_iter++) {
158 if (*requests_iter == request) { 158 if (*requests_iter == request) {
159 (*requests_iter)->RequestFinished(); 159 RequestFinishedIncludingDuplicates(*requests_iter);
160 queued_requests_.erase(requests_iter); 160 queued_requests_.erase(requests_iter);
161 return; 161 return;
162 } 162 }
163 } 163 }
164 for (requests_iter = queued_frame_requests_.begin();
165 requests_iter != queued_frame_requests_.end(); requests_iter++) {
166 if (*requests_iter == request) {
167 RequestFinishedIncludingDuplicates(*requests_iter);
168 queued_frame_requests_.erase(requests_iter);
169 return;
170 }
171 }
164 172
165 std::vector<bool>::iterator accepts_iter = accept_states_.begin(); 173 std::vector<bool>::iterator accepts_iter = accept_states_.begin();
166 for (requests_iter = requests_.begin(), accepts_iter = accept_states_.begin(); 174 for (requests_iter = requests_.begin(), accepts_iter = accept_states_.begin();
167 requests_iter != requests_.end(); 175 requests_iter != requests_.end();
168 requests_iter++, accepts_iter++) { 176 requests_iter++, accepts_iter++) {
169 if (*requests_iter != request) 177 if (*requests_iter != request)
170 continue; 178 continue;
171 179
172 // We can simply erase the current entry in the request table if we aren't 180 // We can simply erase the current entry in the request table if we aren't
173 // showing the dialog, or if we are showing it and it can accept the update. 181 // showing the dialog, or if we are showing it and it can accept the update.
174 bool can_erase = !IsBubbleVisible() || view_->CanAcceptRequestUpdate(); 182 bool can_erase = !IsBubbleVisible() || view_->CanAcceptRequestUpdate();
175 if (can_erase) { 183 if (can_erase) {
176 (*requests_iter)->RequestFinished(); 184 RequestFinishedIncludingDuplicates(*requests_iter);
177 requests_.erase(requests_iter); 185 requests_.erase(requests_iter);
178 accept_states_.erase(accepts_iter); 186 accept_states_.erase(accepts_iter);
179 187
180 if (IsBubbleVisible()) { 188 if (IsBubbleVisible()) {
181 view_->Hide(); 189 view_->Hide();
182 // Will redraw the bubble if it is being shown. 190 // Will redraw the bubble if it is being shown.
183 TriggerShowBubble(); 191 TriggerShowBubble();
184 } 192 }
185 return; 193 return;
186 } 194 }
187 195
188 // Cancel the existing request and replace it with a dummy. 196 // Cancel the existing request and replace it with a dummy.
189 PermissionBubbleRequest* cancelled_request = 197 PermissionBubbleRequest* cancelled_request =
190 new CancelledRequest(*requests_iter); 198 new CancelledRequest(*requests_iter);
191 (*requests_iter)->RequestFinished(); 199 RequestFinishedIncludingDuplicates(*requests_iter);
192 *requests_iter = cancelled_request; 200 *requests_iter = cancelled_request;
193 return; 201 return;
194 } 202 }
195 203
204 // Finally look through the duplicate requests, which can simply be finished.
205 PermissionBubbleRequest* existing_request = GetExistingRequest(request);
felt 2016/01/23 16:51:43 If RequestFinishedIncludingDuplicates removes the
johnme 2016/01/26 15:57:55 Yes - normally duplicate requests only finish when
206 auto range = duplicate_requests_.equal_range(existing_request);
207 for (auto it = range.first; it != range.second; ++it) {
208 if (request == it->second) {
209 it->second->RequestFinished();
210 duplicate_requests_.erase(it);
211 return;
212 }
213 }
214
196 NOTREACHED(); // Callers should not cancel requests that are not pending. 215 NOTREACHED(); // Callers should not cancel requests that are not pending.
197 } 216 }
198 217
199 void PermissionBubbleManager::HideBubble() { 218 void PermissionBubbleManager::HideBubble() {
200 // Disengage from the existing view if there is one. 219 // Disengage from the existing view if there is one.
201 if (!view_) 220 if (!view_)
202 return; 221 return;
203 222
204 view_->SetDelegate(nullptr); 223 view_->SetDelegate(nullptr);
205 view_->Hide(); 224 view_->Hide();
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
279 DCHECK(request_index < static_cast<int>(accept_states_.size())); 298 DCHECK(request_index < static_cast<int>(accept_states_.size()));
280 accept_states_[request_index] = new_value; 299 accept_states_[request_index] = new_value;
281 } 300 }
282 301
283 void PermissionBubbleManager::Accept() { 302 void PermissionBubbleManager::Accept() {
284 std::vector<PermissionBubbleRequest*>::iterator requests_iter; 303 std::vector<PermissionBubbleRequest*>::iterator requests_iter;
285 std::vector<bool>::iterator accepts_iter = accept_states_.begin(); 304 std::vector<bool>::iterator accepts_iter = accept_states_.begin();
286 for (requests_iter = requests_.begin(), accepts_iter = accept_states_.begin(); 305 for (requests_iter = requests_.begin(), accepts_iter = accept_states_.begin();
287 requests_iter != requests_.end(); 306 requests_iter != requests_.end();
288 requests_iter++, accepts_iter++) { 307 requests_iter++, accepts_iter++) {
289 if (*accepts_iter) 308 if (*accepts_iter) {
290 (*requests_iter)->PermissionGranted(); 309 PermissionGrantedIncludingDuplicates(*requests_iter);
291 else 310 } else {
292 (*requests_iter)->PermissionDenied(); 311 PermissionDeniedIncludingDuplicates(*requests_iter);
312 }
293 } 313 }
294 FinalizeBubble(); 314 FinalizeBubble();
295 } 315 }
296 316
297 void PermissionBubbleManager::Deny() { 317 void PermissionBubbleManager::Deny() {
298 std::vector<PermissionBubbleRequest*>::iterator requests_iter; 318 std::vector<PermissionBubbleRequest*>::iterator requests_iter;
299 for (requests_iter = requests_.begin(); 319 for (requests_iter = requests_.begin();
300 requests_iter != requests_.end(); 320 requests_iter != requests_.end();
301 requests_iter++) { 321 requests_iter++) {
302 (*requests_iter)->PermissionDenied(); 322 PermissionDeniedIncludingDuplicates(*requests_iter);
303 } 323 }
304 FinalizeBubble(); 324 FinalizeBubble();
305 } 325 }
306 326
307 void PermissionBubbleManager::Closing() { 327 void PermissionBubbleManager::Closing() {
308 std::vector<PermissionBubbleRequest*>::iterator requests_iter; 328 std::vector<PermissionBubbleRequest*>::iterator requests_iter;
309 for (requests_iter = requests_.begin(); 329 for (requests_iter = requests_.begin();
310 requests_iter != requests_.end(); 330 requests_iter != requests_.end();
311 requests_iter++) { 331 requests_iter++) {
312 (*requests_iter)->Cancelled(); 332 CancelledIncludingDuplicates(*requests_iter);
313 } 333 }
314 FinalizeBubble(); 334 FinalizeBubble();
315 } 335 }
316 336
317 void PermissionBubbleManager::ScheduleShowBubble() { 337 void PermissionBubbleManager::ScheduleShowBubble() {
318 // ::ScheduleShowBubble() will be called again when the main frame will be 338 // ::ScheduleShowBubble() will be called again when the main frame will be
319 // loaded. 339 // loaded.
320 if (!main_frame_has_fully_loaded_) 340 if (!main_frame_has_fully_loaded_)
321 return; 341 return;
322 342
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
366 } 386 }
367 387
368 void PermissionBubbleManager::FinalizeBubble() { 388 void PermissionBubbleManager::FinalizeBubble() {
369 if (view_) 389 if (view_)
370 view_->Hide(); 390 view_->Hide();
371 391
372 std::vector<PermissionBubbleRequest*>::iterator requests_iter; 392 std::vector<PermissionBubbleRequest*>::iterator requests_iter;
373 for (requests_iter = requests_.begin(); 393 for (requests_iter = requests_.begin();
374 requests_iter != requests_.end(); 394 requests_iter != requests_.end();
375 requests_iter++) { 395 requests_iter++) {
376 (*requests_iter)->RequestFinished(); 396 RequestFinishedIncludingDuplicates(*requests_iter);
377 } 397 }
378 requests_.clear(); 398 requests_.clear();
379 accept_states_.clear(); 399 accept_states_.clear();
380 if (queued_requests_.size() || queued_frame_requests_.size()) 400 if (queued_requests_.size() || queued_frame_requests_.size())
381 TriggerShowBubble(); 401 TriggerShowBubble();
382 else 402 else
383 request_url_ = GURL(); 403 request_url_ = GURL();
384 } 404 }
385 405
386 void PermissionBubbleManager::CancelPendingQueues() { 406 void PermissionBubbleManager::CancelPendingQueues() {
387 std::vector<PermissionBubbleRequest*>::iterator requests_iter; 407 std::vector<PermissionBubbleRequest*>::iterator requests_iter;
388 for (requests_iter = queued_requests_.begin(); 408 for (requests_iter = queued_requests_.begin();
389 requests_iter != queued_requests_.end(); 409 requests_iter != queued_requests_.end();
390 requests_iter++) { 410 requests_iter++) {
391 (*requests_iter)->RequestFinished(); 411 RequestFinishedIncludingDuplicates(*requests_iter);
392 } 412 }
393 for (requests_iter = queued_frame_requests_.begin(); 413 for (requests_iter = queued_frame_requests_.begin();
394 requests_iter != queued_frame_requests_.end(); 414 requests_iter != queued_frame_requests_.end();
395 requests_iter++) { 415 requests_iter++) {
396 (*requests_iter)->RequestFinished(); 416 RequestFinishedIncludingDuplicates(*requests_iter);
397 } 417 }
398 queued_requests_.clear(); 418 queued_requests_.clear();
399 queued_frame_requests_.clear(); 419 queued_frame_requests_.clear();
400 } 420 }
401 421
402 bool PermissionBubbleManager::ExistingRequest( 422 bool MessageTextIsEqual(PermissionBubbleRequest* a,
felt 2016/01/23 16:51:43 nit: IsMessageTextEqual
johnme 2016/01/26 15:57:55 Done.
403 PermissionBubbleRequest* request, 423 PermissionBubbleRequest* b) {
404 const std::vector<PermissionBubbleRequest*>& queue, 424 if (a == b)
405 bool* same_object) { 425 return true;
406 CHECK(same_object); 426 if (a->GetMessageTextFragment() == b->GetMessageTextFragment() &&
407 *same_object = false; 427 a->GetRequestingHostname() == b->GetRequestingHostname()) {
felt 2016/01/23 16:57:28 This equality check is bugging me a little bit. I
johnme 2016/01/26 15:57:55 Hmm, interesting. I've put together https://codere
408 std::vector<PermissionBubbleRequest*>::const_iterator iter; 428 return true;
409 for (iter = queue.begin(); iter != queue.end(); iter++) {
410 if (*iter == request) {
411 *same_object = true;
412 return true;
413 }
414 if ((*iter)->GetMessageTextFragment() ==
415 request->GetMessageTextFragment() &&
416 (*iter)->GetRequestingHostname() == request->GetRequestingHostname()) {
417 return true;
418 }
419 } 429 }
420 return false; 430 return false;
421 } 431 }
422 432
433 PermissionBubbleRequest* PermissionBubbleManager::GetExistingRequest(
434 PermissionBubbleRequest* request) {
435 for (PermissionBubbleRequest* existing_request : requests_)
436 if (MessageTextIsEqual(existing_request, request))
437 return existing_request;
438 for (PermissionBubbleRequest* existing_request : queued_requests_)
439 if (MessageTextIsEqual(existing_request, request))
440 return existing_request;
441 for (PermissionBubbleRequest* existing_request : queued_frame_requests_)
442 if (MessageTextIsEqual(existing_request, request))
443 return existing_request;
444 return nullptr;
445 }
446
423 bool PermissionBubbleManager::HasUserGestureRequest( 447 bool PermissionBubbleManager::HasUserGestureRequest(
424 const std::vector<PermissionBubbleRequest*>& queue) { 448 const std::vector<PermissionBubbleRequest*>& queue) {
425 std::vector<PermissionBubbleRequest*>::const_iterator iter; 449 std::vector<PermissionBubbleRequest*>::const_iterator iter;
426 for (iter = queue.begin(); iter != queue.end(); iter++) { 450 for (iter = queue.begin(); iter != queue.end(); iter++) {
427 if ((*iter)->HasUserGesture()) 451 if ((*iter)->HasUserGesture())
428 return true; 452 return true;
429 } 453 }
430 return false; 454 return false;
431 } 455 }
432 456
457 void PermissionBubbleManager::PermissionGrantedIncludingDuplicates(
458 PermissionBubbleRequest* request) {
459 DCHECK_EQ(request, GetExistingRequest(request))
460 << "Request must not be a duplicate";
461 request->PermissionGranted();
462 auto range = duplicate_requests_.equal_range(request);
463 for (auto it = range.first; it != range.second; ++it)
464 it->second->PermissionGranted();
465 }
466 void PermissionBubbleManager::PermissionDeniedIncludingDuplicates(
467 PermissionBubbleRequest* request) {
468 DCHECK_EQ(request, GetExistingRequest(request))
469 << "Request must not be a duplicate";
470 request->PermissionDenied();
471 auto range = duplicate_requests_.equal_range(request);
472 for (auto it = range.first; it != range.second; ++it)
473 it->second->PermissionDenied();
474 }
475 void PermissionBubbleManager::CancelledIncludingDuplicates(
476 PermissionBubbleRequest* request) {
477 DCHECK_EQ(request, GetExistingRequest(request))
478 << "Request must not be a duplicate";
479 request->Cancelled();
480 auto range = duplicate_requests_.equal_range(request);
481 for (auto it = range.first; it != range.second; ++it)
482 it->second->Cancelled();
483 }
484 void PermissionBubbleManager::RequestFinishedIncludingDuplicates(
485 PermissionBubbleRequest* request) {
486 DCHECK_EQ(request, GetExistingRequest(request))
487 << "Request must not be a duplicate";
488 request->RequestFinished();
489 auto range = duplicate_requests_.equal_range(request);
490 for (auto it = range.first; it != range.second; ++it)
491 it->second->RequestFinished();
492 // Additionally, we can now remove the duplicates.
493 duplicate_requests_.erase(request);
felt 2016/01/23 16:51:43 Should you remove the duplicates in the other XInc
johnme 2016/01/26 15:57:55 No, RequestFinished is special. It is documented a
494 }
495
433 void PermissionBubbleManager::AddObserver(Observer* observer) { 496 void PermissionBubbleManager::AddObserver(Observer* observer) {
434 observer_list_.AddObserver(observer); 497 observer_list_.AddObserver(observer);
435 } 498 }
436 499
437 void PermissionBubbleManager::RemoveObserver(Observer* observer) { 500 void PermissionBubbleManager::RemoveObserver(Observer* observer) {
438 observer_list_.RemoveObserver(observer); 501 observer_list_.RemoveObserver(observer);
439 } 502 }
440 503
441 void PermissionBubbleManager::NotifyBubbleAdded() { 504 void PermissionBubbleManager::NotifyBubbleAdded() {
442 FOR_EACH_OBSERVER(Observer, observer_list_, OnBubbleAdded()); 505 FOR_EACH_OBSERVER(Observer, observer_list_, OnBubbleAdded());
443 } 506 }
444 507
445 void PermissionBubbleManager::DoAutoResponseForTesting() { 508 void PermissionBubbleManager::DoAutoResponseForTesting() {
446 switch (auto_response_for_test_) { 509 switch (auto_response_for_test_) {
447 case ACCEPT_ALL: 510 case ACCEPT_ALL:
448 Accept(); 511 Accept();
449 break; 512 break;
450 case DENY_ALL: 513 case DENY_ALL:
451 Deny(); 514 Deny();
452 break; 515 break;
453 case DISMISS: 516 case DISMISS:
454 Closing(); 517 Closing();
455 break; 518 break;
456 case NONE: 519 case NONE:
457 NOTREACHED(); 520 NOTREACHED();
458 } 521 }
459 } 522 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/website_settings/permission_bubble_manager.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698