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

Side by Side Diff: chrome/browser/download/download_request_limiter.cc

Issue 10412061: Fix crashes in DownloadRequestLimiter when extension popups/bubbles initiate downloads automatically (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/download/download_request_limiter.h" 5 #include "chrome/browser/download/download_request_limiter.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/stl_util.h" 8 #include "base/stl_util.h"
9 #include "chrome/browser/download/download_request_infobar_delegate.h" 9 #include "chrome/browser/download/download_request_infobar_delegate.h"
10 #include "chrome/browser/infobars/infobar_tab_helper.h" 10 #include "chrome/browser/infobars/infobar_tab_helper.h"
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
77 WebContents* tab, 77 WebContents* tab,
78 const DownloadRequestLimiter::Callback& callback) { 78 const DownloadRequestLimiter::Callback& callback) {
79 callbacks_.push_back(callback); 79 callbacks_.push_back(callback);
80 80
81 if (is_showing_prompt()) 81 if (is_showing_prompt())
82 return; // Already showing prompt. 82 return; // Already showing prompt.
83 83
84 if (DownloadRequestLimiter::delegate_) { 84 if (DownloadRequestLimiter::delegate_) {
85 NotifyCallbacks(DownloadRequestLimiter::delegate_->ShouldAllowDownload()); 85 NotifyCallbacks(DownloadRequestLimiter::delegate_->ShouldAllowDownload());
86 } else { 86 } else {
87 InfoBarTabHelper* infobar_helper = 87 TabContentsWrapper* tab_wrapper =
88 TabContentsWrapper::GetCurrentWrapperForContents(tab)-> 88 TabContentsWrapper::GetCurrentWrapperForContents(tab);
89 infobar_tab_helper(); 89 if (!tab_wrapper) {
Randy Smith (Not in Mondays) 2012/05/23 21:57:54 A sentence or two aside from the TODOs indicating
benjhayden 2012/05/24 20:43:39 Done.
90 // TODO(benjhayden): There's a bug in chromium where OnUserGesture() is
91 // not being called for successive clicks/downloads.
92 // TODO(benjhayden): If this is an automatic download from an extension,
93 // send a message to the extension's DevTools console (as we do for CSP)
94 // about how extensions should use chrome.downloads.download() to
95 // automatically download multiple files. This method requires the
96 // "downloads" permission.
97 Cancel();
98 return;
99 }
100 InfoBarTabHelper* infobar_helper = tab_wrapper->infobar_tab_helper();
90 infobar_ = new DownloadRequestInfoBarDelegate(infobar_helper, this); 101 infobar_ = new DownloadRequestInfoBarDelegate(infobar_helper, this);
91 infobar_helper->AddInfoBar(infobar_); 102 infobar_helper->AddInfoBar(infobar_);
92 } 103 }
93 } 104 }
94 105
95 void DownloadRequestLimiter::TabDownloadState::Cancel() { 106 void DownloadRequestLimiter::TabDownloadState::Cancel() {
96 NotifyCallbacks(false); 107 NotifyCallbacks(false);
97 } 108 }
98 109
99 void DownloadRequestLimiter::TabDownloadState::Accept() { 110 void DownloadRequestLimiter::TabDownloadState::Accept() {
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 } 215 }
205 216
206 DownloadRequestLimiter::~DownloadRequestLimiter() { 217 DownloadRequestLimiter::~DownloadRequestLimiter() {
207 // All the tabs should have closed before us, which sends notification and 218 // All the tabs should have closed before us, which sends notification and
208 // removes from state_map_. As such, there should be no pending callbacks. 219 // removes from state_map_. As such, there should be no pending callbacks.
209 DCHECK(state_map_.empty()); 220 DCHECK(state_map_.empty());
210 } 221 }
211 222
212 DownloadRequestLimiter::DownloadStatus 223 DownloadRequestLimiter::DownloadStatus
213 DownloadRequestLimiter::GetDownloadStatus(WebContents* tab) { 224 DownloadRequestLimiter::GetDownloadStatus(WebContents* tab) {
214 TabDownloadState* state = GetDownloadState(&tab->GetController(), NULL, false) ; 225 TabDownloadState* state =
226 GetDownloadState(&tab->GetController(), NULL, false);
215 return state ? state->download_status() : ALLOW_ONE_DOWNLOAD; 227 return state ? state->download_status() : ALLOW_ONE_DOWNLOAD;
216 } 228 }
217 229
218 void DownloadRequestLimiter::CanDownloadOnIOThread( 230 void DownloadRequestLimiter::CanDownloadOnIOThread(
219 int render_process_host_id, 231 int render_process_host_id,
220 int render_view_id, 232 int render_view_id,
221 int request_id, 233 int request_id,
222 const std::string& request_method, 234 const std::string& request_method,
223 const Callback& callback) { 235 const Callback& callback) {
224 // This is invoked on the IO thread. Schedule the task to run on the UI 236 // This is invoked on the IO thread. Schedule the task to run on the UI
225 // thread so that we can query UI state. 237 // thread so that we can query UI state.
226 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 238 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
227 BrowserThread::PostTask( 239 BrowserThread::PostTask(
228 BrowserThread::UI, FROM_HERE, 240 BrowserThread::UI, FROM_HERE,
229 base::Bind(&DownloadRequestLimiter::CanDownload, this, 241 base::Bind(&DownloadRequestLimiter::CanDownload, this,
230 render_process_host_id, render_view_id, request_id, 242 render_process_host_id, render_view_id, request_id,
231 request_method, callback)); 243 request_method, callback));
232 } 244 }
233 245
234 void DownloadRequestLimiter::OnUserGesture(WebContents* tab) { 246 void DownloadRequestLimiter::OnUserGesture(WebContents* tab) {
235 TabDownloadState* state = 247 TabDownloadState* state = GetDownloadState(
236 GetDownloadState(&tab->GetController(), NULL, false); 248 &tab->GetController(), NULL, false);
237 if (!state) 249 if (!state)
238 return; 250 return;
239 251
240 state->OnUserGesture(); 252 state->OnUserGesture();
241 } 253 }
242 254
243 // static 255 // static
244 void DownloadRequestLimiter::SetTestingDelegate(TestingDelegate* delegate) { 256 void DownloadRequestLimiter::SetTestingDelegate(TestingDelegate* delegate) {
245 delegate_ = delegate; 257 delegate_ = delegate;
246 } 258 }
247 259
248 DownloadRequestLimiter::TabDownloadState* DownloadRequestLimiter:: 260 DownloadRequestLimiter::TabDownloadState*
249 GetDownloadState(NavigationController* controller, 261 DownloadRequestLimiter::GetDownloadState(
250 NavigationController* originating_controller, 262 NavigationController* controller,
251 bool create) { 263 NavigationController* originating_controller,
264 bool create) {
252 DCHECK(controller); 265 DCHECK(controller);
253 StateMap::iterator i = state_map_.find(controller); 266 StateMap::iterator i = state_map_.find(controller);
254 if (i != state_map_.end()) 267 if (i != state_map_.end())
255 return i->second; 268 return i->second;
256 269
257 if (!create) 270 if (!create)
258 return NULL; 271 return NULL;
259 272
260 TabDownloadState* state = 273 TabDownloadState* state =
261 new TabDownloadState(this, controller, originating_controller); 274 new TabDownloadState(this, controller, originating_controller);
262 state_map_[controller] = state; 275 state_map_[controller] = state;
263 return state; 276 return state;
264 } 277 }
265 278
266 void DownloadRequestLimiter::CanDownload(int render_process_host_id, 279 void DownloadRequestLimiter::CanDownload(int render_process_host_id,
267 int render_view_id, 280 int render_view_id,
268 int request_id, 281 int request_id,
269 const std::string& request_method, 282 const std::string& request_method,
270 const Callback& callback) { 283 const Callback& callback) {
271 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 284 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
272 285
273 WebContents* originating_tab = 286 WebContents* originating_contents =
274 tab_util::GetWebContentsByID(render_process_host_id, render_view_id); 287 tab_util::GetWebContentsByID(render_process_host_id, render_view_id);
275 if (!originating_tab) { 288 if (!originating_contents) {
276 // The tab was closed, don't allow the download. 289 // The tab was closed, don't allow the download.
277 ScheduleNotification(callback, false); 290 ScheduleNotification(callback, false);
278 return; 291 return;
279 } 292 }
280 293
281 CanDownloadImpl( 294 CanDownloadImpl(
282 TabContentsWrapper::GetCurrentWrapperForContents(originating_tab), 295 originating_contents,
283 request_id, 296 request_id,
284 request_method, 297 request_method,
285 callback); 298 callback);
286 } 299 }
287 300
288 void DownloadRequestLimiter::CanDownloadImpl( 301 void DownloadRequestLimiter::CanDownloadImpl(WebContents* originating_contents,
289 TabContentsWrapper* originating_tab, 302 int request_id,
290 int request_id, 303 const std::string& request_method,
291 const std::string& request_method, 304 const Callback& callback) {
292 const Callback& callback) { 305 DCHECK(originating_contents);
293 DCHECK(originating_tab);
294 306
295 // FYI: Chrome Frame overrides CanDownload in ExternalTabContainer in order 307 // FYI: Chrome Frame overrides CanDownload in ExternalTabContainer in order
296 // to cancel the download operation in chrome and let the host browser 308 // to cancel the download operation in chrome and let the host browser
297 // take care of it. 309 // take care of it.
298 WebContents* tab = originating_tab->web_contents(); 310 if (originating_contents->GetDelegate() &&
299 if (tab->GetDelegate() && !tab->GetDelegate()->CanDownload( 311 !originating_contents->GetDelegate()->CanDownload(
300 tab->GetRenderViewHost(), request_id, request_method)) { 312 originating_contents->GetRenderViewHost(),
313 request_id,
314 request_method)) {
301 ScheduleNotification(callback, false); 315 ScheduleNotification(callback, false);
302 return; 316 return;
303 } 317 }
304 318
305 // If the tab requesting the download is a constrained popup that is not 319 // If the tab requesting the download is a constrained popup that is not
306 // shown, treat the request as if it came from the parent. 320 // shown, treat the request as if it came from the parent.
307 TabContentsWrapper* effective_wrapper = originating_tab; 321 WebContents* effective_contents = originating_contents;
308 if (effective_wrapper->blocked_content_tab_helper()->delegate()) { 322 TabContentsWrapper* originating_wrapper =
309 effective_wrapper = effective_wrapper->blocked_content_tab_helper()-> 323 TabContentsWrapper::GetCurrentWrapperForContents(originating_contents);
310 delegate()->GetConstrainingContentsWrapper(effective_wrapper); 324 if (originating_wrapper &&
325 originating_wrapper->blocked_content_tab_helper()->delegate()) {
326 effective_contents = originating_wrapper->blocked_content_tab_helper()->
327 delegate()->GetConstrainingContentsWrapper(originating_wrapper)->
328 web_contents();
311 } 329 }
312 330
313 TabDownloadState* state = GetDownloadState( 331 TabDownloadState* state = GetDownloadState(
314 &effective_wrapper->web_contents()->GetController(), 332 &effective_contents->GetController(),
315 &tab->GetController(), true); 333 &originating_contents->GetController(),
334 true);
316 switch (state->download_status()) { 335 switch (state->download_status()) {
317 case ALLOW_ALL_DOWNLOADS: 336 case ALLOW_ALL_DOWNLOADS:
318 if (state->download_count() && !(state->download_count() % 337 if (state->download_count() && !(state->download_count() %
319 DownloadRequestLimiter::kMaxDownloadsAtOnce)) 338 DownloadRequestLimiter::kMaxDownloadsAtOnce))
320 state->set_download_status(PROMPT_BEFORE_DOWNLOAD); 339 state->set_download_status(PROMPT_BEFORE_DOWNLOAD);
321 ScheduleNotification(callback, true); 340 ScheduleNotification(callback, true);
322 state->increment_download_count(); 341 state->increment_download_count();
323 break; 342 break;
324 343
325 case ALLOW_ONE_DOWNLOAD: 344 case ALLOW_ONE_DOWNLOAD:
326 state->set_download_status(PROMPT_BEFORE_DOWNLOAD); 345 state->set_download_status(PROMPT_BEFORE_DOWNLOAD);
327 ScheduleNotification(callback, true); 346 ScheduleNotification(callback, true);
328 break; 347 break;
329 348
330 case DOWNLOADS_NOT_ALLOWED: 349 case DOWNLOADS_NOT_ALLOWED:
331 ScheduleNotification(callback, false); 350 ScheduleNotification(callback, false);
332 break; 351 break;
333 352
334 case PROMPT_BEFORE_DOWNLOAD: 353 case PROMPT_BEFORE_DOWNLOAD:
335 state->PromptUserForDownload(effective_wrapper->web_contents(), callback); 354 state->PromptUserForDownload(effective_contents, callback);
336 state->increment_download_count(); 355 state->increment_download_count();
337 break; 356 break;
338 357
339 default: 358 default:
340 NOTREACHED(); 359 NOTREACHED();
341 } 360 }
342 } 361 }
343 362
344 void DownloadRequestLimiter::ScheduleNotification(const Callback& callback, 363 void DownloadRequestLimiter::ScheduleNotification(const Callback& callback,
345 bool allow) { 364 bool allow) {
346 BrowserThread::PostTask( 365 BrowserThread::PostTask(
347 BrowserThread::IO, FROM_HERE, base::Bind(callback, allow)); 366 BrowserThread::IO, FROM_HERE, base::Bind(callback, allow));
348 } 367 }
349 368
350 void DownloadRequestLimiter::Remove(TabDownloadState* state) { 369 void DownloadRequestLimiter::Remove(TabDownloadState* state) {
351 DCHECK(ContainsKey(state_map_, state->controller())); 370 DCHECK(ContainsKey(state_map_, state->controller()));
352 state_map_.erase(state->controller()); 371 state_map_.erase(state->controller());
353 delete state; 372 delete state;
354 } 373 }
355 374
356 // static 375 // static
357 DownloadRequestLimiter::TestingDelegate* DownloadRequestLimiter::delegate_ = 376 DownloadRequestLimiter::TestingDelegate* DownloadRequestLimiter::delegate_ =
358 NULL; 377 NULL;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698