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

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: fixed duplicate logic 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_;
Greg Billock 2014/05/21 17:09:19 Do we need to extract just the hostport from the r
leng 2014/05/22 00:08:47 I have no idea. I don't know enough about main fr
Greg Billock 2014/05/22 02:06:31 I think GetLastCommittedURL() is the full url, and
leng 2014/05/22 23:57:05 Got it. I changed it to use GetOrigin() for both
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 exact_duplicate = false;
107 for (requests_iter = requests_.begin(); 109 if (ExistingRequest(request, requests_, &exact_duplicate) ||
Greg Billock 2014/05/21 17:09:19 Maybe exact_duplicate --> same_object ?
leng 2014/05/22 00:08:47 Good call. Done.
108 requests_iter != requests_.end(); 110 ExistingRequest(request, queued_requests_, &exact_duplicate) ||
109 requests_iter++) { 111 ExistingRequest(request, queued_frame_requests_, &exact_duplicate)) {
110 if (*requests_iter == request) 112 if (!exact_duplicate)
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)
128 requests_.push_back(request);
129 else
130 queued_frame_requests_.push_back(request);
131
139 // TODO(gbillock): do we need to make default state a request property? 132 // TODO(gbillock): do we need to make default state a request property?
140 accept_states_.push_back(true); 133 accept_states_.push_back(true);
Greg Billock 2014/05/21 17:09:19 should this only execute if is_main_frame, right?
leng 2014/05/22 00:08:47 Done.
141 134
142 if (request->HasUserGesture()) 135 if (request->HasUserGesture())
143 ShowBubble(); 136 TriggerShowBubble();
Greg Billock 2014/05/21 17:09:19 Should this be ScheduleShowBubble, right? (and was
leng 2014/05/22 00:08:47 I see no harm in making it ScheduleShowBubble(), a
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_) {
Greg Billock 2014/05/21 17:09:19 no braces
leng 2014/05/22 00:08:47 Done.
216 ScheduleShowBubble();
217 }
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) {
Greg Billock 2014/05/21 17:09:19 Makes sense. We then get the re-notifications for
leng 2014/05/22 00:08:47 Correct. I tested it manually.
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, 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() &&
308 queued_requests_.empty() &&
309 queued_frame_requests_.empty())
310 return;
311
312 if (requests_.empty()) {
313 if (queued_requests_.size())
314 requests_.swap(queued_requests_);
315 else
316 requests_.swap(queued_frame_requests_);
317 accept_states_.resize(requests_.size(), true);
Greg Billock 2014/05/21 17:09:19 Maybe a comment that the 'true' here is setting th
leng 2014/05/22 00:08:47 Done.
318 }
305 319
306 // Note: this should appear above Show() for testing, since in that 320 // Note: this should appear above Show() for testing, since in that
307 // case we may do in-line calling of finalization. 321 // case we may do in-line calling of finalization.
308 bubble_showing_ = true; 322 bubble_showing_ = true;
309 view_->Show(requests_, accept_states_, customization_mode_); 323 view_->Show(requests_, accept_states_, customization_mode_);
310 } 324 }
311 325
312 void PermissionBubbleManager::FinalizeBubble() { 326 void PermissionBubbleManager::FinalizeBubble() {
313 if (view_) 327 if (view_)
314 view_->Hide(); 328 view_->Hide();
315 bubble_showing_ = false; 329 bubble_showing_ = false;
316 330
317 std::vector<PermissionBubbleRequest*>::iterator requests_iter; 331 std::vector<PermissionBubbleRequest*>::iterator requests_iter;
318 for (requests_iter = requests_.begin(); 332 for (requests_iter = requests_.begin();
319 requests_iter != requests_.end(); 333 requests_iter != requests_.end();
320 requests_iter++) { 334 requests_iter++) {
321 (*requests_iter)->RequestFinished(); 335 (*requests_iter)->RequestFinished();
322 } 336 }
323 requests_.clear(); 337 requests_.clear();
324 accept_states_.clear(); 338 accept_states_.clear();
325 if (queued_requests_.size()) { 339 if (queued_requests_.size() || queued_frame_requests_.size()) {
326 requests_ = queued_requests_; 340 TriggerShowBubble();
327 accept_states_.resize(requests_.size(), true);
328 queued_requests_.clear();
329 ShowBubble();
330 } else { 341 } else {
331 request_url_ = GURL(); 342 request_url_ = GURL();
332 } 343 }
333 } 344 }
334 345
335 void PermissionBubbleManager::CancelPendingQueue() { 346 void PermissionBubbleManager::CancelPendingQueue() {
336 std::vector<PermissionBubbleRequest*>::iterator requests_iter; 347 std::vector<PermissionBubbleRequest*>::iterator requests_iter;
337 for (requests_iter = queued_requests_.begin(); 348 for (requests_iter = queued_requests_.begin();
338 requests_iter != queued_requests_.end(); 349 requests_iter != queued_requests_.end();
339 requests_iter++) { 350 requests_iter++) {
340 (*requests_iter)->RequestFinished(); 351 (*requests_iter)->RequestFinished();
341 } 352 }
342 } 353 }
354
355 bool PermissionBubbleManager::ExistingRequest(
356 PermissionBubbleRequest* request,
357 const std::vector<PermissionBubbleRequest*>& queue,
358 bool* exact_duplicate) {
359 std::vector<PermissionBubbleRequest*>::const_iterator iter;
360 for (iter = queue.begin();
Greg Billock 2014/05/21 17:09:19 fits on one line?
leng 2014/05/22 00:08:47 Done.
361 iter != queue.end();
362 iter++) {
363 if (*iter == request) {
364 if (exact_duplicate)
Greg Billock 2014/05/21 17:09:19 we can stipulate that CHECK(exact_duplicate)
leng 2014/05/22 00:08:47 Done.
365 *exact_duplicate = true;
366 return true;
367 }
368 if ((*iter)->GetMessageTextFragment() ==
369 request->GetMessageTextFragment() &&
370 (*iter)->GetRequestingHostname() ==
371 request->GetRequestingHostname()) {
372 if (exact_duplicate)
373 *exact_duplicate = false;
374 return true;
375 }
376 }
377 return false;
378 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698