two_phase_testserver.py: Remove unnecessary method override.
[chromium-blink-merge.git] / chrome / renderer / content_settings_observer.cc
blobfb8ddf8a8bb216b7d7a71d1c0c7acda56d8187a2
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/renderer/content_settings_observer.h"
7 #include "base/command_line.h"
8 #include "chrome/common/chrome_switches.h"
9 #include "chrome/common/render_messages.h"
10 #include "chrome/common/url_constants.h"
11 #include "content/public/renderer/document_state.h"
12 #include "content/public/renderer/navigation_state.h"
13 #include "content/public/renderer/render_view.h"
14 #include "extensions/common/constants.h"
15 #include "third_party/WebKit/public/platform/WebURL.h"
16 #include "third_party/WebKit/public/web/WebDataSource.h"
17 #include "third_party/WebKit/public/web/WebDocument.h"
18 #include "third_party/WebKit/public/web/WebFrame.h"
19 #include "third_party/WebKit/public/web/WebFrameClient.h"
20 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
21 #include "third_party/WebKit/public/web/WebView.h"
22 #include "webkit/child/weburlresponse_extradata_impl.h"
24 using WebKit::WebDataSource;
25 using WebKit::WebFrame;
26 using WebKit::WebFrameClient;
27 using WebKit::WebSecurityOrigin;
28 using WebKit::WebString;
29 using WebKit::WebURL;
30 using WebKit::WebView;
31 using content::DocumentState;
32 using content::NavigationState;
34 namespace {
36 GURL GetOriginOrURL(const WebFrame* frame) {
37 WebString top_origin = frame->top()->document().securityOrigin().toString();
38 // The the |top_origin| is unique ("null") e.g., for file:// URLs. Use the
39 // document URL as the primary URL in those cases.
40 if (top_origin == "null")
41 return frame->top()->document().url();
42 return GURL(top_origin);
45 ContentSetting GetContentSettingFromRules(
46 const ContentSettingsForOneType& rules,
47 const WebFrame* frame,
48 const GURL& secondary_url) {
49 ContentSettingsForOneType::const_iterator it;
50 // If there is only one rule, it's the default rule and we don't need to match
51 // the patterns.
52 if (rules.size() == 1) {
53 DCHECK(rules[0].primary_pattern == ContentSettingsPattern::Wildcard());
54 DCHECK(rules[0].secondary_pattern == ContentSettingsPattern::Wildcard());
55 return rules[0].setting;
57 const GURL& primary_url = GetOriginOrURL(frame);
58 for (it = rules.begin(); it != rules.end(); ++it) {
59 if (it->primary_pattern.Matches(primary_url) &&
60 it->secondary_pattern.Matches(secondary_url)) {
61 return it->setting;
64 NOTREACHED();
65 return CONTENT_SETTING_DEFAULT;
68 } // namespace
70 ContentSettingsObserver::ContentSettingsObserver(
71 content::RenderView* render_view)
72 : content::RenderViewObserver(render_view),
73 content::RenderViewObserverTracker<ContentSettingsObserver>(render_view),
74 content_setting_rules_(NULL),
75 is_interstitial_page_(false),
76 npapi_plugins_blocked_(false) {
77 ClearBlockedContentSettings();
80 ContentSettingsObserver::~ContentSettingsObserver() {
83 void ContentSettingsObserver::SetContentSettingRules(
84 const RendererContentSettingRules* content_setting_rules) {
85 content_setting_rules_ = content_setting_rules;
88 bool ContentSettingsObserver::IsPluginTemporarilyAllowed(
89 const std::string& identifier) {
90 // If the empty string is in here, it means all plug-ins are allowed.
91 // TODO(bauerb): Remove this once we only pass in explicit identifiers.
92 return (temporarily_allowed_plugins_.find(identifier) !=
93 temporarily_allowed_plugins_.end()) ||
94 (temporarily_allowed_plugins_.find(std::string()) !=
95 temporarily_allowed_plugins_.end());
98 void ContentSettingsObserver::DidBlockContentType(
99 ContentSettingsType settings_type,
100 const std::string& resource_identifier) {
101 // Always send a message when |resource_identifier| is not empty, to tell the
102 // browser which resource was blocked (otherwise the browser will only show
103 // the first resource to be blocked, and none that are blocked at a later
104 // time).
105 if (!content_blocked_[settings_type] || !resource_identifier.empty()) {
106 content_blocked_[settings_type] = true;
107 Send(new ChromeViewHostMsg_ContentBlocked(routing_id(), settings_type,
108 resource_identifier));
112 bool ContentSettingsObserver::OnMessageReceived(const IPC::Message& message) {
113 bool handled = true;
114 IPC_BEGIN_MESSAGE_MAP(ContentSettingsObserver, message)
115 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetAsInterstitial, OnSetAsInterstitial)
116 IPC_MESSAGE_UNHANDLED(handled = false)
117 IPC_END_MESSAGE_MAP()
118 if (handled)
119 return true;
121 // Don't swallow LoadBlockedPlugins messages, as they're sent to every
122 // blocked plugin.
123 IPC_BEGIN_MESSAGE_MAP(ContentSettingsObserver, message)
124 IPC_MESSAGE_HANDLER(ChromeViewMsg_LoadBlockedPlugins, OnLoadBlockedPlugins)
125 IPC_END_MESSAGE_MAP()
127 return false;
130 void ContentSettingsObserver::DidCommitProvisionalLoad(
131 WebFrame* frame, bool is_new_navigation) {
132 if (frame->parent())
133 return; // Not a top-level navigation.
135 DocumentState* document_state = DocumentState::FromDataSource(
136 frame->dataSource());
137 NavigationState* navigation_state = document_state->navigation_state();
138 if (!navigation_state->was_within_same_page()) {
139 // Clear "block" flags for the new page. This needs to happen before any of
140 // |AllowScript()|, |AllowScriptFromSource()|, |AllowImage()|, or
141 // |AllowPlugins()| is called for the new page so that these functions can
142 // correctly detect that a piece of content flipped from "not blocked" to
143 // "blocked".
144 ClearBlockedContentSettings();
145 temporarily_allowed_plugins_.clear();
148 GURL url = frame->document().url();
149 // If we start failing this DCHECK, please makes sure we don't regress
150 // this bug: http://code.google.com/p/chromium/issues/detail?id=79304
151 DCHECK(frame->document().securityOrigin().toString() == "null" ||
152 !url.SchemeIs(chrome::kDataScheme));
155 bool ContentSettingsObserver::AllowDatabase(WebFrame* frame,
156 const WebString& name,
157 const WebString& display_name,
158 unsigned long estimated_size) {
159 if (frame->document().securityOrigin().isUnique() ||
160 frame->top()->document().securityOrigin().isUnique())
161 return false;
163 bool result = false;
164 Send(new ChromeViewHostMsg_AllowDatabase(
165 routing_id(), GURL(frame->document().securityOrigin().toString()),
166 GURL(frame->top()->document().securityOrigin().toString()),
167 name, display_name, &result));
168 return result;
171 bool ContentSettingsObserver::AllowFileSystem(WebFrame* frame) {
172 if (frame->document().securityOrigin().isUnique() ||
173 frame->top()->document().securityOrigin().isUnique())
174 return false;
176 bool result = false;
177 Send(new ChromeViewHostMsg_AllowFileSystem(
178 routing_id(), GURL(frame->document().securityOrigin().toString()),
179 GURL(frame->top()->document().securityOrigin().toString()), &result));
180 return result;
183 bool ContentSettingsObserver::AllowImage(WebFrame* frame,
184 bool enabled_per_settings,
185 const WebURL& image_url) {
186 bool allow = enabled_per_settings;
187 if (enabled_per_settings) {
188 if (is_interstitial_page_)
189 return true;
190 if (IsWhitelistedForContentSettings(frame))
191 return true;
193 if (content_setting_rules_) {
194 GURL secondary_url(image_url);
195 allow = GetContentSettingFromRules(
196 content_setting_rules_->image_rules,
197 frame, secondary_url) != CONTENT_SETTING_BLOCK;
200 if (!allow)
201 DidBlockContentType(CONTENT_SETTINGS_TYPE_IMAGES, std::string());
202 return allow;
205 bool ContentSettingsObserver::AllowIndexedDB(WebFrame* frame,
206 const WebString& name,
207 const WebSecurityOrigin& origin) {
208 if (frame->document().securityOrigin().isUnique() ||
209 frame->top()->document().securityOrigin().isUnique())
210 return false;
212 bool result = false;
213 Send(new ChromeViewHostMsg_AllowIndexedDB(
214 routing_id(), GURL(frame->document().securityOrigin().toString()),
215 GURL(frame->top()->document().securityOrigin().toString()),
216 name, &result));
217 return result;
220 bool ContentSettingsObserver::AllowPlugins(WebFrame* frame,
221 bool enabled_per_settings) {
222 return enabled_per_settings;
225 bool ContentSettingsObserver::AllowScript(WebFrame* frame,
226 bool enabled_per_settings) {
227 if (!enabled_per_settings)
228 return false;
229 if (is_interstitial_page_)
230 return true;
232 std::map<WebFrame*, bool>::const_iterator it =
233 cached_script_permissions_.find(frame);
234 if (it != cached_script_permissions_.end())
235 return it->second;
237 // Evaluate the content setting rules before
238 // |IsWhitelistedForContentSettings|; if there is only the default rule
239 // allowing all scripts, it's quicker this way.
240 bool allow = true;
241 if (content_setting_rules_) {
242 ContentSetting setting = GetContentSettingFromRules(
243 content_setting_rules_->script_rules,
244 frame,
245 GURL(frame->document().securityOrigin().toString()));
246 allow = setting != CONTENT_SETTING_BLOCK;
248 allow = allow || IsWhitelistedForContentSettings(frame);
250 cached_script_permissions_[frame] = allow;
251 return allow;
254 bool ContentSettingsObserver::AllowScriptFromSource(
255 WebFrame* frame,
256 bool enabled_per_settings,
257 const WebKit::WebURL& script_url) {
258 if (!enabled_per_settings)
259 return false;
260 if (is_interstitial_page_)
261 return true;
263 bool allow = true;
264 if (content_setting_rules_) {
265 ContentSetting setting = GetContentSettingFromRules(
266 content_setting_rules_->script_rules,
267 frame,
268 GURL(script_url));
269 allow = setting != CONTENT_SETTING_BLOCK;
271 return allow || IsWhitelistedForContentSettings(frame);
274 bool ContentSettingsObserver::AllowStorage(WebFrame* frame, bool local) {
275 if (frame->document().securityOrigin().isUnique() ||
276 frame->top()->document().securityOrigin().isUnique())
277 return false;
278 bool result = false;
280 StoragePermissionsKey key(
281 GURL(frame->document().securityOrigin().toString()), local);
282 std::map<StoragePermissionsKey, bool>::const_iterator permissions =
283 cached_storage_permissions_.find(key);
284 if (permissions != cached_storage_permissions_.end())
285 return permissions->second;
287 Send(new ChromeViewHostMsg_AllowDOMStorage(
288 routing_id(), GURL(frame->document().securityOrigin().toString()),
289 GURL(frame->top()->document().securityOrigin().toString()),
290 local, &result));
291 cached_storage_permissions_[key] = result;
292 return result;
295 void ContentSettingsObserver::DidNotAllowPlugins() {
296 DidBlockContentType(CONTENT_SETTINGS_TYPE_PLUGINS, std::string());
299 void ContentSettingsObserver::DidNotAllowScript() {
300 DidBlockContentType(CONTENT_SETTINGS_TYPE_JAVASCRIPT, std::string());
303 void ContentSettingsObserver::DidNotAllowMixedScript() {
304 DidBlockContentType(CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, std::string());
307 void ContentSettingsObserver::BlockNPAPIPlugins() {
308 npapi_plugins_blocked_ = true;
311 bool ContentSettingsObserver::AreNPAPIPluginsBlocked() const {
312 return npapi_plugins_blocked_;
315 void ContentSettingsObserver::OnLoadBlockedPlugins(
316 const std::string& identifier) {
317 temporarily_allowed_plugins_.insert(identifier);
320 void ContentSettingsObserver::OnSetAsInterstitial() {
321 is_interstitial_page_ = true;
324 void ContentSettingsObserver::ClearBlockedContentSettings() {
325 for (size_t i = 0; i < arraysize(content_blocked_); ++i)
326 content_blocked_[i] = false;
327 cached_storage_permissions_.clear();
328 cached_script_permissions_.clear();
331 bool ContentSettingsObserver::IsWhitelistedForContentSettings(WebFrame* frame) {
332 // Whitelist Instant processes.
333 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kInstantProcess))
334 return true;
336 // Whitelist ftp directory listings, as they require JavaScript to function
337 // properly.
338 webkit_glue::WebURLResponseExtraDataImpl* extra_data =
339 static_cast<webkit_glue::WebURLResponseExtraDataImpl*>(
340 frame->dataSource()->response().extraData());
341 if (extra_data && extra_data->is_ftp_directory_listing())
342 return true;
343 return IsWhitelistedForContentSettings(frame->document().securityOrigin(),
344 frame->document().url());
347 bool ContentSettingsObserver::IsWhitelistedForContentSettings(
348 const WebSecurityOrigin& origin,
349 const GURL& document_url) {
350 if (document_url == GURL(content::kUnreachableWebDataURL))
351 return true;
353 if (origin.isUnique())
354 return false; // Uninitialized document?
356 if (EqualsASCII(origin.protocol(), chrome::kChromeUIScheme))
357 return true; // Browser UI elements should still work.
359 if (EqualsASCII(origin.protocol(), chrome::kChromeDevToolsScheme))
360 return true; // DevTools UI elements should still work.
362 if (EqualsASCII(origin.protocol(), extensions::kExtensionScheme))
363 return true;
365 if (EqualsASCII(origin.protocol(), chrome::kChromeInternalScheme))
366 return true;
368 // If the scheme is file:, an empty file name indicates a directory listing,
369 // which requires JavaScript to function properly.
370 if (EqualsASCII(origin.protocol(), chrome::kFileScheme)) {
371 return document_url.SchemeIs(chrome::kFileScheme) &&
372 document_url.ExtractFileName().empty();
375 return false;