Chromium Code Reviews| Index: chrome/browser/download/download_request_limiter.cc |
| diff --git a/chrome/browser/download/download_request_limiter.cc b/chrome/browser/download/download_request_limiter.cc |
| index 00e471659f68a97fa98006c9ad3d006fdc7cc282..44c0f422fc5114aa8015199f611356057d32cc63 100644 |
| --- a/chrome/browser/download/download_request_limiter.cc |
| +++ b/chrome/browser/download/download_request_limiter.cc |
| @@ -8,18 +8,17 @@ |
| #include "base/stl_util.h" |
| #include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/content_settings/host_content_settings_map_factory.h" |
| -#include "chrome/browser/content_settings/tab_specific_content_settings.h" |
| #include "chrome/browser/infobars/infobar_service.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/tab_contents/tab_util.h" |
| +#include "components/content_settings/core/browser/content_settings_details.h" |
| #include "components/content_settings/core/browser/host_content_settings_map.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/navigation_controller.h" |
| #include "content/public/browser/navigation_entry.h" |
| #include "content/public/browser/navigation_handle.h" |
| -#include "content/public/browser/notification_source.h" |
| -#include "content/public/browser/notification_types.h" |
| +#include "content/public/browser/notification_service.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/browser/resource_dispatcher_host.h" |
| #include "content/public/browser/web_contents.h" |
| @@ -37,6 +36,44 @@ using content::BrowserThread; |
| using content::NavigationController; |
| using content::NavigationEntry; |
| +namespace { |
| + |
| +ContentSetting GetSettingFromStatus( |
| + DownloadRequestLimiter::DownloadStatus status) { |
| + switch (status) { |
| + case DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD: |
| + case DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD: |
| + return CONTENT_SETTING_ASK; |
| + case DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS: |
| + return CONTENT_SETTING_ALLOW; |
| + case DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED: |
| + return CONTENT_SETTING_BLOCK; |
| + default: |
|
Bernhard Bauer
2017/02/16 13:08:14
Actually, the default isn't necessary if you have
alshabalin
2017/02/17 09:21:10
Good point, thank you. Done. However, I'm surprise
Bernhard Bauer
2017/02/17 10:51:22
Haha :-D Turns out, the dirty secret is that the c
|
| + NOTREACHED(); |
| + return CONTENT_SETTING_DEFAULT; |
| + } |
| +} |
| + |
| +DownloadRequestLimiter::DownloadStatus GetStatusFromSetting( |
| + ContentSetting setting) { |
| + switch (setting) { |
| + case CONTENT_SETTING_ALLOW: |
| + return DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS; |
| + case CONTENT_SETTING_BLOCK: |
| + return DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED; |
| + case CONTENT_SETTING_DEFAULT: |
| + case CONTENT_SETTING_ASK: |
| + return DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD; |
| + case CONTENT_SETTING_SESSION_ONLY: |
| + case CONTENT_SETTING_NUM_SETTINGS: |
| + case CONTENT_SETTING_DETECT_IMPORTANT_CONTENT: |
| + NOTREACHED(); |
| + return DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD; |
| + } |
| +} |
| + |
| +} // namespace |
| + |
| // TabDownloadState ------------------------------------------------------------ |
| DownloadRequestLimiter::TabDownloadState::TabDownloadState( |
| @@ -48,9 +85,9 @@ DownloadRequestLimiter::TabDownloadState::TabDownloadState( |
| host_(host), |
| status_(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD), |
| download_count_(0), |
| + observer_(this), |
| factory_(this) { |
| - registrar_.Add(this, chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, |
| - content::Source<content::WebContents>(contents)); |
| + observer_.Add(GetContentSettings(contents)); |
| NavigationEntry* last_entry = |
| originating_web_contents |
| ? originating_web_contents->GetController().GetLastCommittedEntry() |
| @@ -67,6 +104,11 @@ DownloadRequestLimiter::TabDownloadState::~TabDownloadState() { |
| DCHECK(!factory_.HasWeakPtrs()); |
| } |
| +void DownloadRequestLimiter::TabDownloadState::SetDownloadStatusAndNotify( |
| + DownloadStatus status) { |
| + SetDownloadStatusAndNotifyImpl(status, GetSettingFromStatus(status)); |
| +} |
| + |
| void DownloadRequestLimiter::TabDownloadState::DidStartNavigation( |
| content::NavigationHandle* navigation_handle) { |
| if (!navigation_handle->IsInMainFrame()) |
| @@ -194,16 +236,22 @@ void DownloadRequestLimiter::TabDownloadState::SetContentSetting( |
| void DownloadRequestLimiter::TabDownloadState::Cancel() { |
| SetContentSetting(CONTENT_SETTING_BLOCK); |
| - NotifyCallbacks(false); |
| + bool throttled = NotifyCallbacks(false); |
| + SetDownloadStatusAndNotify(throttled ? PROMPT_BEFORE_DOWNLOAD |
| + : DOWNLOADS_NOT_ALLOWED); |
| } |
| void DownloadRequestLimiter::TabDownloadState::CancelOnce() { |
| - NotifyCallbacks(false); |
| + bool throttled = NotifyCallbacks(false); |
| + SetDownloadStatusAndNotify(throttled ? PROMPT_BEFORE_DOWNLOAD |
| + : DOWNLOADS_NOT_ALLOWED); |
| } |
| void DownloadRequestLimiter::TabDownloadState::Accept() { |
| SetContentSetting(CONTENT_SETTING_ALLOW); |
| - NotifyCallbacks(true); |
| + bool throttled = NotifyCallbacks(true); |
| + SetDownloadStatusAndNotify(throttled ? PROMPT_BEFORE_DOWNLOAD |
| + : ALLOW_ALL_DOWNLOADS); |
| } |
| DownloadRequestLimiter::TabDownloadState::TabDownloadState() |
| @@ -211,17 +259,34 @@ DownloadRequestLimiter::TabDownloadState::TabDownloadState() |
| host_(NULL), |
| status_(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD), |
| download_count_(0), |
| + observer_(this), |
| factory_(this) {} |
| bool DownloadRequestLimiter::TabDownloadState::is_showing_prompt() const { |
| return factory_.HasWeakPtrs(); |
| } |
| -void DownloadRequestLimiter::TabDownloadState::Observe( |
| - int type, |
| - const content::NotificationSource& source, |
| - const content::NotificationDetails& details) { |
| - DCHECK_EQ(chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, type); |
| +void DownloadRequestLimiter::TabDownloadState::OnContentSettingChanged( |
| + const ContentSettingsPattern& primary_pattern, |
| + const ContentSettingsPattern& secondary_pattern, |
| + ContentSettingsType content_type, |
| + std::string resource_identifier) { |
| + if (content_type != CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS) |
| + return; |
| + |
| + // Analogous to TabSpecificContentSettings::OnContentSettingChanged: |
| + const ContentSettingsDetails details(primary_pattern, secondary_pattern, |
| + content_type, resource_identifier); |
| + const NavigationController& controller = web_contents()->GetController(); |
| + |
| + // The visible NavigationEntry is the URL in the URL field of a tab. |
| + // Currently this should be matched by the |primary_pattern|. |
| + NavigationEntry* entry = controller.GetVisibleEntry(); |
| + GURL entry_url; |
| + if (entry) |
| + entry_url = entry->GetURL(); |
| + if (!details.update_all() && !details.primary_pattern().Matches(entry_url)) |
| + return; |
| // Content settings have been updated for our web contents, e.g. via the OIB |
| // or the settings page. Check to see if the automatic downloads setting is |
| @@ -231,45 +296,24 @@ void DownloadRequestLimiter::TabDownloadState::Observe( |
| // |
| // NotifyCallbacks is not called as this notification should be triggered when |
| // a download is not pending. |
| - content::WebContents* contents = |
| - content::Source<content::WebContents>(source).ptr(); |
| - DCHECK_EQ(contents, web_contents()); |
| - |
| + // |
| // Fetch the content settings map for this web contents, and extract the |
| // automatic downloads permission value. |
| - HostContentSettingsMap* content_settings = GetContentSettings(contents); |
| + HostContentSettingsMap* content_settings = GetContentSettings(web_contents()); |
| if (!content_settings) |
| return; |
| ContentSetting setting = content_settings->GetContentSetting( |
| - contents->GetURL(), contents->GetURL(), |
| + web_contents()->GetURL(), web_contents()->GetURL(), |
| CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, std::string()); |
| // Update the internal state to match if necessary. |
| - switch (setting) { |
| - case CONTENT_SETTING_ALLOW: |
| - set_download_status(ALLOW_ALL_DOWNLOADS); |
| - break; |
| - case CONTENT_SETTING_BLOCK: |
| - set_download_status(DOWNLOADS_NOT_ALLOWED); |
| - break; |
| - case CONTENT_SETTING_ASK: |
| - case CONTENT_SETTING_DEFAULT: |
| - case CONTENT_SETTING_SESSION_ONLY: |
| - set_download_status(PROMPT_BEFORE_DOWNLOAD); |
| - break; |
| - case CONTENT_SETTING_NUM_SETTINGS: |
| - case CONTENT_SETTING_DETECT_IMPORTANT_CONTENT: |
| - NOTREACHED(); |
| - return; |
| - } |
| + SetDownloadStatusAndNotifyImpl(GetStatusFromSetting(setting), setting); |
| } |
| -void DownloadRequestLimiter::TabDownloadState::NotifyCallbacks(bool allow) { |
| - set_download_status(allow ? DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS |
| - : DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED); |
| +bool DownloadRequestLimiter::TabDownloadState::NotifyCallbacks(bool allow) { |
| std::vector<DownloadRequestLimiter::Callback> callbacks; |
| - bool change_status = false; |
| + bool throttled = false; |
| // Selectively send first few notifications only if number of downloads exceed |
| // kMaxDownloadsAtOnce. In that case, we also retain the infobar instance and |
| @@ -285,7 +329,7 @@ void DownloadRequestLimiter::TabDownloadState::NotifyCallbacks(bool allow) { |
| end = callbacks_.begin() + kMaxDownloadsAtOnce; |
| callbacks.assign(start, end); |
| callbacks_.erase(start, end); |
| - change_status = true; |
| + throttled = true; |
| } |
| for (const auto& callback : callbacks) { |
| @@ -294,8 +338,22 @@ void DownloadRequestLimiter::TabDownloadState::NotifyCallbacks(bool allow) { |
| base::Bind(callback, allow)); |
| } |
| - if (change_status) |
| - set_download_status(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD); |
| + return throttled; |
| +} |
| + |
| +void DownloadRequestLimiter::TabDownloadState::SetDownloadStatusAndNotifyImpl( |
| + DownloadStatus status, |
| + ContentSetting setting) { |
| + ContentSetting last_setting = GetSettingFromStatus(status_); |
| + status_ = status; |
| + if (!web_contents()) |
| + return; |
| + if (last_setting == setting) |
| + return; |
| + content::NotificationService::current()->Notify( |
| + chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, |
| + content::Source<content::WebContents>(web_contents()), |
| + content::NotificationService::NoDetails()); |
| } |
| // DownloadRequestLimiter ------------------------------------------------------ |
| @@ -406,13 +464,13 @@ void DownloadRequestLimiter::CanDownloadImpl( |
| if (state->download_count() && |
| !(state->download_count() % |
| DownloadRequestLimiter::kMaxDownloadsAtOnce)) |
| - state->set_download_status(PROMPT_BEFORE_DOWNLOAD); |
| + state->SetDownloadStatusAndNotify(PROMPT_BEFORE_DOWNLOAD); |
| callback.Run(true); |
| state->increment_download_count(); |
| break; |
| case ALLOW_ONE_DOWNLOAD: |
| - state->set_download_status(PROMPT_BEFORE_DOWNLOAD); |
| + state->SetDownloadStatusAndNotify(PROMPT_BEFORE_DOWNLOAD); |
| callback.Run(true); |
| state->increment_download_count(); |
| break; |
| @@ -431,28 +489,22 @@ void DownloadRequestLimiter::CanDownloadImpl( |
| CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, std::string()); |
| switch (setting) { |
| case CONTENT_SETTING_ALLOW: { |
| - TabSpecificContentSettings* settings = |
| - TabSpecificContentSettings::FromWebContents(originating_contents); |
| - if (settings) |
| - settings->SetDownloadsBlocked(false); |
| + state->SetDownloadStatusAndNotify(ALLOW_ALL_DOWNLOADS); |
| callback.Run(true); |
| state->increment_download_count(); |
| return; |
| } |
| case CONTENT_SETTING_BLOCK: { |
| - TabSpecificContentSettings* settings = |
| - TabSpecificContentSettings::FromWebContents(originating_contents); |
| - if (settings) |
| - settings->SetDownloadsBlocked(true); |
| + state->SetDownloadStatusAndNotify(DOWNLOADS_NOT_ALLOWED); |
| callback.Run(false); |
| return; |
| } |
| case CONTENT_SETTING_DEFAULT: |
| case CONTENT_SETTING_ASK: |
| - case CONTENT_SETTING_SESSION_ONLY: |
| state->PromptUserForDownload(callback); |
| state->increment_download_count(); |
| break; |
| + case CONTENT_SETTING_SESSION_ONLY: |
| case CONTENT_SETTING_NUM_SETTINGS: |
| default: |
| NOTREACHED(); |