Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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; |
| OLD | NEW |