From bfc2b4cbaa865df05976d73b989d321277b757aa Mon Sep 17 00:00:00 2001 From: "cmp@chromium.org" Date: Thu, 10 Nov 2011 01:46:50 +0000 Subject: Revert 109228 - ContentSettingsObserver (+ related classes) cleanup. This CL needs to be reverted before we revert 109213, which we speculate caused some performance regressions. Per-page content settings and default content settings are no longer needed, since the renderer stores the content setting rules for images and scripts. BUG=102662 TEST=NONE Review URL: http://codereview.chromium.org/8498007 TBR=marja@chromium.org Review URL: http://codereview.chromium.org/8497062 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@109360 0039d316-1c4b-4281-b951-d872f2087c98 --- .../content_settings_default_provider.cc | 33 +++-- .../content_settings_default_provider.h | 4 +- .../content_settings_pref_provider_unittest.cc | 9 ++ .../content_settings/host_content_settings_map.cc | 27 ++++ .../content_settings/host_content_settings_map.h | 13 ++ .../host_content_settings_map_unittest.cc | 145 ++++++++++++--------- .../content_settings/mock_settings_observer.cc | 3 +- .../tab_specific_content_settings.cc | 17 ++- .../tab_specific_content_settings.h | 1 + .../chrome_resource_dispatcher_host_delegate.cc | 10 ++ chrome/common/content_settings.cc | 10 ++ chrome/common/content_settings.h | 8 ++ chrome/common/render_messages.cc | 20 +++ chrome/common/render_messages.h | 27 ++++ chrome/renderer/chrome_content_renderer_client.cc | 2 + chrome/renderer/chrome_render_process_observer.cc | 45 +++++++ chrome/renderer/chrome_render_process_observer.h | 6 + chrome/renderer/content_settings_observer.cc | 73 ++++++++++- chrome/renderer/content_settings_observer.h | 28 ++++ .../content_settings_observer_browsertest.cc | 7 + 20 files changed, 404 insertions(+), 84 deletions(-) diff --git a/chrome/browser/content_settings/content_settings_default_provider.cc b/chrome/browser/content_settings/content_settings_default_provider.cc index d70a4d0..d1ff977 100644 --- a/chrome/browser/content_settings/content_settings_default_provider.cc +++ b/chrome/browser/content_settings/content_settings_default_provider.cc @@ -109,7 +109,7 @@ DefaultProvider::DefaultProvider(PrefService* prefs, bool incognito) // Read global defaults. ReadDefaultSettings(true); - if (default_content_settings_[CONTENT_SETTINGS_TYPE_COOKIES] == + if (default_content_settings_.settings[CONTENT_SETTINGS_TYPE_COOKIES] == CONTENT_SETTING_BLOCK) { UserMetrics::RecordAction( UserMetricsAction("CookieBlockingEnabledPerDefault")); @@ -161,12 +161,12 @@ void DefaultProvider::SetContentSetting( base::AutoLock lock(lock_); if (setting == CONTENT_SETTING_DEFAULT || setting == kDefaultSettings[content_type]) { - default_content_settings_[content_type] = + default_content_settings_.settings[content_type] = kDefaultSettings[content_type]; default_settings_dictionary->RemoveWithoutPathExpansion(dictionary_path, NULL); } else { - default_content_settings_[content_type] = setting; + default_content_settings_.settings[content_type] = setting; default_settings_dictionary->SetWithoutPathExpansion( dictionary_path, Value::CreateIntegerValue(setting)); } @@ -194,7 +194,7 @@ RuleIterator* DefaultProvider::GetRuleIterator( base::AutoLock lock(lock_); if (resource_identifier.empty()) { return new DefaultRuleIterator( - default_content_settings_[content_type]); + default_content_settings_.settings[content_type]); } else { return new EmptyRuleIterator(); } @@ -254,29 +254,27 @@ void DefaultProvider::ReadDefaultSettings(bool overwrite) { const DictionaryValue* default_settings_dictionary = prefs_->GetDictionary(prefs::kDefaultContentSettings); - if (overwrite) { - for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) - default_content_settings_[i] = CONTENT_SETTING_DEFAULT; - } + if (overwrite) + default_content_settings_ = ContentSettings(); // Careful: The returned value could be NULL if the pref has never been set. if (default_settings_dictionary) { GetSettingsFromDictionary(default_settings_dictionary, - default_content_settings_); + &default_content_settings_); } ForceDefaultsToBeExplicit(); } void DefaultProvider::ForceDefaultsToBeExplicit() { for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) { - if (default_content_settings_[i] == CONTENT_SETTING_DEFAULT) - default_content_settings_[i] = kDefaultSettings[i]; + if (default_content_settings_.settings[i] == CONTENT_SETTING_DEFAULT) + default_content_settings_.settings[i] = kDefaultSettings[i]; } } void DefaultProvider::GetSettingsFromDictionary( const DictionaryValue* dictionary, - ContentSetting* settings) { + ContentSettings* settings) { for (DictionaryValue::key_iterator i(dictionary->begin_keys()); i != dictionary->end_keys(); ++i) { const std::string& content_type(*i); @@ -286,18 +284,19 @@ void DefaultProvider::GetSettingsFromDictionary( bool found = dictionary->GetIntegerWithoutPathExpansion(content_type, &setting); DCHECK(found); - settings[type] = IntToContentSetting(setting); + settings->settings[type] = IntToContentSetting(setting); break; } } } // Migrate obsolete cookie prompt mode/ - if (settings[CONTENT_SETTINGS_TYPE_COOKIES] == CONTENT_SETTING_ASK) - settings[CONTENT_SETTINGS_TYPE_COOKIES] = CONTENT_SETTING_BLOCK; + if (settings->settings[CONTENT_SETTINGS_TYPE_COOKIES] == + CONTENT_SETTING_ASK) + settings->settings[CONTENT_SETTINGS_TYPE_COOKIES] = CONTENT_SETTING_BLOCK; - settings[CONTENT_SETTINGS_TYPE_PLUGINS] = + settings->settings[CONTENT_SETTINGS_TYPE_PLUGINS] = ClickToPlayFixup(CONTENT_SETTINGS_TYPE_PLUGINS, - settings[CONTENT_SETTINGS_TYPE_PLUGINS]); + settings->settings[CONTENT_SETTINGS_TYPE_PLUGINS]); } void DefaultProvider::MigrateObsoleteNotificationPref() { diff --git a/chrome/browser/content_settings/content_settings_default_provider.h b/chrome/browser/content_settings/content_settings_default_provider.h index f9ddaff..f4a9c34 100644 --- a/chrome/browser/content_settings/content_settings_default_provider.h +++ b/chrome/browser/content_settings/content_settings_default_provider.h @@ -57,7 +57,7 @@ class DefaultProvider : public ObservableProvider, private: // Sets the fields of |settings| based on the values in |dictionary|. void GetSettingsFromDictionary(const base::DictionaryValue* dictionary, - ContentSetting* settings); + ContentSettings* settings); // Forces the default settings to be explicitly set instead of themselves // being CONTENT_SETTING_DEFAULT. @@ -71,7 +71,7 @@ class DefaultProvider : public ObservableProvider, void MigrateObsoleteGeolocationPref(); // Copies of the pref data, so that we can read it on the IO thread. - ContentSetting default_content_settings_[CONTENT_SETTINGS_NUM_TYPES]; + ContentSettings default_content_settings_; PrefService* prefs_; diff --git a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc index edefe97..50e56ff 100644 --- a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc +++ b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc @@ -53,6 +53,15 @@ void ExpectObsoleteGeolocationSetting( namespace content_settings { +bool SettingsEqual(const ContentSettings& settings1, + const ContentSettings& settings2) { + for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) { + if (settings1.settings[i] != settings2.settings[i]) + return false; + } + return true; +} + class DeadlockCheckerThread : public base::PlatformThread::Delegate { public: explicit DeadlockCheckerThread(PrefProvider* provider) diff --git a/chrome/browser/content_settings/host_content_settings_map.cc b/chrome/browser/content_settings/host_content_settings_map.cc index 2c09ad2..b0baa04 100644 --- a/chrome/browser/content_settings/host_content_settings_map.cc +++ b/chrome/browser/content_settings/host_content_settings_map.cc @@ -163,6 +163,16 @@ ContentSetting HostContentSettingsMap::GetDefaultContentSetting( return CONTENT_SETTING_DEFAULT; } +ContentSettings HostContentSettingsMap::GetDefaultContentSettings() const { + ContentSettings output(CONTENT_SETTING_DEFAULT); + for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) { + if (!ContentTypeHasCompoundValue(ContentSettingsType(i))) + output.settings[i] = GetDefaultContentSetting(ContentSettingsType(i), + NULL); + } + return output; +} + ContentSetting HostContentSettingsMap::GetContentSetting( const GURL& primary_url, const GURL& secondary_url, @@ -173,6 +183,23 @@ ContentSetting HostContentSettingsMap::GetContentSetting( return content_settings::ValueToContentSetting(value.get()); } +ContentSettings HostContentSettingsMap::GetContentSettings( + const GURL& primary_url) const { + ContentSettings output; + // If we require a resource identifier, set the content settings to default, + // otherwise make the defaults explicit. Values for content type + // CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE can't be mapped to the type + // |ContentSetting|. So we ignore them here. + for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) { + ContentSettingsType type = ContentSettingsType(j); + if (!ContentTypeHasCompoundValue(type)) { + output.settings[j] = GetContentSetting( + primary_url, primary_url, ContentSettingsType(j), std::string()); + } + } + return output; +} + void HostContentSettingsMap::GetSettingsForOneType( ContentSettingsType content_type, const std::string& resource_identifier, diff --git a/chrome/browser/content_settings/host_content_settings_map.h b/chrome/browser/content_settings/host_content_settings_map.h index a6f8700..7c91008 100644 --- a/chrome/browser/content_settings/host_content_settings_map.h +++ b/chrome/browser/content_settings/host_content_settings_map.h @@ -60,6 +60,11 @@ class HostContentSettingsMap ContentSetting GetDefaultContentSetting(ContentSettingsType content_type, std::string* provider_id) const; + // Returns the default settings for all content types. + // + // This may be called on any thread. + ContentSettings GetDefaultContentSettings() const; + // Returns a single |ContentSetting| which applies to the given URLs. Note // that certain internal schemes are whitelisted. For |CONTENT_TYPE_COOKIES|, // |CookieSettings| should be used instead. For content types that can't be @@ -93,6 +98,14 @@ class HostContentSettingsMap const std::string& resource_identifier, content_settings::SettingInfo* info) const; + // Returns all ContentSettings which apply to the given |primary_url|. For + // content setting types that require an additional resource identifier, the + // default content setting is returned. + // + // This may be called on any thread. + ContentSettings GetContentSettings( + const GURL& primary_url) const; + // For a given content type, returns all patterns with a non-default setting, // mapped to their actual settings, in the precedence order of the rules. // |settings| must be a non-NULL outparam. diff --git a/chrome/browser/content_settings/host_content_settings_map_unittest.cc b/chrome/browser/content_settings/host_content_settings_map_unittest.cc index 44fd8db..0965bc3 100644 --- a/chrome/browser/content_settings/host_content_settings_map_unittest.cc +++ b/chrome/browser/content_settings/host_content_settings_map_unittest.cc @@ -26,6 +26,23 @@ using content::BrowserThread; using ::testing::_; +namespace { + +bool SettingsEqual(const ContentSettings& settings1, + const ContentSettings& settings2) { + for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) { + if (settings1.settings[i] != settings2.settings[i]) { + LOG(ERROR) << "type: " << i + << " [expected: " << settings1.settings[i] + << " actual: " << settings2.settings[i] << "]"; + return false; + } + } + return true; +} + +} // namespace + class HostContentSettingsMapTest : public testing::Test { public: HostContentSettingsMapTest() : ui_thread_(BrowserThread::UI, &message_loop_) { @@ -109,51 +126,48 @@ TEST_F(HostContentSettingsMapTest, IndividualSettings) { host, host, CONTENT_SETTINGS_TYPE_PLUGINS, "")); // Check returning all settings for a host. + ContentSettings desired_settings; + desired_settings.settings[CONTENT_SETTINGS_TYPE_COOKIES] = + CONTENT_SETTING_ALLOW; host_content_settings_map->SetContentSetting( pattern, ContentSettingsPattern::Wildcard(), CONTENT_SETTINGS_TYPE_IMAGES, std::string(), CONTENT_SETTING_DEFAULT); - EXPECT_EQ(CONTENT_SETTING_ALLOW, - host_content_settings_map->GetContentSetting( - host, host, CONTENT_SETTINGS_TYPE_IMAGES, "")); + desired_settings.settings[CONTENT_SETTINGS_TYPE_IMAGES] = + CONTENT_SETTING_ALLOW; host_content_settings_map->SetContentSetting( pattern, ContentSettingsPattern::Wildcard(), CONTENT_SETTINGS_TYPE_JAVASCRIPT, std::string(), CONTENT_SETTING_BLOCK); - EXPECT_EQ(CONTENT_SETTING_BLOCK, - host_content_settings_map->GetContentSetting( - host, host, CONTENT_SETTINGS_TYPE_JAVASCRIPT, "")); + desired_settings.settings[CONTENT_SETTINGS_TYPE_JAVASCRIPT] = + CONTENT_SETTING_BLOCK; host_content_settings_map->SetContentSetting( pattern, ContentSettingsPattern::Wildcard(), CONTENT_SETTINGS_TYPE_PLUGINS, std::string(), CONTENT_SETTING_ALLOW); - EXPECT_EQ(CONTENT_SETTING_ALLOW, - host_content_settings_map->GetContentSetting( - host, host, CONTENT_SETTINGS_TYPE_PLUGINS, "")); - EXPECT_EQ(CONTENT_SETTING_BLOCK, - host_content_settings_map->GetContentSetting( - host, host, CONTENT_SETTINGS_TYPE_POPUPS, "")); - EXPECT_EQ(CONTENT_SETTING_ASK, - host_content_settings_map->GetContentSetting( - host, host, CONTENT_SETTINGS_TYPE_GEOLOCATION, "")); - EXPECT_EQ(CONTENT_SETTING_ASK, - host_content_settings_map->GetContentSetting( - host, host, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, "")); - EXPECT_EQ(CONTENT_SETTING_ASK, - host_content_settings_map->GetContentSetting( - host, host, CONTENT_SETTINGS_TYPE_INTENTS, "")); - EXPECT_EQ(CONTENT_SETTING_ASK, - host_content_settings_map->GetContentSetting( - host, host, CONTENT_SETTINGS_TYPE_FULLSCREEN, "")); - EXPECT_EQ(CONTENT_SETTING_ASK, - host_content_settings_map->GetContentSetting( - host, host, CONTENT_SETTINGS_TYPE_MOUSELOCK, "")); + desired_settings.settings[CONTENT_SETTINGS_TYPE_PLUGINS] = + CONTENT_SETTING_ALLOW; + desired_settings.settings[CONTENT_SETTINGS_TYPE_POPUPS] = + CONTENT_SETTING_BLOCK; + desired_settings.settings[CONTENT_SETTINGS_TYPE_GEOLOCATION] = + CONTENT_SETTING_ASK; + desired_settings.settings[CONTENT_SETTINGS_TYPE_NOTIFICATIONS] = + CONTENT_SETTING_ASK; + desired_settings.settings[CONTENT_SETTINGS_TYPE_INTENTS] = + CONTENT_SETTING_ASK; + desired_settings.settings[CONTENT_SETTINGS_TYPE_FULLSCREEN] = + CONTENT_SETTING_ASK; + desired_settings.settings[CONTENT_SETTINGS_TYPE_MOUSELOCK] = + CONTENT_SETTING_ASK; + ContentSettings settings = + host_content_settings_map->GetContentSettings(host); + EXPECT_TRUE(SettingsEqual(desired_settings, settings)); // Check returning all hosts for a setting. ContentSettingsPattern pattern2 = @@ -589,36 +603,48 @@ TEST_F(HostContentSettingsMapTest, NestedSettings) { host_content_settings_map->SetDefaultContentSetting( CONTENT_SETTINGS_TYPE_JAVASCRIPT, CONTENT_SETTING_BLOCK); - EXPECT_EQ(CONTENT_SETTING_BLOCK, - host_content_settings_map->GetContentSetting( - host, host, CONTENT_SETTINGS_TYPE_COOKIES, "")); - EXPECT_EQ(CONTENT_SETTING_BLOCK, - host_content_settings_map->GetContentSetting( - host, host, CONTENT_SETTINGS_TYPE_IMAGES, "")); - EXPECT_EQ(CONTENT_SETTING_BLOCK, - host_content_settings_map->GetContentSetting( - host, host, CONTENT_SETTINGS_TYPE_JAVASCRIPT, "")); - EXPECT_EQ(CONTENT_SETTING_BLOCK, - host_content_settings_map->GetContentSetting( - host, host, CONTENT_SETTINGS_TYPE_PLUGINS, "")); - EXPECT_EQ(CONTENT_SETTING_BLOCK, - host_content_settings_map->GetContentSetting( - host, host, CONTENT_SETTINGS_TYPE_POPUPS, "")); - EXPECT_EQ(CONTENT_SETTING_ASK, - host_content_settings_map->GetContentSetting( - host, host, CONTENT_SETTINGS_TYPE_GEOLOCATION, "")); - EXPECT_EQ(CONTENT_SETTING_ASK, - host_content_settings_map->GetContentSetting( - host, host, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, "")); - EXPECT_EQ(CONTENT_SETTING_ASK, - host_content_settings_map->GetContentSetting( - host, host, CONTENT_SETTINGS_TYPE_INTENTS, "")); - EXPECT_EQ(CONTENT_SETTING_ASK, - host_content_settings_map->GetContentSetting( - host, host, CONTENT_SETTINGS_TYPE_FULLSCREEN, "")); - EXPECT_EQ(CONTENT_SETTING_ASK, - host_content_settings_map->GetContentSetting( - host, host, CONTENT_SETTINGS_TYPE_MOUSELOCK, "")); + ContentSettings desired_settings; + desired_settings.settings[CONTENT_SETTINGS_TYPE_COOKIES] = + CONTENT_SETTING_BLOCK; + desired_settings.settings[CONTENT_SETTINGS_TYPE_IMAGES] = + CONTENT_SETTING_BLOCK; + desired_settings.settings[CONTENT_SETTINGS_TYPE_JAVASCRIPT] = + CONTENT_SETTING_BLOCK; + desired_settings.settings[CONTENT_SETTINGS_TYPE_PLUGINS] = + CONTENT_SETTING_BLOCK; + desired_settings.settings[CONTENT_SETTINGS_TYPE_POPUPS] = + CONTENT_SETTING_BLOCK; + desired_settings.settings[CONTENT_SETTINGS_TYPE_GEOLOCATION] = + CONTENT_SETTING_ASK; + desired_settings.settings[CONTENT_SETTINGS_TYPE_NOTIFICATIONS] = + CONTENT_SETTING_ASK; + desired_settings.settings[CONTENT_SETTINGS_TYPE_INTENTS] = + CONTENT_SETTING_ASK; + desired_settings.settings[CONTENT_SETTINGS_TYPE_FULLSCREEN] = + CONTENT_SETTING_ASK; + desired_settings.settings[CONTENT_SETTINGS_TYPE_MOUSELOCK] = + CONTENT_SETTING_ASK; + ContentSettings settings = + host_content_settings_map->GetContentSettings(host); + EXPECT_TRUE(SettingsEqual(desired_settings, settings)); + EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_COOKIES], + settings.settings[CONTENT_SETTINGS_TYPE_COOKIES]); + EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_IMAGES], + settings.settings[CONTENT_SETTINGS_TYPE_IMAGES]); + EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_PLUGINS], + settings.settings[CONTENT_SETTINGS_TYPE_PLUGINS]); + EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_POPUPS], + settings.settings[CONTENT_SETTINGS_TYPE_POPUPS]); + EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_GEOLOCATION], + settings.settings[CONTENT_SETTINGS_TYPE_GEOLOCATION]); + EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_COOKIES], + settings.settings[CONTENT_SETTINGS_TYPE_COOKIES]); + EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_INTENTS], + settings.settings[CONTENT_SETTINGS_TYPE_INTENTS]); + EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_FULLSCREEN], + settings.settings[CONTENT_SETTINGS_TYPE_FULLSCREEN]); + EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_MOUSELOCK], + settings.settings[CONTENT_SETTINGS_TYPE_MOUSELOCK]); } TEST_F(HostContentSettingsMapTest, OffTheRecord) { @@ -788,9 +814,10 @@ TEST_F(HostContentSettingsMapTest, ResourceIdentifier) { ContentSetting default_plugin_setting = host_content_settings_map->GetDefaultContentSetting( CONTENT_SETTINGS_TYPE_PLUGINS, NULL); + ContentSettings settings = + host_content_settings_map->GetContentSettings(host); EXPECT_EQ(default_plugin_setting, - host_content_settings_map->GetContentSetting( - host, host, CONTENT_SETTINGS_TYPE_PLUGINS, "")); + settings.settings[CONTENT_SETTINGS_TYPE_PLUGINS]); // If no resource-specific content settings are defined, the setting should be // DEFAULT. diff --git a/chrome/browser/content_settings/mock_settings_observer.cc b/chrome/browser/content_settings/mock_settings_observer.cc index a281a1d..a0cc5b1 100644 --- a/chrome/browser/content_settings/mock_settings_observer.cc +++ b/chrome/browser/content_settings/mock_settings_observer.cc @@ -34,6 +34,5 @@ void MockSettingsObserver::Observe( settings_details->update_all()); // This checks that calling a Get function from an observer doesn't // deadlock. - GURL url("http://random-hostname.com/"); - map->GetContentSetting(url, url, CONTENT_SETTINGS_TYPE_IMAGES, ""); + map->GetContentSettings(GURL("http://random-hostname.com/")); } diff --git a/chrome/browser/content_settings/tab_specific_content_settings.cc b/chrome/browser/content_settings/tab_specific_content_settings.cc index fda4042..91948d5 100644 --- a/chrome/browser/content_settings/tab_specific_content_settings.cc +++ b/chrome/browser/content_settings/tab_specific_content_settings.cc @@ -431,6 +431,15 @@ void TabSpecificContentSettings::DidNavigateMainFramePostCommit( } } +void TabSpecificContentSettings::RenderViewCreated( + RenderViewHost* render_view_host) { + Profile* profile = + Profile::FromBrowserContext(tab_contents()->browser_context()); + HostContentSettingsMap* map = profile->GetHostContentSettingsMap(); + render_view_host->Send(new ChromeViewMsg_SetDefaultContentSettings( + map->GetDefaultContentSettings())); +} + void TabSpecificContentSettings::DidStartProvisionalLoadForFrame( int64 frame_id, bool is_main_frame, @@ -477,9 +486,13 @@ void TabSpecificContentSettings::Observe( settings_details.ptr()->primary_pattern().Matches(entry_url)) { Profile* profile = Profile::FromBrowserContext(tab_contents()->browser_context()); + HostContentSettingsMap* map = profile->GetHostContentSettingsMap(); + Send(new ChromeViewMsg_SetDefaultContentSettings( + map->GetDefaultContentSettings())); + Send(new ChromeViewMsg_SetContentSettingsForCurrentURL( + entry_url, map->GetContentSettings(entry_url))); RendererContentSettingRules rules; - GetRendererContentSettingRules(profile->GetHostContentSettingsMap(), - &rules); + GetRendererContentSettingRules(map, &rules); Send(new ChromeViewMsg_SetContentSettingRules(rules)); } } diff --git a/chrome/browser/content_settings/tab_specific_content_settings.h b/chrome/browser/content_settings/tab_specific_content_settings.h index cef428d..c240759 100644 --- a/chrome/browser/content_settings/tab_specific_content_settings.h +++ b/chrome/browser/content_settings/tab_specific_content_settings.h @@ -163,6 +163,7 @@ class TabSpecificContentSettings : public TabContentsObserver, virtual void DidNavigateMainFramePostCommit( const content::LoadCommittedDetails& details, const ViewHostMsg_FrameNavigate_Params& params) OVERRIDE; + virtual void RenderViewCreated(RenderViewHost* render_view_host) OVERRIDE; virtual void DidStartProvisionalLoadForFrame( int64 frame_id, bool is_main_frame, diff --git a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc index 3d86c7c..35231bb 100644 --- a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc +++ b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc @@ -333,6 +333,16 @@ void ChromeResourceDispatcherHostDelegate::OnResponseStarted( } } + // We must send the content settings for the URL before sending response + // headers to the renderer. + const content::ResourceContext& resource_context = filter->resource_context(); + ProfileIOData* io_data = + reinterpret_cast(resource_context.GetUserData(NULL)); + HostContentSettingsMap* map = io_data->GetHostContentSettingsMap(); + filter->Send(new ChromeViewMsg_SetContentSettingsForLoadingURL( + info->route_id(), request->url(), + map->GetContentSettings(request->url()))); + // See if the response contains the X-Auto-Login header. If so, this was // a request for a login page, and the server is allowing the browser to // suggest auto-login, if available. diff --git a/chrome/common/content_settings.cc b/chrome/common/content_settings.cc index 8b28f4b..cd30d6c 100644 --- a/chrome/common/content_settings.cc +++ b/chrome/common/content_settings.cc @@ -10,6 +10,16 @@ ContentSetting IntToContentSetting(int content_setting) { CONTENT_SETTING_DEFAULT : static_cast(content_setting); } +ContentSettings::ContentSettings() { + for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) + settings[i] = CONTENT_SETTING_DEFAULT; +} + +ContentSettings::ContentSettings(ContentSetting default_setting) { + for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) + settings[i] = default_setting; +} + ContentSettingPatternSource::ContentSettingPatternSource( const ContentSettingsPattern& primary_pattern, const ContentSettingsPattern& secondary_pattern, diff --git a/chrome/common/content_settings.h b/chrome/common/content_settings.h index 0c44417..cff4102 100644 --- a/chrome/common/content_settings.h +++ b/chrome/common/content_settings.h @@ -27,6 +27,14 @@ enum ContentSetting { // prefs off disk. ContentSetting IntToContentSetting(int content_setting); +// Aggregates the permissions for the different content types. +struct ContentSettings { + ContentSettings(); + explicit ContentSettings(ContentSetting default_setting); + + ContentSetting settings[CONTENT_SETTINGS_NUM_TYPES]; +}; + struct ContentSettingPatternSource { ContentSettingPatternSource(const ContentSettingsPattern& primary_pattern, const ContentSettingsPattern& secondary_patttern, diff --git a/chrome/common/render_messages.cc b/chrome/common/render_messages.cc index 726f082..39c6705 100644 --- a/chrome/common/render_messages.cc +++ b/chrome/common/render_messages.cc @@ -6,6 +6,26 @@ namespace IPC { +void ParamTraits::Write( + Message* m, const ContentSettings& settings) { + for (size_t i = 0; i < arraysize(settings.settings); ++i) + WriteParam(m, settings.settings[i]); +} + +bool ParamTraits::Read( + const Message* m, void** iter, ContentSettings* r) { + for (size_t i = 0; i < arraysize(r->settings); ++i) { + if (!ReadParam(m, iter, &r->settings[i])) + return false; + } + return true; +} + +void ParamTraits::Log( + const ContentSettings& p, std::string* l) { + l->append(""); +} + void ParamTraits::Write( Message* m, const ContentSettingsPattern& pattern) { pattern.WriteToMessage(m); diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h index 54b5be3..89e395e 100644 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h @@ -98,6 +98,14 @@ struct ParamTraits { #endif // defined(OS_POSIX) && !defined(USE_AURA) template <> +struct ParamTraits { + typedef ContentSettings param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template <> struct ParamTraits { typedef ContentSettingsPattern param_type; static void Write(Message* m, const param_type& p); @@ -223,6 +231,25 @@ IPC_MESSAGE_CONTROL1(ChromeViewMsg_VisitedLink_Add, std::vector) // re-calculated. IPC_MESSAGE_CONTROL0(ChromeViewMsg_VisitedLink_Reset) +// Set the content settings for a particular url that the renderer is in the +// process of loading. This will be stored, to be used if the load commits +// and ignored otherwise. +IPC_MESSAGE_ROUTED2(ChromeViewMsg_SetContentSettingsForLoadingURL, + GURL /* url */, + ContentSettings /* content_settings */) + +// Set the content settings for a particular url, so all render views +// displaying this host url update their content settings to match. +IPC_MESSAGE_CONTROL2(ChromeViewMsg_SetContentSettingsForCurrentURL, + GURL /* url */, + ContentSettings /* content_settings */) + +// Set the content settings for a particular url that the renderer is in the +// process of loading. This will be stored, to be used if the load commits +// and ignored otherwise. +IPC_MESSAGE_CONTROL1(ChromeViewMsg_SetDefaultContentSettings, + ContentSettings /* content_settings */) + // Set the content setting rules stored by the renderer. IPC_MESSAGE_CONTROL1(ChromeViewMsg_SetContentSettingRules, RendererContentSettingRules /* rules */) diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc index 841772c..7cf200c 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc @@ -217,6 +217,8 @@ void ChromeContentRendererClient::RenderViewCreated( ContentSettingsObserver* content_settings = new ContentSettingsObserver(render_view); if (chrome_observer_.get()) { + content_settings->SetDefaultContentSettings( + chrome_observer_->default_content_settings()); content_settings->SetContentSettingRules( chrome_observer_->content_setting_rules()); } diff --git a/chrome/renderer/chrome_render_process_observer.cc b/chrome/renderer/chrome_render_process_observer.cc index c1ff810..0b2fd95 100644 --- a/chrome/renderer/chrome_render_process_observer.cc +++ b/chrome/renderer/chrome_render_process_observer.cc @@ -106,6 +106,30 @@ class RendererResourceDelegate : public content::ResourceDispatcherDelegate { DISALLOW_COPY_AND_ASSIGN(RendererResourceDelegate); }; +class RenderViewContentSettingsSetter : public content::RenderViewVisitor { + public: + RenderViewContentSettingsSetter(const GURL& url, + const ContentSettings& content_settings) + : url_(url), + content_settings_(content_settings) { + } + + virtual bool Visit(content::RenderView* render_view) { + if (GURL(render_view->GetWebView()->mainFrame()->document().url()) == + url_) { + ContentSettingsObserver::Get(render_view)->SetContentSettings( + content_settings_); + } + return true; + } + + private: + GURL url_; + ContentSettings content_settings_; + + DISALLOW_COPY_AND_ASSIGN(RenderViewContentSettingsSetter); +}; + #if defined(OS_WIN) static base::win::IATPatchFunction g_iat_patch_createdca; HDC WINAPI CreateDCAPatch(LPCSTR driver_name, @@ -239,6 +263,10 @@ bool ChromeRenderProcessObserver::OnControlMessageReceived( IPC_BEGIN_MESSAGE_MAP(ChromeRenderProcessObserver, message) IPC_MESSAGE_HANDLER(ChromeViewMsg_SetIsIncognitoProcess, OnSetIsIncognitoProcess) + IPC_MESSAGE_HANDLER(ChromeViewMsg_SetDefaultContentSettings, + OnSetDefaultContentSettings) + IPC_MESSAGE_HANDLER(ChromeViewMsg_SetContentSettingsForCurrentURL, + OnSetContentSettingsForCurrentURL) IPC_MESSAGE_HANDLER(ChromeViewMsg_SetContentSettingRules, OnSetContentSettingRules) IPC_MESSAGE_HANDLER(ChromeViewMsg_SetCacheCapacities, OnSetCacheCapacities) @@ -270,6 +298,18 @@ void ChromeRenderProcessObserver::OnSetIsIncognitoProcess( is_incognito_process_ = is_incognito_process; } +void ChromeRenderProcessObserver::OnSetContentSettingsForCurrentURL( + const GURL& url, + const ContentSettings& content_settings) { + RenderViewContentSettingsSetter setter(url, content_settings); + content::RenderView::ForEach(&setter); +} + +void ChromeRenderProcessObserver::OnSetDefaultContentSettings( + const ContentSettings& content_settings) { + default_content_settings_ = content_settings; +} + void ChromeRenderProcessObserver::OnSetContentSettingRules( const RendererContentSettingRules& rules) { content_setting_rules_ = rules; @@ -394,3 +434,8 @@ const RendererContentSettingRules* ChromeRenderProcessObserver::content_setting_rules() const { return &content_setting_rules_; } + +const ContentSettings* +ChromeRenderProcessObserver::default_content_settings() const { + return &default_content_settings_; +} diff --git a/chrome/renderer/chrome_render_process_observer.h b/chrome/renderer/chrome_render_process_observer.h index ed4805e..74ab740 100644 --- a/chrome/renderer/chrome_render_process_observer.h +++ b/chrome/renderer/chrome_render_process_observer.h @@ -41,6 +41,10 @@ class ChromeRenderProcessObserver : public content::RenderProcessObserver { // any 'clear cache' commands that were delayed until the next navigation. void ExecutePendingClearCache(); + // Returns a pointer to the default content settings owned by + // |ChromeRenderProcessObserver|. + const ContentSettings* default_content_settings() const; + // Returns a pointer to the content setting rules owned by // |ChromeRenderProcessObserver|. const RendererContentSettingRules* content_setting_rules() const; @@ -53,6 +57,7 @@ class ChromeRenderProcessObserver : public content::RenderProcessObserver { void OnSetIsIncognitoProcess(bool is_incognito_process); void OnSetContentSettingsForCurrentURL( const GURL& url, const ContentSettings& content_settings); + void OnSetDefaultContentSettings(const ContentSettings& content_settings); void OnSetContentSettingRules(const RendererContentSettingRules& rules); void OnSetCacheCapacities(size_t min_dead_capacity, size_t max_dead_capacity, @@ -74,6 +79,7 @@ class ChromeRenderProcessObserver : public content::RenderProcessObserver { chrome::ChromeContentRendererClient* client_; // If true, the web cache shall be cleared before the next navigation event. bool clear_cache_pending_; + ContentSettings default_content_settings_; RendererContentSettingRules content_setting_rules_; DISALLOW_COPY_AND_ASSIGN(ChromeRenderProcessObserver); diff --git a/chrome/renderer/content_settings_observer.cc b/chrome/renderer/content_settings_observer.cc index dda5235..3d1bfac 100644 --- a/chrome/renderer/content_settings_observer.cc +++ b/chrome/renderer/content_settings_observer.cc @@ -80,6 +80,7 @@ ContentSettingsObserver::ContentSettingsObserver( content::RenderView* render_view) : content::RenderViewObserver(render_view), content::RenderViewObserverTracker(render_view), + default_content_settings_(NULL), content_setting_rules_(NULL), plugins_temporarily_allowed_(false) { ClearBlockedContentSettings(); @@ -88,11 +89,28 @@ ContentSettingsObserver::ContentSettingsObserver( ContentSettingsObserver::~ContentSettingsObserver() { } +void ContentSettingsObserver::SetContentSettings( + const ContentSettings& settings) { + current_content_settings_ = settings; +} + +void ContentSettingsObserver::SetDefaultContentSettings( + const ContentSettings* settings) { + default_content_settings_ = settings; +} + void ContentSettingsObserver::SetContentSettingRules( const RendererContentSettingRules* content_setting_rules) { content_setting_rules_ = content_setting_rules; } +ContentSetting ContentSettingsObserver::GetContentSetting( + ContentSettingsType type) { + // Don't call this for plug-ins. + DCHECK_NE(CONTENT_SETTINGS_TYPE_PLUGINS, type); + return current_content_settings_.settings[type]; +} + void ContentSettingsObserver::DidBlockContentType( ContentSettingsType settings_type, const std::string& resource_identifier) { @@ -114,6 +132,8 @@ bool ContentSettingsObserver::OnMessageReceived(const IPC::Message& message) { // blocked plugin. IPC_MESSAGE_HANDLER_GENERIC(ChromeViewMsg_LoadBlockedPlugins, OnLoadBlockedPlugins(); handled = false) + IPC_MESSAGE_HANDLER(ChromeViewMsg_SetContentSettingsForLoadingURL, + OnSetContentSettingsForLoadingURL) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -136,10 +156,46 @@ void ContentSettingsObserver::DidCommitProvisionalLoad( } GURL url = frame->document().url(); + + if (frame->document().securityOrigin().toString() == "null" && + !url.SchemeIs(chrome::kFileScheme)) { + // The Frame has a unique security origin. Instead of granting the frame + // privileges based on it's URL, we fall back to the default content + // settings. + + // We exempt file URLs here because we sandbox them by default, but folks + // might reasonably want to supply non-default content settings for various + // file URLs. + if (default_content_settings_) + SetContentSettings(*default_content_settings_); + return; + } + // If we start failing this DCHECK, please makes sure we don't regress // this bug: http://code.google.com/p/chromium/issues/detail?id=79304 - DCHECK(frame->document().securityOrigin().toString() == "null" || - !url.SchemeIs(chrome::kDataScheme)); + DCHECK(!url.SchemeIs(chrome::kDataScheme)); + + // Set content settings. Default them from the parent window if one exists. + // This makes sure about:blank windows work as expected. + HostContentSettings::iterator host_content_settings = + host_content_settings_.find(url); + if (host_content_settings != host_content_settings_.end()) { + SetContentSettings(host_content_settings->second); + + // These content settings were merely recorded transiently for this load. + // We can erase them now. If at some point we reload this page, the + // browser will send us new, up-to-date content settings. + host_content_settings_.erase(host_content_settings); + } else if (frame->opener()) { + // The opener's view is not guaranteed to be non-null (it could be + // detached from its page but not yet destructed). + if (WebView* opener_view = frame->opener()->view()) { + content::RenderView* opener = + content::RenderView::FromWebView(opener_view); + ContentSettingsObserver* observer = ContentSettingsObserver::Get(opener); + SetContentSettings(observer->current_content_settings_); + } + } } bool ContentSettingsObserver::AllowDatabase(WebFrame* frame, @@ -276,10 +332,23 @@ void ContentSettingsObserver::DidNotAllowScript(WebFrame* frame) { DidBlockContentType(CONTENT_SETTINGS_TYPE_JAVASCRIPT, std::string()); } +void ContentSettingsObserver::OnSetContentSettingsForLoadingURL( + const GURL& url, + const ContentSettings& content_settings) { + host_content_settings_[url] = content_settings; +} + void ContentSettingsObserver::OnLoadBlockedPlugins() { plugins_temporarily_allowed_ = true; } +bool ContentSettingsObserver::AllowContentType( + ContentSettingsType settings_type) { + // CONTENT_SETTING_ASK is only valid for cookies. + return current_content_settings_.settings[settings_type] != + CONTENT_SETTING_BLOCK; +} + void ContentSettingsObserver::ClearBlockedContentSettings() { for (size_t i = 0; i < arraysize(content_blocked_); ++i) content_blocked_[i] = false; diff --git a/chrome/renderer/content_settings_observer.h b/chrome/renderer/content_settings_observer.h index 6c3d3f5..dd9c7b9 100644 --- a/chrome/renderer/content_settings_observer.h +++ b/chrome/renderer/content_settings_observer.h @@ -27,12 +27,22 @@ class ContentSettingsObserver explicit ContentSettingsObserver(content::RenderView* render_view); virtual ~ContentSettingsObserver(); + // Sets the content settings that back allowScripts() and allowPlugins(). + void SetContentSettings(const ContentSettings& settings); + + // Sets the default content settings that back allowScripts() and + // allowPlugins(). + void SetDefaultContentSettings(const ContentSettings* settings); + // Sets the content setting rules which back |AllowImage()|, |AllowScript()|, // and |AllowScriptFromSource()|. |content_setting_rules| must outlive this // |ContentSettingsObserver|. void SetContentSettingRules( const RendererContentSettingRules* content_setting_rules); + // Returns the setting for the given type. + ContentSetting GetContentSetting(ContentSettingsType type); + bool plugins_temporarily_allowed() { return plugins_temporarily_allowed_; } @@ -71,11 +81,29 @@ class ContentSettingsObserver bool is_new_navigation); // Message handlers. + void OnSetContentSettingsForLoadingURL( + const GURL& url, + const ContentSettings& content_settings); void OnLoadBlockedPlugins(); + // Helper method that returns if the user wants to block content of type + // |content_type|. + bool AllowContentType(ContentSettingsType settings_type); + // Resets the |content_blocked_| array. void ClearBlockedContentSettings(); + typedef std::map HostContentSettings; + HostContentSettings host_content_settings_; + + // A pointer to the most up-to-date view of the default content + // settings. Normally, they are owned by |ChromeRenderProcessObserver|. In the + // tests they are owned by the caller of |SetDefaultContentSettings|. + const ContentSettings* default_content_settings_; + + // Stores if loading of scripts and plugins is allowed. + ContentSettings current_content_settings_; + // A pointer to content setting rules stored by the renderer. Normally, the // |RendererContentSettingRules| object is owned by // |ChromeRenderProcessObserver|. In the tests it is owned by the caller of diff --git a/chrome/renderer/content_settings_observer_browsertest.cc b/chrome/renderer/content_settings_observer_browsertest.cc index eb9d337..78c7d21 100644 --- a/chrome/renderer/content_settings_observer_browsertest.cc +++ b/chrome/renderer/content_settings_observer_browsertest.cc @@ -149,7 +149,14 @@ TEST_F(ChromeRenderViewTest, PluginsTemporarilyAllowed) { // Load some HTML. LoadHTML("Foo"); + // Block plugins. + ContentSettings settings; + for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) + settings.settings[i] = CONTENT_SETTING_ALLOW; + settings.settings[CONTENT_SETTINGS_TYPE_PLUGINS] = CONTENT_SETTING_BLOCK; ContentSettingsObserver* observer = ContentSettingsObserver::Get(view_); + observer->SetContentSettings(settings); + observer->SetDefaultContentSettings(&settings); EXPECT_FALSE(observer->plugins_temporarily_allowed()); // Temporarily allow plugins. -- cgit v1.1