forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
jam@chromium.org
committed
Apr 18, 2011
1 parent
f3f4d7f
commit 5e56df8
Showing
11 changed files
with
399 additions
and
195 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} |
Oops, something went wrong.