Fixed service side implementation of glTexStorage2DEXT to only initialize the number of
[chromium-blink-merge.git] / chrome / renderer / content_settings_observer.cc
blob246d831bf05644e46a13d2ad0e8fc0327771ad7a
1 // Copyright (c) 2011 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 "chrome/common/render_messages.h"
8 #include "chrome/common/url_constants.h"
9 #include "content/public/renderer/document_state.h"
10 #include "content/public/renderer/navigation_state.h"
11 #include "content/public/renderer/render_view.h"
12 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDataSource.h"
13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
15 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrameClient.h"
16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
17 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURL.h"
18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
20 using WebKit::WebDataSource;
21 using WebKit::WebFrame;
22 using WebKit::WebFrameClient;
23 using WebKit::WebSecurityOrigin;
24 using WebKit::WebString;
25 using WebKit::WebURL;
26 using WebKit::WebView;
27 using content::DocumentState;
28 using content::NavigationState;
30 namespace {
32 GURL GetOriginOrURL(const WebFrame* frame) {
33 WebString top_origin = frame->top()->document().securityOrigin().toString();
34 // The the |top_origin| is unique ("null") e.g., for file:// URLs. Use the
35 // document URL as the primary URL in those cases.
36 if (top_origin == "null")
37 return frame->top()->document().url();
38 return GURL(top_origin);
41 ContentSetting GetContentSettingFromRules(
42 const ContentSettingsForOneType& rules,
43 const WebFrame* frame,
44 const GURL& secondary_url) {
45 ContentSettingsForOneType::const_iterator it;
46 // If there is only one rule, it's the default rule and we don't need to match
47 // the patterns.
48 if (rules.size() == 1) {
49 DCHECK(rules[0].primary_pattern == ContentSettingsPattern::Wildcard());
50 DCHECK(rules[0].secondary_pattern == ContentSettingsPattern::Wildcard());
51 return rules[0].setting;
53 const GURL& primary_url = GetOriginOrURL(frame);
54 for (it = rules.begin(); it != rules.end(); ++it) {
55 if (it->primary_pattern.Matches(primary_url) &&
56 it->secondary_pattern.Matches(secondary_url)) {
57 return it->setting;
60 NOTREACHED();
61 return CONTENT_SETTING_DEFAULT;
64 } // namespace
66 ContentSettingsObserver::ContentSettingsObserver(
67 content::RenderView* render_view)
68 : content::RenderViewObserver(render_view),
69 content::RenderViewObserverTracker<ContentSettingsObserver>(render_view),
70 content_setting_rules_(NULL),
71 plugins_temporarily_allowed_(false),
72 is_interstitial_page_(false) {
73 ClearBlockedContentSettings();
76 ContentSettingsObserver::~ContentSettingsObserver() {
79 void ContentSettingsObserver::SetContentSettingRules(
80 const RendererContentSettingRules* content_setting_rules) {
81 content_setting_rules_ = content_setting_rules;
84 void ContentSettingsObserver::DidBlockContentType(
85 ContentSettingsType settings_type,
86 const std::string& resource_identifier) {
87 // Always send a message when |resource_identifier| is not empty, to tell the
88 // browser which resource was blocked (otherwise the browser will only show
89 // the first resource to be blocked, and none that are blocked at a later
90 // time).
91 if (!content_blocked_[settings_type] || !resource_identifier.empty()) {
92 content_blocked_[settings_type] = true;
93 Send(new ChromeViewHostMsg_ContentBlocked(routing_id(), settings_type,
94 resource_identifier));
98 bool ContentSettingsObserver::OnMessageReceived(const IPC::Message& message) {
99 bool handled = true;
100 IPC_BEGIN_MESSAGE_MAP(ContentSettingsObserver, message)
101 // Don't swallow LoadBlockedPlugins messages, as they're sent to every
102 // blocked plugin.
103 IPC_MESSAGE_HANDLER_GENERIC(ChromeViewMsg_LoadBlockedPlugins,
104 OnLoadBlockedPlugins(); handled = false)
105 IPC_MESSAGE_UNHANDLED(handled = false)
106 IPC_END_MESSAGE_MAP()
107 return handled;
110 void ContentSettingsObserver::DidCommitProvisionalLoad(
111 WebFrame* frame, bool is_new_navigation) {
112 if (frame->parent())
113 return; // Not a top-level navigation.
115 DocumentState* document_state = DocumentState::FromDataSource(
116 frame->dataSource());
117 NavigationState* navigation_state = document_state->navigation_state();
118 if (!navigation_state->was_within_same_page()) {
119 // Clear "block" flags for the new page. This needs to happen before any of
120 // |AllowScript()|, |AllowScriptFromSource()|, |AllowImage()|, or
121 // |AllowPlugins()| is called for the new page so that these functions can
122 // correctly detect that a piece of content flipped from "not blocked" to
123 // "blocked".
124 ClearBlockedContentSettings();
125 plugins_temporarily_allowed_ = false;
128 GURL url = frame->document().url();
129 // If we start failing this DCHECK, please makes sure we don't regress
130 // this bug: http://code.google.com/p/chromium/issues/detail?id=79304
131 DCHECK(frame->document().securityOrigin().toString() == "null" ||
132 !url.SchemeIs(chrome::kDataScheme));
135 bool ContentSettingsObserver::AllowDatabase(WebFrame* frame,
136 const WebString& name,
137 const WebString& display_name,
138 unsigned long estimated_size) {
139 if (frame->document().securityOrigin().isUnique() ||
140 frame->top()->document().securityOrigin().isUnique())
141 return false;
143 bool result = false;
144 Send(new ChromeViewHostMsg_AllowDatabase(
145 routing_id(), GURL(frame->document().securityOrigin().toString()),
146 GURL(frame->top()->document().securityOrigin().toString()),
147 name, display_name, &result));
148 return result;
151 bool ContentSettingsObserver::AllowFileSystem(WebFrame* frame) {
152 if (frame->document().securityOrigin().isUnique() ||
153 frame->top()->document().securityOrigin().isUnique())
154 return false;
156 bool result = false;
157 Send(new ChromeViewHostMsg_AllowFileSystem(
158 routing_id(), GURL(frame->document().securityOrigin().toString()),
159 GURL(frame->top()->document().securityOrigin().toString()), &result));
160 return result;
163 bool ContentSettingsObserver::AllowImage(WebFrame* frame,
164 bool enabled_per_settings,
165 const WebURL& image_url) {
166 if (is_interstitial_page_)
167 return true;
168 if (IsWhitelistedForContentSettings(frame))
169 return true;
171 bool allow = enabled_per_settings;
172 if (content_setting_rules_ && enabled_per_settings) {
173 GURL secondary_url(image_url);
174 allow = GetContentSettingFromRules(
175 content_setting_rules_->image_rules,
176 frame, secondary_url) != CONTENT_SETTING_BLOCK;
179 if (!allow)
180 DidBlockContentType(CONTENT_SETTINGS_TYPE_IMAGES, std::string());
181 return allow;
184 bool ContentSettingsObserver::AllowIndexedDB(WebFrame* frame,
185 const WebString& name,
186 const WebSecurityOrigin& origin) {
187 if (frame->document().securityOrigin().isUnique() ||
188 frame->top()->document().securityOrigin().isUnique())
189 return false;
191 bool result = false;
192 Send(new ChromeViewHostMsg_AllowIndexedDB(
193 routing_id(), GURL(frame->document().securityOrigin().toString()),
194 GURL(frame->top()->document().securityOrigin().toString()),
195 name, &result));
196 return result;
199 bool ContentSettingsObserver::AllowPlugins(WebFrame* frame,
200 bool enabled_per_settings) {
201 return enabled_per_settings;
204 bool ContentSettingsObserver::AllowScript(WebFrame* frame,
205 bool enabled_per_settings) {
206 if (is_interstitial_page_)
207 return true;
208 if (!enabled_per_settings)
209 return false;
211 std::map<WebFrame*, bool>::const_iterator it =
212 cached_script_permissions_.find(frame);
213 if (it != cached_script_permissions_.end())
214 return it->second;
216 // Evaluate the content setting rules before
217 // |IsWhitelistedForContentSettings|; if there is only the default rule
218 // allowing all scripts, it's quicker this way.
219 bool allow = true;
220 if (content_setting_rules_) {
221 ContentSetting setting = GetContentSettingFromRules(
222 content_setting_rules_->script_rules,
223 frame,
224 GURL(frame->document().securityOrigin().toString()));
225 allow = setting != CONTENT_SETTING_BLOCK;
227 allow = allow || IsWhitelistedForContentSettings(frame);
229 cached_script_permissions_[frame] = allow;
230 return allow;
233 bool ContentSettingsObserver::AllowScriptFromSource(
234 WebFrame* frame,
235 bool enabled_per_settings,
236 const WebKit::WebURL& script_url) {
237 if (is_interstitial_page_)
238 return true;
239 if (!enabled_per_settings)
240 return false;
242 bool allow = true;
243 if (content_setting_rules_) {
244 ContentSetting setting = GetContentSettingFromRules(
245 content_setting_rules_->script_rules,
246 frame,
247 GURL(script_url));
248 allow = setting != CONTENT_SETTING_BLOCK;
250 return allow || IsWhitelistedForContentSettings(frame);
253 bool ContentSettingsObserver::AllowStorage(WebFrame* frame, bool local) {
254 if (frame->document().securityOrigin().isUnique() ||
255 frame->top()->document().securityOrigin().isUnique())
256 return false;
257 bool result = false;
259 StoragePermissionsKey key(
260 GURL(frame->document().securityOrigin().toString()), local);
261 std::map<StoragePermissionsKey, bool>::const_iterator permissions =
262 cached_storage_permissions_.find(key);
263 if (permissions != cached_storage_permissions_.end())
264 return permissions->second;
266 Send(new ChromeViewHostMsg_AllowDOMStorage(
267 routing_id(), GURL(frame->document().securityOrigin().toString()),
268 GURL(frame->top()->document().securityOrigin().toString()),
269 local, &result));
270 cached_storage_permissions_[key] = result;
271 return result;
274 void ContentSettingsObserver::DidNotAllowPlugins(WebFrame* frame) {
275 DidBlockContentType(CONTENT_SETTINGS_TYPE_PLUGINS, std::string());
278 void ContentSettingsObserver::DidNotAllowScript(WebFrame* frame) {
279 DidBlockContentType(CONTENT_SETTINGS_TYPE_JAVASCRIPT, std::string());
282 void ContentSettingsObserver::SetAsInterstitial() {
283 is_interstitial_page_ = true;
286 void ContentSettingsObserver::OnLoadBlockedPlugins() {
287 plugins_temporarily_allowed_ = true;
290 void ContentSettingsObserver::ClearBlockedContentSettings() {
291 for (size_t i = 0; i < arraysize(content_blocked_); ++i)
292 content_blocked_[i] = false;
293 cached_storage_permissions_.clear();
294 cached_script_permissions_.clear();
297 bool ContentSettingsObserver::IsWhitelistedForContentSettings(WebFrame* frame) {
298 return IsWhitelistedForContentSettings(frame->document().securityOrigin(),
299 frame->document().url());
302 bool ContentSettingsObserver::IsWhitelistedForContentSettings(
303 const WebSecurityOrigin& origin,
304 const GURL& document_url) {
305 if (origin.isUnique())
306 return false; // Uninitialized document?
308 if (EqualsASCII(origin.protocol(), chrome::kChromeUIScheme))
309 return true; // Browser UI elements should still work.
311 if (EqualsASCII(origin.protocol(), chrome::kChromeDevToolsScheme))
312 return true; // DevTools UI elements should still work.
314 if (EqualsASCII(origin.protocol(), chrome::kExtensionScheme))
315 return true;
317 if (EqualsASCII(origin.protocol(), chrome::kChromeInternalScheme))
318 return true;
320 // If the scheme is ftp: or file:, an empty file name indicates a directory
321 // listing, which requires JavaScript to function properly.
322 const char* kDirProtocols[] = { chrome::kFtpScheme, chrome::kFileScheme };
323 for (size_t i = 0; i < arraysize(kDirProtocols); ++i) {
324 if (EqualsASCII(origin.protocol(), kDirProtocols[i])) {
325 return document_url.SchemeIs(kDirProtocols[i]) &&
326 document_url.ExtractFileName().empty();
330 return false;