diff options
author | abarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-17 10:39:09 +0000 |
---|---|---|
committer | abarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-17 10:39:09 +0000 |
commit | 6326d8b152d2fb48416720faaa9e9684a64b83ac (patch) | |
tree | 86970b51280be685bd94669b883ccb3f9276b516 | |
parent | 53fa16073b7f17ca0c46432b1ec7dad30bcb3b6e (diff) | |
download | chromium_src-6326d8b152d2fb48416720faaa9e9684a64b83ac.zip chromium_src-6326d8b152d2fb48416720faaa9e9684a64b83ac.tar.gz chromium_src-6326d8b152d2fb48416720faaa9e9684a64b83ac.tar.bz2 |
Correctly apply content settings to data URLs.
Data URLs don't round-trip through the browser's network stack, so they don't
trigger the content settings code to upload the proper settings to the
renderer. This patch proactively pushes the default content settings into the
renderer so that it can use them for data URLs (and other sandboxed frames).
Review URL: http://codereview.chromium.org/7167003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@89466 0039d316-1c4b-4281-b951-d872f2087c98
11 files changed, 91 insertions, 10 deletions
diff --git a/chrome/browser/content_settings/content_settings_browsertest.cc b/chrome/browser/content_settings/content_settings_browsertest.cc index b1e5556..383dc7e 100644 --- a/chrome/browser/content_settings/content_settings_browsertest.cc +++ b/chrome/browser/content_settings/content_settings_browsertest.cc @@ -30,3 +30,18 @@ IN_PROC_BROWSER_TEST_F(InProcessBrowserTest, RedirectLoopCookies) { EXPECT_TRUE(tab_contents->content_settings()->IsContentBlocked( CONTENT_SETTINGS_TYPE_COOKIES)); } + +IN_PROC_BROWSER_TEST_F(InProcessBrowserTest, ContentSettingsBlockDataURLs) { + GURL url("data:text/html,<title>Data URL</title><script>alert(1)</script>"); + + browser()->profile()->GetHostContentSettingsMap()->SetDefaultContentSetting( + CONTENT_SETTINGS_TYPE_JAVASCRIPT, CONTENT_SETTING_BLOCK); + + ui_test_utils::NavigateToURL(browser(), url); + + TabContentsWrapper* tab_contents = browser()->GetSelectedTabContentsWrapper(); + ASSERT_EQ(UTF8ToUTF16("Data URL"), tab_contents->tab_contents()->GetTitle()); + + EXPECT_TRUE(tab_contents->content_settings()->IsContentBlocked( + CONTENT_SETTINGS_TYPE_JAVASCRIPT)); +} diff --git a/chrome/browser/content_settings/host_content_settings_map.cc b/chrome/browser/content_settings/host_content_settings_map.cc index 66853dd..419921c 100644 --- a/chrome/browser/content_settings/host_content_settings_map.cc +++ b/chrome/browser/content_settings/host_content_settings_map.cc @@ -158,6 +158,13 @@ ContentSetting HostContentSettingsMap::GetDefaultContentSetting( return setting; } +ContentSettings HostContentSettingsMap::GetDefaultContentSettings() const { + ContentSettings output(CONTENT_SETTING_DEFAULT); + for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) + output.settings[i] = GetDefaultContentSetting(ContentSettingsType(i)); + return output; +} + ContentSetting HostContentSettingsMap::GetCookieContentSetting( const GURL& url, const GURL& first_party_url, diff --git a/chrome/browser/content_settings/host_content_settings_map.h b/chrome/browser/content_settings/host_content_settings_map.h index 64556f7..dcb48cf 100644 --- a/chrome/browser/content_settings/host_content_settings_map.h +++ b/chrome/browser/content_settings/host_content_settings_map.h @@ -54,6 +54,11 @@ class HostContentSettingsMap ContentSetting GetDefaultContentSetting( ContentSettingsType content_type) 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 ContentSettingsTypes that // require an resource identifier to be specified, the |resource_identifier| diff --git a/chrome/browser/content_settings/tab_specific_content_settings.cc b/chrome/browser/content_settings/tab_specific_content_settings.cc index 0a8716a..59303e2 100644 --- a/chrome/browser/content_settings/tab_specific_content_settings.cc +++ b/chrome/browser/content_settings/tab_specific_content_settings.cc @@ -430,6 +430,14 @@ void TabSpecificContentSettings::DidNavigateMainFramePostCommit( } } +void TabSpecificContentSettings::RenderViewCreated( + RenderViewHost* render_view_host) { + HostContentSettingsMap* map = + tab_contents()->profile()->GetHostContentSettingsMap(); + render_view_host->Send(new ViewMsg_SetDefaultContentSettings( + map->GetDefaultContentSettings())); +} + void TabSpecificContentSettings::DidStartProvisionalLoadForFrame( int64 frame_id, bool is_main_frame, @@ -468,9 +476,12 @@ void TabSpecificContentSettings::Observe(NotificationType type, // The active NavigationEntry is the URL in the URL field of a tab. // Currently this should be matched by the |primary_pattern|. settings_details.ptr()->primary_pattern().Matches(entry_url)) { + HostContentSettingsMap* map = + tab_contents()->profile()->GetHostContentSettingsMap(); + Send(new ViewMsg_SetDefaultContentSettings( + map->GetDefaultContentSettings())); Send(new ViewMsg_SetContentSettingsForCurrentURL( - entry_url, tab_contents()->profile()->GetHostContentSettingsMap()-> - GetContentSettings(entry_url, entry_url))); + entry_url, map->GetContentSettings(entry_url, entry_url))); } } diff --git a/chrome/browser/content_settings/tab_specific_content_settings.h b/chrome/browser/content_settings/tab_specific_content_settings.h index d262b92..b862dc5 100644 --- a/chrome/browser/content_settings/tab_specific_content_settings.h +++ b/chrome/browser/content_settings/tab_specific_content_settings.h @@ -159,6 +159,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/common/render_messages.h b/chrome/common/render_messages.h index 65f07433..d33c9fb 100644 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h @@ -176,6 +176,12 @@ IPC_MESSAGE_CONTROL2(ViewMsg_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(ViewMsg_SetDefaultContentSettings, + ContentSettings /* content_settings */) + // Tells the render view to load all blocked plugins. IPC_MESSAGE_ROUTED0(ViewMsg_LoadBlockedPlugins) diff --git a/chrome/renderer/chrome_render_process_observer.cc b/chrome/renderer/chrome_render_process_observer.cc index 1721723..d50c638 100644 --- a/chrome/renderer/chrome_render_process_observer.cc +++ b/chrome/renderer/chrome_render_process_observer.cc @@ -409,6 +409,8 @@ bool ChromeRenderProcessObserver::OnControlMessageReceived( bool handled = true; IPC_BEGIN_MESSAGE_MAP(ChromeRenderProcessObserver, message) IPC_MESSAGE_HANDLER(ViewMsg_SetIsIncognitoProcess, OnSetIsIncognitoProcess) + IPC_MESSAGE_HANDLER(ViewMsg_SetDefaultContentSettings, + OnSetDefaultContentSettings) IPC_MESSAGE_HANDLER(ViewMsg_SetContentSettingsForCurrentURL, OnSetContentSettingsForCurrentURL) IPC_MESSAGE_HANDLER(ViewMsg_SetCacheCapacities, OnSetCacheCapacities) @@ -446,6 +448,11 @@ void ChromeRenderProcessObserver::OnSetContentSettingsForCurrentURL( RenderView::ForEach(&setter); } +void ChromeRenderProcessObserver::OnSetDefaultContentSettings( + const ContentSettings& content_settings) { + ContentSettingsObserver::SetDefaultContentSettings(content_settings); +} + void ChromeRenderProcessObserver::OnSetCacheCapacities(size_t min_dead_capacity, size_t max_dead_capacity, size_t capacity) { diff --git a/chrome/renderer/chrome_render_process_observer.h b/chrome/renderer/chrome_render_process_observer.h index f447c82..beb2b26 100644 --- a/chrome/renderer/chrome_render_process_observer.h +++ b/chrome/renderer/chrome_render_process_observer.h @@ -35,6 +35,7 @@ class ChromeRenderProcessObserver : public RenderProcessObserver { void OnSetIsIncognitoProcess(bool is_incognito_process); void OnSetContentSettingsForCurrentURL( const GURL& url, const ContentSettings& content_settings); + void OnSetDefaultContentSettings(const ContentSettings& content_settings); void OnSetCacheCapacities(size_t min_dead_capacity, size_t max_dead_capacity, size_t capacity); diff --git a/chrome/renderer/content_settings_observer.cc b/chrome/renderer/content_settings_observer.cc index ef8ebfe..1f9de9e 100644 --- a/chrome/renderer/content_settings_observer.cc +++ b/chrome/renderer/content_settings_observer.cc @@ -13,7 +13,6 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrameClient.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebURLRequest.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" using WebKit::WebDataSource; @@ -21,7 +20,6 @@ using WebKit::WebFrame; using WebKit::WebFrameClient; using WebKit::WebSecurityOrigin; using WebKit::WebString; -using WebKit::WebURLRequest; using WebKit::WebView; namespace { @@ -38,7 +36,7 @@ static bool IsWhitelistedForContentSettings(WebFrame* frame) { // If the scheme is ftp: or file:, an empty file name indicates a directory // listing, which requires JavaScript to function properly. GURL frame_url = frame->url(); - const char* kDirProtocols[] = { "ftp", "file" }; + const char* kDirProtocols[] = { chrome::kFtpScheme, chrome::kFileScheme }; for (size_t i = 0; i < arraysize(kDirProtocols); ++i) { if (EqualsASCII(origin.protocol(), kDirProtocols[i])) { return frame_url.SchemeIs(kDirProtocols[i]) && @@ -51,6 +49,8 @@ static bool IsWhitelistedForContentSettings(WebFrame* frame) { } // namespace +ContentSettings ContentSettingsObserver::default_settings_; + ContentSettingsObserver::ContentSettingsObserver(RenderView* render_view) : RenderViewObserver(render_view), RenderViewObserverTracker<ContentSettingsObserver>(render_view), @@ -61,12 +61,16 @@ ContentSettingsObserver::ContentSettingsObserver(RenderView* render_view) ContentSettingsObserver::~ContentSettingsObserver() { } - void ContentSettingsObserver::SetContentSettings( const ContentSettings& settings) { current_content_settings_ = settings; } +void ContentSettingsObserver::SetDefaultContentSettings( + const ContentSettings& settings) { + default_settings_ = settings; +} + ContentSetting ContentSettingsObserver::GetContentSetting( ContentSettingsType type) { if (type == CONTENT_SETTINGS_TYPE_PLUGINS && @@ -109,19 +113,35 @@ void ContentSettingsObserver::DidCommitProvisionalLoad( if (frame->parent()) return; // Not a top-level navigation. - WebDataSource* ds = frame->dataSource(); - const WebURLRequest& request = ds->request(); - // Clear "block" flags for the new page. This needs to happen before any of // allowScripts(), allowImages(), allowPlugins() is called for the new page // so that these functions can correctly detect that a piece of content // flipped from "not blocked" to "blocked". ClearBlockedContentSettings(); + GURL url = frame->url(); + + if (frame->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. + SetContentSettings(default_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(!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(GURL(request.url())); + host_content_settings_.find(url); if (host_content_settings != host_content_settings_.end()) { SetContentSettings(host_content_settings->second); diff --git a/chrome/renderer/content_settings_observer.h b/chrome/renderer/content_settings_observer.h index 4929edb..d28deb8 100644 --- a/chrome/renderer/content_settings_observer.h +++ b/chrome/renderer/content_settings_observer.h @@ -30,6 +30,10 @@ class ContentSettingsObserver // allowPlugins(). void SetContentSettings(const ContentSettings& settings); + // Sets the default content settings that back allowScripts(), + // allowImages(), and allowPlugins(). + static void SetDefaultContentSettings(const ContentSettings& settings); + // Returns the setting for the given type. ContentSetting GetContentSetting(ContentSettingsType type); @@ -78,6 +82,9 @@ class ContentSettingsObserver typedef std::map<GURL, ContentSettings> HostContentSettings; HostContentSettings host_content_settings_; + // Stores our most up-to-date view of the default content settings. + static ContentSettings default_settings_; + // Stores if loading of images, scripts, and plugins is allowed. ContentSettings current_content_settings_; diff --git a/chrome/renderer/content_settings_observer_browsertest.cc b/chrome/renderer/content_settings_observer_browsertest.cc index 391bc30..e1b484d 100644 --- a/chrome/renderer/content_settings_observer_browsertest.cc +++ b/chrome/renderer/content_settings_observer_browsertest.cc @@ -107,6 +107,7 @@ TEST_F(RenderViewTest, JSBlockSentAfterPageLoad) { settings.settings[CONTENT_SETTINGS_TYPE_JAVASCRIPT] = CONTENT_SETTING_BLOCK; ContentSettingsObserver* observer = ContentSettingsObserver::Get(view_); observer->SetContentSettings(settings); + ContentSettingsObserver::SetDefaultContentSettings(settings); // Make sure no pending messages are in the queue. ProcessPendingMessages(); |