summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-18 17:00:15 +0000
committerjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-18 17:00:15 +0000
commit5e56df8fb10f7aca72c51184ea66e4d5462d31e3 (patch)
treed49606d0e1af4ec568dfa8f03c778c7ae0780d06 /chrome
parentf3f4d7fc63d2e686208de341e01c559a2f0a4487 (diff)
downloadchromium_src-5e56df8fb10f7aca72c51184ea66e4d5462d31e3.zip
chromium_src-5e56df8fb10f7aca72c51184ea66e4d5462d31e3.tar.gz
chromium_src-5e56df8fb10f7aca72c51184ea66e4d5462d31e3.tar.bz2
Move the content settings code out of RenderView, since it belongs in the Chrome layer.
BUG=76793 Review URL: http://codereview.chromium.org/6873040 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81955 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/chrome_renderer.gypi2
-rw-r--r--chrome/renderer/chrome_content_renderer_client.cc9
-rw-r--r--chrome/renderer/chrome_render_process_observer.cc7
-rw-r--r--chrome/renderer/content_settings_observer.cc184
-rw-r--r--chrome/renderer/content_settings_observer.h74
-rw-r--r--chrome/renderer/content_settings_observer_browsertest.cc61
6 files changed, 332 insertions, 5 deletions
diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi
index 9bd1bac..dd3929e 100644
--- a/chrome/chrome_renderer.gypi
+++ b/chrome/chrome_renderer.gypi
@@ -99,6 +99,8 @@
'renderer/chrome_render_process_observer.h',
'renderer/chrome_render_view_observer.cc',
'renderer/chrome_render_view_observer.h',
+ 'renderer/content_settings_observer.cc',
+ 'renderer/content_settings_observer.h',
'renderer/devtools_agent.cc',
'renderer/devtools_agent.h',
'renderer/devtools_agent_filter.cc',
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index 1bdf1b5..76bd2da 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -30,6 +30,7 @@
#include "chrome/renderer/blocked_plugin.h"
#include "chrome/renderer/chrome_render_process_observer.h"
#include "chrome/renderer/chrome_render_view_observer.h"
+#include "chrome/renderer/content_settings_observer.h"
#include "chrome/renderer/devtools_agent.h"
#include "chrome/renderer/devtools_agent_filter.h"
#include "chrome/renderer/extensions/bindings_utils.h"
@@ -281,6 +282,7 @@ void ChromeContentRendererClient::RenderViewCreated(RenderView* render_view) {
}
#endif
+ new ContentSettingsObserver(render_view);
new DevToolsAgent(render_view);
new ExtensionHelper(render_view, extension_dispatcher_.get());
new PageLoadHistograms(render_view, histogram_snapshots_.get());
@@ -381,8 +383,9 @@ WebPlugin* ChromeContentRendererClient::CreatePlugin(
}
}
- ContentSetting host_setting = render_view->current_content_settings_.
- settings[CONTENT_SETTINGS_TYPE_PLUGINS];
+ ContentSettingsObserver* observer = ContentSettingsObserver::Get(render_view);
+ ContentSetting host_setting =
+ observer->GetContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS);
if (group->RequiresAuthorization() &&
!cmd->HasSwitch(switches::kAlwaysAuthorizePlugins) &&
@@ -425,7 +428,7 @@ WebPlugin* ChromeContentRendererClient::CreatePlugin(
std::string resource;
if (cmd->HasSwitch(switches::kEnableResourceContentSettings))
resource = group->identifier();
- render_view->DidBlockContentType(CONTENT_SETTINGS_TYPE_PLUGINS, resource);
+ observer->DidBlockContentType(CONTENT_SETTINGS_TYPE_PLUGINS, resource);
if (plugin_setting == CONTENT_SETTING_ASK) {
return CreatePluginPlaceholder(
render_view, frame, params, *group, IDR_CLICK_TO_PLAY_PLUGIN_HTML,
diff --git a/chrome/renderer/chrome_render_process_observer.cc b/chrome/renderer/chrome_render_process_observer.cc
index 5a3d89a..4d7672b 100644
--- a/chrome/renderer/chrome_render_process_observer.cc
+++ b/chrome/renderer/chrome_render_process_observer.cc
@@ -12,6 +12,7 @@
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/render_messages.h"
+#include "chrome/renderer/content_settings_observer.h"
#include "content/common/view_messages.h"
#include "content/renderer/render_thread.h"
#include "content/renderer/render_view.h"
@@ -83,8 +84,10 @@ class RenderViewContentSettingsSetter : public RenderViewVisitor {
}
virtual bool Visit(RenderView* render_view) {
- if (GURL(render_view->webview()->mainFrame()->url()) == url_)
- render_view->SetContentSettings(content_settings_);
+ if (GURL(render_view->webview()->mainFrame()->url()) == url_) {
+ ContentSettingsObserver::Get(render_view)->SetContentSettings(
+ content_settings_);
+ }
return true;
}
diff --git a/chrome/renderer/content_settings_observer.cc b/chrome/renderer/content_settings_observer.cc
new file mode 100644
index 0000000..b752f9b
--- /dev/null
+++ b/chrome/renderer/content_settings_observer.cc
@@ -0,0 +1,184 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/renderer/content_settings_observer.h"
+
+#include "chrome/common/render_messages.h"
+#include "chrome/common/url_constants.h"
+#include "content/renderer/render_view.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebDataSource.h"
+#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;
+using WebKit::WebFrame;
+using WebKit::WebFrameClient;
+using WebKit::WebSecurityOrigin;
+using WebKit::WebURLRequest;
+using WebKit::WebView;
+
+namespace {
+
+// True if |frame| contains content that is white-listed for content settings.
+static bool IsWhitelistedForContentSettings(WebFrame* frame) {
+ WebSecurityOrigin origin = frame->securityOrigin();
+ if (origin.isEmpty())
+ return false; // Uninitialized document?
+
+ if (EqualsASCII(origin.protocol(), chrome::kChromeUIScheme))
+ return true; // Browser UI elements should still work.
+
+ // 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" };
+ for (size_t i = 0; i < arraysize(kDirProtocols); ++i) {
+ if (EqualsASCII(origin.protocol(), kDirProtocols[i])) {
+ return frame_url.SchemeIs(kDirProtocols[i]) &&
+ frame_url.ExtractFileName().empty();
+ }
+ }
+
+ return false;
+}
+
+} // namespace
+
+ContentSettingsObserver::ContentSettingsObserver(RenderView* render_view)
+ : RenderViewObserver(render_view),
+ RenderViewObserverTracker<ContentSettingsObserver>(render_view) {
+ ClearBlockedContentSettings();
+}
+
+ContentSettingsObserver::~ContentSettingsObserver() {
+}
+
+
+void ContentSettingsObserver::SetContentSettings(
+ const ContentSettings& settings) {
+ current_content_settings_ = settings;
+}
+
+ContentSetting ContentSettingsObserver::GetContentSetting(
+ ContentSettingsType type) {
+ return current_content_settings_.settings[type];
+}
+
+void ContentSettingsObserver::DidBlockContentType(
+ ContentSettingsType settings_type,
+ const std::string& resource_identifier) {
+ if (!content_blocked_[settings_type]) {
+ content_blocked_[settings_type] = true;
+ Send(new ViewHostMsg_ContentBlocked(routing_id(), settings_type,
+ resource_identifier));
+ }
+}
+
+bool ContentSettingsObserver::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(ContentSettingsObserver, message)
+ IPC_MESSAGE_HANDLER(ViewMsg_SetContentSettingsForLoadingURL,
+ OnSetContentSettingsForLoadingURL)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void ContentSettingsObserver::DidCommitProvisionalLoad(
+ WebFrame* frame, bool is_new_navigation) {
+ 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();
+
+ // 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()));
+ 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()) {
+ RenderView* opener = RenderView::FromWebView(opener_view);
+ ContentSettingsObserver* observer = ContentSettingsObserver::Get(opener);
+ SetContentSettings(observer->current_content_settings_);
+ }
+ }
+}
+
+bool ContentSettingsObserver::AllowImages(WebFrame* frame,
+ bool enabled_per_settings) {
+ if (enabled_per_settings &&
+ AllowContentType(CONTENT_SETTINGS_TYPE_IMAGES)) {
+ return true;
+ }
+
+ if (IsWhitelistedForContentSettings(frame))
+ return true;
+
+ DidBlockContentType(CONTENT_SETTINGS_TYPE_IMAGES, std::string());
+ return false; // Other protocols fall through here.
+}
+
+bool ContentSettingsObserver::AllowPlugins(WebFrame* frame,
+ bool enabled_per_settings) {
+ return render_view()->WebFrameClient::allowPlugins(
+ frame, enabled_per_settings);
+}
+
+bool ContentSettingsObserver::AllowScript(WebFrame* frame,
+ bool enabled_per_settings) {
+ if (enabled_per_settings &&
+ AllowContentType(CONTENT_SETTINGS_TYPE_JAVASCRIPT)) {
+ return true;
+ }
+
+ if (IsWhitelistedForContentSettings(frame))
+ return true;
+
+ return false; // Other protocols fall through here.
+}
+
+void ContentSettingsObserver::DidNotAllowPlugins(WebFrame* frame) {
+ DidBlockContentType(CONTENT_SETTINGS_TYPE_PLUGINS, std::string());
+}
+
+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;
+}
+
+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
new file mode 100644
index 0000000..52d89f5
--- /dev/null
+++ b/chrome/renderer/content_settings_observer.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_RENDERER_CONTENT_SETTINGS_OBSERVER_H_
+#define CHROME_RENDERER_CONTENT_SETTINGS_OBSERVER_H_
+#pragma once
+
+#include <map>
+
+#include "chrome/common/content_settings.h"
+#include "content/renderer/render_view_observer.h"
+#include "content/renderer/render_view_observer_tracker.h"
+
+class GURL;
+
+// Handles blocking content per content settings for each RenderView.
+class ContentSettingsObserver
+ : public RenderViewObserver,
+ public RenderViewObserverTracker<ContentSettingsObserver> {
+ public:
+ explicit ContentSettingsObserver(RenderView* render_view);
+ virtual ~ContentSettingsObserver();
+
+ // Sets the content settings that back allowScripts(), allowImages(), and
+ // allowPlugins().
+ void SetContentSettings(const ContentSettings& settings);
+
+ // Returns the setting for the given type.
+ ContentSetting GetContentSetting(ContentSettingsType type);
+
+ // Sends an IPC notification that the specified content type was blocked.
+ // If the content type requires it, |resource_identifier| names the specific
+ // resource that was blocked (the plugin path in the case of plugins),
+ // otherwise it's the empty string.
+ void DidBlockContentType(ContentSettingsType settings_type,
+ const std::string& resource_identifier);
+
+ private:
+ // RenderViewObserver implementation.
+ virtual bool OnMessageReceived(const IPC::Message& message);
+ virtual void DidCommitProvisionalLoad(WebKit::WebFrame* frame,
+ bool is_new_navigation);
+ virtual bool AllowImages(WebKit::WebFrame* frame, bool enabled_per_settings);
+ virtual bool AllowPlugins(WebKit::WebFrame* frame, bool enabled_per_settings);
+ virtual bool AllowScript(WebKit::WebFrame* frame, bool enabled_per_settings);
+ virtual void DidNotAllowPlugins(WebKit::WebFrame* frame);
+ virtual void DidNotAllowScript(WebKit::WebFrame* frame);
+
+ // Message handlers.
+ void OnSetContentSettingsForLoadingURL(
+ const GURL& url,
+ const ContentSettings& content_settings);
+
+ // 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<GURL, ContentSettings> HostContentSettings;
+ HostContentSettings host_content_settings_;
+
+ // Stores if loading of images, scripts, and plugins is allowed.
+ ContentSettings current_content_settings_;
+
+ // Stores if images, scripts, and plugins have actually been blocked.
+ bool content_blocked_[CONTENT_SETTINGS_NUM_TYPES];
+
+ DISALLOW_COPY_AND_ASSIGN(ContentSettingsObserver);
+};
+
+#endif // CHROME_RENDERER_CONTENT_SETTINGS_OBSERVER_H_
diff --git a/chrome/renderer/content_settings_observer_browsertest.cc b/chrome/renderer/content_settings_observer_browsertest.cc
new file mode 100644
index 0000000..c65592d
--- /dev/null
+++ b/chrome/renderer/content_settings_observer_browsertest.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/content_settings.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/renderer/content_settings_observer.h"
+#include "chrome/test/render_view_test.h"
+#include "content/common/view_messages.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Regression test for http://crbug.com/35011
+TEST_F(RenderViewTest, JSBlockSentAfterPageLoad) {
+ // 1. Load page with JS.
+ std::string html = "<html>"
+ "<head>"
+ "<script>document.createElement('div');</script>"
+ "</head>"
+ "<body>"
+ "</body>"
+ "</html>";
+ render_thread_.sink().ClearMessages();
+ LoadHTML(html.c_str());
+
+ // 2. Block JavaScript.
+ ContentSettings settings;
+ for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i)
+ settings.settings[i] = CONTENT_SETTING_ALLOW;
+ settings.settings[CONTENT_SETTINGS_TYPE_JAVASCRIPT] = CONTENT_SETTING_BLOCK;
+ ContentSettingsObserver* observer = ContentSettingsObserver::Get(view_);
+ observer->SetContentSettings(settings);
+
+ // Make sure no pending messages are in the queue.
+ ProcessPendingMessages();
+ render_thread_.sink().ClearMessages();
+
+ // 3. Reload page.
+ ViewMsg_Navigate_Params params;
+ std::string url_str = "data:text/html;charset=utf-8,";
+ url_str.append(html);
+ GURL url(url_str);
+ params.url = url;
+ params.navigation_type = ViewMsg_Navigate_Type::RELOAD;
+ view_->OnNavigate(params);
+ ProcessPendingMessages();
+
+ // 4. Verify that the notification that javascript was blocked is sent after
+ // the navigation notifiction is sent.
+ int navigation_index = -1;
+ int block_index = -1;
+ for (size_t i = 0; i < render_thread_.sink().message_count(); ++i) {
+ const IPC::Message* msg = render_thread_.sink().GetMessageAt(i);
+ if (msg->type() == ViewHostMsg_FrameNavigate::ID)
+ navigation_index = i;
+ if (msg->type() == ViewHostMsg_ContentBlocked::ID)
+ block_index = i;
+ }
+ EXPECT_NE(-1, navigation_index);
+ EXPECT_NE(-1, block_index);
+ EXPECT_LT(navigation_index, block_index);
+}