summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorinferno@chromium.org <inferno@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-29 22:33:15 +0000
committerinferno@chromium.org <inferno@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-29 22:33:15 +0000
commit02fd1ecdadfd2c0ffe0426188bafff7f1a942919 (patch)
treec7aa6f35ccd3b8a393940381d1dc193eb5e5e56c
parent1414de82ef8592ced38d6424e9e763877a90e25a (diff)
downloadchromium_src-02fd1ecdadfd2c0ffe0426188bafff7f1a942919.zip
chromium_src-02fd1ecdadfd2c0ffe0426188bafff7f1a942919.tar.gz
chromium_src-02fd1ecdadfd2c0ffe0426188bafff7f1a942919.tar.bz2
Patch the Browser GDI crash with excessive downloads by restricting maximum number of downloads allowed at one time. When this limit is reached, we re-prompt the user.
BUG=39277 TEST=None Review URL: http://codereview.chromium.org/1539002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@43006 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/download/download_request_infobar_delegate.cc4
-rw-r--r--chrome/browser/download/download_request_manager.cc38
-rw-r--r--chrome/browser/download/download_request_manager.h14
3 files changed, 47 insertions, 9 deletions
diff --git a/chrome/browser/download/download_request_infobar_delegate.cc b/chrome/browser/download/download_request_infobar_delegate.cc
index 3a6aa5d..88c83fc 100644
--- a/chrome/browser/download/download_request_infobar_delegate.cc
+++ b/chrome/browser/download/download_request_infobar_delegate.cc
@@ -51,9 +51,9 @@ std::wstring DownloadRequestInfoBarDelegate::GetButtonLabel(
bool DownloadRequestInfoBarDelegate::Accept() {
if (host_) {
host_->Accept();
- host_ = NULL;
}
- return true;
+ // Accept() call will nullify host_ if no furthur prompts are required.
+ return !host_;
}
bool DownloadRequestInfoBarDelegate::Cancel() {
diff --git a/chrome/browser/download/download_request_manager.cc b/chrome/browser/download/download_request_manager.cc
index 4498233..9e86736 100644
--- a/chrome/browser/download/download_request_manager.cc
+++ b/chrome/browser/download/download_request_manager.cc
@@ -135,18 +135,37 @@ void DownloadRequestManager::TabDownloadState::Observe(
}
void DownloadRequestManager::TabDownloadState::NotifyCallbacks(bool allow) {
- if (infobar_) {
- // Reset the delegate so we don't get notified again.
- infobar_->set_host(NULL);
- infobar_ = NULL;
- }
status_ = allow ?
DownloadRequestManager::ALLOW_ALL_DOWNLOADS :
DownloadRequestManager::DOWNLOADS_NOT_ALLOWED;
std::vector<DownloadRequestManager::Callback*> callbacks;
- callbacks.swap(callbacks_);
- for (size_t i = 0; i < callbacks.size(); ++i)
+ bool change_status = false;
+
+ // Selectively send first few notifications only if number of downloads exceed
+ // kMaxDownloadsAtOnce. In that case, we also retain the infobar instance and
+ // don't close it. If allow is false, we send all the notifications to cancel
+ // all remaining downloads and close the infobar.
+ if (!allow || (callbacks_.size() < kMaxDownloadsAtOnce)) {
+ if (infobar_) {
+ // Reset the delegate so we don't get notified again.
+ infobar_->set_host(NULL);
+ infobar_ = NULL;
+ }
+ callbacks.swap(callbacks_);
+ } else {
+ std::vector<DownloadRequestManager::Callback*>::iterator start, end;
+ start = callbacks_.begin();
+ end = callbacks_.begin() + kMaxDownloadsAtOnce;
+ callbacks.assign(start, end);
+ callbacks_.erase(start, end);
+ change_status = true;
+ }
+
+ for (size_t i = 0; i < callbacks.size(); ++i) {
host_->ScheduleNotification(callbacks[i], allow);
+ }
+ if (change_status)
+ status_ = DownloadRequestManager::PROMPT_BEFORE_DOWNLOAD;
}
// DownloadRequestManager ------------------------------------------------------
@@ -247,7 +266,11 @@ void DownloadRequestManager::CanDownloadImpl(
&effective_tab->controller(), &originating_tab->controller(), true);
switch (state->download_status()) {
case ALLOW_ALL_DOWNLOADS:
+ if (state->download_count() && !(state->download_count() %
+ DownloadRequestManager::kMaxDownloadsAtOnce))
+ state->set_download_status(PROMPT_BEFORE_DOWNLOAD);
ScheduleNotification(callback, true);
+ state->increment_download_count();
break;
case ALLOW_ONE_DOWNLOAD:
@@ -261,6 +284,7 @@ void DownloadRequestManager::CanDownloadImpl(
case PROMPT_BEFORE_DOWNLOAD:
state->PromptUserForDownload(effective_tab, callback);
+ state->increment_download_count();
break;
default:
diff --git a/chrome/browser/download/download_request_manager.h b/chrome/browser/download/download_request_manager.h
index cea0536..97fa7f8 100644
--- a/chrome/browser/download/download_request_manager.h
+++ b/chrome/browser/download/download_request_manager.h
@@ -51,6 +51,9 @@ class DownloadRequestManager
DOWNLOADS_NOT_ALLOWED
};
+ // Max number of downloads before a "Prompt Before Download" Dialog is shown.
+ static const size_t kMaxDownloadsAtOnce = 50;
+
// The callback from CanDownloadOnIOThread. This is invoked on the io thread.
class Callback {
public:
@@ -87,6 +90,14 @@ class DownloadRequestManager
return status_;
}
+ // Number of "ALLOWED" downloads.
+ void increment_download_count() {
+ download_count_++;
+ }
+ size_t download_count() const {
+ return download_count_;
+ }
+
// Invoked when a user gesture occurs (mouse click, enter or space). This
// may result in invoking Remove on DownloadRequestManager.
void OnUserGesture();
@@ -114,6 +125,7 @@ class DownloadRequestManager
: host_(NULL),
controller_(NULL),
status_(DownloadRequestManager::ALLOW_ONE_DOWNLOAD),
+ download_count_(0),
infobar_(NULL) {
}
@@ -136,6 +148,8 @@ class DownloadRequestManager
DownloadRequestManager::DownloadStatus status_;
+ size_t download_count_;
+
// Callbacks we need to notify. This is only non-empty if we're showing a
// dialog.
// See description above CanDownloadOnIOThread for details on lifetime of