| 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/content_settings/tab_specific_content_settings.h" | 9 #include "chrome/browser/content_settings/tab_specific_content_settings.h" |
| 10 #include "chrome/browser/download/download_permission_request.h" | 10 #include "chrome/browser/download/download_permission_request.h" |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 callbacks.swap(callbacks_); | 240 callbacks.swap(callbacks_); |
| 241 } else { | 241 } else { |
| 242 std::vector<DownloadRequestLimiter::Callback>::iterator start, end; | 242 std::vector<DownloadRequestLimiter::Callback>::iterator start, end; |
| 243 start = callbacks_.begin(); | 243 start = callbacks_.begin(); |
| 244 end = callbacks_.begin() + kMaxDownloadsAtOnce; | 244 end = callbacks_.begin() + kMaxDownloadsAtOnce; |
| 245 callbacks.assign(start, end); | 245 callbacks.assign(start, end); |
| 246 callbacks_.erase(start, end); | 246 callbacks_.erase(start, end); |
| 247 change_status = true; | 247 change_status = true; |
| 248 } | 248 } |
| 249 | 249 |
| 250 for (size_t i = 0; i < callbacks.size(); ++i) | 250 for (const auto& callback : callbacks) { |
| 251 host_->ScheduleNotification(callbacks[i], allow); | 251 // When callback runs, it can cause the WebContents to be destroyed. |
| 252 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 253 base::Bind(callback, allow)); |
| 254 } |
| 252 | 255 |
| 253 if (change_status) | 256 if (change_status) |
| 254 set_download_status(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD); | 257 set_download_status(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD); |
| 255 } | 258 } |
| 256 | 259 |
| 257 // DownloadRequestLimiter ------------------------------------------------------ | 260 // DownloadRequestLimiter ------------------------------------------------------ |
| 258 | 261 |
| 259 HostContentSettingsMap* DownloadRequestLimiter::content_settings_ = NULL; | 262 HostContentSettingsMap* DownloadRequestLimiter::content_settings_ = NULL; |
| 260 | 263 |
| 261 void DownloadRequestLimiter::SetContentSettingsForTesting( | 264 void DownloadRequestLimiter::SetContentSettingsForTesting( |
| (...skipping 10 matching lines...) Expand all Loading... |
| 272 // removes from state_map_. As such, there should be no pending callbacks. | 275 // removes from state_map_. As such, there should be no pending callbacks. |
| 273 DCHECK(state_map_.empty()); | 276 DCHECK(state_map_.empty()); |
| 274 } | 277 } |
| 275 | 278 |
| 276 DownloadRequestLimiter::DownloadStatus | 279 DownloadRequestLimiter::DownloadStatus |
| 277 DownloadRequestLimiter::GetDownloadStatus(content::WebContents* web_contents) { | 280 DownloadRequestLimiter::GetDownloadStatus(content::WebContents* web_contents) { |
| 278 TabDownloadState* state = GetDownloadState(web_contents, NULL, false); | 281 TabDownloadState* state = GetDownloadState(web_contents, NULL, false); |
| 279 return state ? state->download_status() : ALLOW_ONE_DOWNLOAD; | 282 return state ? state->download_status() : ALLOW_ONE_DOWNLOAD; |
| 280 } | 283 } |
| 281 | 284 |
| 282 void DownloadRequestLimiter::CanDownloadOnIOThread( | |
| 283 int render_process_host_id, | |
| 284 int render_view_id, | |
| 285 const GURL& url, | |
| 286 const std::string& request_method, | |
| 287 const Callback& callback) { | |
| 288 // This is invoked on the IO thread. Schedule the task to run on the UI | |
| 289 // thread so that we can query UI state. | |
| 290 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 291 BrowserThread::PostTask( | |
| 292 BrowserThread::UI, FROM_HERE, | |
| 293 base::Bind(&DownloadRequestLimiter::CanDownload, this, | |
| 294 render_process_host_id, render_view_id, url, | |
| 295 request_method, callback)); | |
| 296 } | |
| 297 | |
| 298 DownloadRequestLimiter::TabDownloadState* | 285 DownloadRequestLimiter::TabDownloadState* |
| 299 DownloadRequestLimiter::GetDownloadState( | 286 DownloadRequestLimiter::GetDownloadState( |
| 300 content::WebContents* web_contents, | 287 content::WebContents* web_contents, |
| 301 content::WebContents* originating_web_contents, | 288 content::WebContents* originating_web_contents, |
| 302 bool create) { | 289 bool create) { |
| 303 DCHECK(web_contents); | 290 DCHECK(web_contents); |
| 304 StateMap::iterator i = state_map_.find(web_contents); | 291 StateMap::iterator i = state_map_.find(web_contents); |
| 305 if (i != state_map_.end()) | 292 if (i != state_map_.end()) |
| 306 return i->second; | 293 return i->second; |
| 307 | 294 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 318 int render_view_id, | 305 int render_view_id, |
| 319 const GURL& url, | 306 const GURL& url, |
| 320 const std::string& request_method, | 307 const std::string& request_method, |
| 321 const Callback& callback) { | 308 const Callback& callback) { |
| 322 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 309 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 323 | 310 |
| 324 content::WebContents* originating_contents = | 311 content::WebContents* originating_contents = |
| 325 tab_util::GetWebContentsByID(render_process_host_id, render_view_id); | 312 tab_util::GetWebContentsByID(render_process_host_id, render_view_id); |
| 326 if (!originating_contents) { | 313 if (!originating_contents) { |
| 327 // The WebContents was closed, don't allow the download. | 314 // The WebContents was closed, don't allow the download. |
| 328 ScheduleNotification(callback, false); | 315 callback.Run(false); |
| 329 return; | 316 return; |
| 330 } | 317 } |
| 331 | 318 |
| 332 if (!originating_contents->GetDelegate()) { | 319 if (!originating_contents->GetDelegate()) { |
| 333 ScheduleNotification(callback, false); | 320 callback.Run(false); |
| 334 return; | 321 return; |
| 335 } | 322 } |
| 336 | 323 |
| 337 // Note that because |originating_contents| might go away before | 324 // Note that because |originating_contents| might go away before |
| 338 // OnCanDownloadDecided is invoked, we look it up by |render_process_host_id| | 325 // OnCanDownloadDecided is invoked, we look it up by |render_process_host_id| |
| 339 // and |render_view_id|. | 326 // and |render_view_id|. |
| 340 base::Callback<void(bool)> can_download_callback = base::Bind( | 327 base::Callback<void(bool)> can_download_callback = base::Bind( |
| 341 &DownloadRequestLimiter::OnCanDownloadDecided, | 328 &DownloadRequestLimiter::OnCanDownloadDecided, |
| 342 factory_.GetWeakPtr(), | 329 factory_.GetWeakPtr(), |
| 343 render_process_host_id, | 330 render_process_host_id, |
| 344 render_view_id, | 331 render_view_id, |
| 345 request_method, | 332 request_method, |
| 346 callback); | 333 callback); |
| 347 | 334 |
| 348 originating_contents->GetDelegate()->CanDownload( | 335 originating_contents->GetDelegate()->CanDownload( |
| 349 url, | 336 url, |
| 350 request_method, | 337 request_method, |
| 351 can_download_callback); | 338 can_download_callback); |
| 352 } | 339 } |
| 353 | 340 |
| 354 void DownloadRequestLimiter::OnCanDownloadDecided( | 341 void DownloadRequestLimiter::OnCanDownloadDecided( |
| 355 int render_process_host_id, | 342 int render_process_host_id, |
| 356 int render_view_id, | 343 int render_view_id, |
| 357 const std::string& request_method, | 344 const std::string& request_method, |
| 358 const Callback& orig_callback, bool allow) { | 345 const Callback& orig_callback, bool allow) { |
| 359 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 346 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 360 content::WebContents* originating_contents = | 347 content::WebContents* originating_contents = |
| 361 tab_util::GetWebContentsByID(render_process_host_id, render_view_id); | 348 tab_util::GetWebContentsByID(render_process_host_id, render_view_id); |
| 362 if (!originating_contents || !allow) { | 349 if (!originating_contents || !allow) { |
| 363 ScheduleNotification(orig_callback, false); | 350 orig_callback.Run(false); |
| 364 return; | 351 return; |
| 365 } | 352 } |
| 366 | 353 |
| 367 CanDownloadImpl(originating_contents, | 354 CanDownloadImpl(originating_contents, |
| 368 request_method, | 355 request_method, |
| 369 orig_callback); | 356 orig_callback); |
| 370 } | 357 } |
| 371 | 358 |
| 372 HostContentSettingsMap* DownloadRequestLimiter::GetContentSettings( | 359 HostContentSettingsMap* DownloadRequestLimiter::GetContentSettings( |
| 373 content::WebContents* contents) { | 360 content::WebContents* contents) { |
| 374 return content_settings_ ? content_settings_ : Profile::FromBrowserContext( | 361 return content_settings_ ? content_settings_ : Profile::FromBrowserContext( |
| 375 contents->GetBrowserContext())->GetHostContentSettingsMap(); | 362 contents->GetBrowserContext())->GetHostContentSettingsMap(); |
| 376 } | 363 } |
| 377 | 364 |
| 378 void DownloadRequestLimiter::CanDownloadImpl( | 365 void DownloadRequestLimiter::CanDownloadImpl( |
| 379 content::WebContents* originating_contents, | 366 content::WebContents* originating_contents, |
| 380 const std::string& request_method, | 367 const std::string& request_method, |
| 381 const Callback& callback) { | 368 const Callback& callback) { |
| 382 DCHECK(originating_contents); | 369 DCHECK(originating_contents); |
| 383 | 370 |
| 384 TabDownloadState* state = GetDownloadState( | 371 TabDownloadState* state = GetDownloadState( |
| 385 originating_contents, originating_contents, true); | 372 originating_contents, originating_contents, true); |
| 386 switch (state->download_status()) { | 373 switch (state->download_status()) { |
| 387 case ALLOW_ALL_DOWNLOADS: | 374 case ALLOW_ALL_DOWNLOADS: |
| 388 if (state->download_count() && !(state->download_count() % | 375 if (state->download_count() && !(state->download_count() % |
| 389 DownloadRequestLimiter::kMaxDownloadsAtOnce)) | 376 DownloadRequestLimiter::kMaxDownloadsAtOnce)) |
| 390 state->set_download_status(PROMPT_BEFORE_DOWNLOAD); | 377 state->set_download_status(PROMPT_BEFORE_DOWNLOAD); |
| 391 ScheduleNotification(callback, true); | 378 callback.Run(true); |
| 392 state->increment_download_count(); | 379 state->increment_download_count(); |
| 393 break; | 380 break; |
| 394 | 381 |
| 395 case ALLOW_ONE_DOWNLOAD: | 382 case ALLOW_ONE_DOWNLOAD: |
| 396 state->set_download_status(PROMPT_BEFORE_DOWNLOAD); | 383 state->set_download_status(PROMPT_BEFORE_DOWNLOAD); |
| 397 ScheduleNotification(callback, true); | 384 callback.Run(true); |
| 398 state->increment_download_count(); | 385 state->increment_download_count(); |
| 399 break; | 386 break; |
| 400 | 387 |
| 401 case DOWNLOADS_NOT_ALLOWED: | 388 case DOWNLOADS_NOT_ALLOWED: |
| 402 ScheduleNotification(callback, false); | 389 callback.Run(false); |
| 403 break; | 390 break; |
| 404 | 391 |
| 405 case PROMPT_BEFORE_DOWNLOAD: { | 392 case PROMPT_BEFORE_DOWNLOAD: { |
| 406 HostContentSettingsMap* content_settings = GetContentSettings( | 393 HostContentSettingsMap* content_settings = GetContentSettings( |
| 407 originating_contents); | 394 originating_contents); |
| 408 ContentSetting setting = CONTENT_SETTING_ASK; | 395 ContentSetting setting = CONTENT_SETTING_ASK; |
| 409 if (content_settings) | 396 if (content_settings) |
| 410 setting = content_settings->GetContentSetting( | 397 setting = content_settings->GetContentSetting( |
| 411 originating_contents->GetURL(), | 398 originating_contents->GetURL(), |
| 412 originating_contents->GetURL(), | 399 originating_contents->GetURL(), |
| 413 CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, | 400 CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, |
| 414 std::string()); | 401 std::string()); |
| 415 switch (setting) { | 402 switch (setting) { |
| 416 case CONTENT_SETTING_ALLOW: { | 403 case CONTENT_SETTING_ALLOW: { |
| 417 TabSpecificContentSettings* settings = | 404 TabSpecificContentSettings* settings = |
| 418 TabSpecificContentSettings::FromWebContents( | 405 TabSpecificContentSettings::FromWebContents( |
| 419 originating_contents); | 406 originating_contents); |
| 420 if (settings) | 407 if (settings) |
| 421 settings->SetDownloadsBlocked(false); | 408 settings->SetDownloadsBlocked(false); |
| 422 ScheduleNotification(callback, true); | 409 callback.Run(true); |
| 423 state->increment_download_count(); | 410 state->increment_download_count(); |
| 424 return; | 411 return; |
| 425 } | 412 } |
| 426 case CONTENT_SETTING_BLOCK: { | 413 case CONTENT_SETTING_BLOCK: { |
| 427 TabSpecificContentSettings* settings = | 414 TabSpecificContentSettings* settings = |
| 428 TabSpecificContentSettings::FromWebContents( | 415 TabSpecificContentSettings::FromWebContents( |
| 429 originating_contents); | 416 originating_contents); |
| 430 if (settings) | 417 if (settings) |
| 431 settings->SetDownloadsBlocked(true); | 418 settings->SetDownloadsBlocked(true); |
| 432 ScheduleNotification(callback, false); | 419 callback.Run(false); |
| 433 return; | 420 return; |
| 434 } | 421 } |
| 435 case CONTENT_SETTING_DEFAULT: | 422 case CONTENT_SETTING_DEFAULT: |
| 436 case CONTENT_SETTING_ASK: | 423 case CONTENT_SETTING_ASK: |
| 437 case CONTENT_SETTING_SESSION_ONLY: | 424 case CONTENT_SETTING_SESSION_ONLY: |
| 438 state->PromptUserForDownload(callback); | 425 state->PromptUserForDownload(callback); |
| 439 state->increment_download_count(); | 426 state->increment_download_count(); |
| 440 break; | 427 break; |
| 441 case CONTENT_SETTING_NUM_SETTINGS: | 428 case CONTENT_SETTING_NUM_SETTINGS: |
| 442 default: | 429 default: |
| 443 NOTREACHED(); | 430 NOTREACHED(); |
| 444 return; | 431 return; |
| 445 } | 432 } |
| 446 break; | 433 break; |
| 447 } | 434 } |
| 448 | 435 |
| 449 default: | 436 default: |
| 450 NOTREACHED(); | 437 NOTREACHED(); |
| 451 } | 438 } |
| 452 } | 439 } |
| 453 | 440 |
| 454 void DownloadRequestLimiter::ScheduleNotification(const Callback& callback, | |
| 455 bool allow) { | |
| 456 BrowserThread::PostTask( | |
| 457 BrowserThread::IO, FROM_HERE, base::Bind(callback, allow)); | |
| 458 } | |
| 459 | |
| 460 void DownloadRequestLimiter::Remove(TabDownloadState* state, | 441 void DownloadRequestLimiter::Remove(TabDownloadState* state, |
| 461 content::WebContents* contents) { | 442 content::WebContents* contents) { |
| 462 DCHECK(ContainsKey(state_map_, contents)); | 443 DCHECK(ContainsKey(state_map_, contents)); |
| 463 state_map_.erase(contents); | 444 state_map_.erase(contents); |
| 464 delete state; | 445 delete state; |
| 465 } | 446 } |
| OLD | NEW |