OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } | |
OLD | NEW |