OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/renderer/content_settings_observer.h" | 5 #include "chrome/renderer/content_settings_observer.h" |
6 | 6 |
7 #include "chrome/common/render_messages.h" | 7 #include "chrome/common/render_messages.h" |
8 #include "chrome/common/url_constants.h" | 8 #include "chrome/common/url_constants.h" |
9 #include "content/public/renderer/navigation_state.h" | 9 #include "content/public/renderer/navigation_state.h" |
10 #include "content/public/renderer/render_view.h" | 10 #include "content/public/renderer/render_view.h" |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
51 } | 51 } |
52 | 52 |
53 return false; | 53 return false; |
54 } | 54 } |
55 | 55 |
56 GURL GetOriginOrURL(const WebFrame* frame) { | 56 GURL GetOriginOrURL(const WebFrame* frame) { |
57 WebString top_origin = frame->top()->document().securityOrigin().toString(); | 57 WebString top_origin = frame->top()->document().securityOrigin().toString(); |
58 // The the |top_origin| is unique ("null") e.g., for file:// URLs. Use the | 58 // The the |top_origin| is unique ("null") e.g., for file:// URLs. Use the |
59 // document URL as the primary URL in those cases. | 59 // document URL as the primary URL in those cases. |
60 if (top_origin == "null") | 60 if (top_origin == "null") |
61 return frame->document().url(); | 61 return frame->top()->document().url(); |
62 return GURL(top_origin); | 62 return GURL(top_origin); |
63 } | 63 } |
64 | 64 |
| 65 ContentSetting GetContentSettingFromRules( |
| 66 const ContentSettingsForOneType& rules, |
| 67 const WebFrame* frame, |
| 68 const GURL& secondary_url) { |
| 69 ContentSettingsForOneType::const_iterator it; |
| 70 // If there is only one rule, it's the default rule and we don't need to match |
| 71 // the patterns. |
| 72 if (rules.size() == 1) { |
| 73 DCHECK(rules[0].primary_pattern == ContentSettingsPattern::Wildcard()); |
| 74 DCHECK(rules[0].secondary_pattern == ContentSettingsPattern::Wildcard()); |
| 75 return rules[0].setting; |
| 76 } |
| 77 const GURL& primary_url = GetOriginOrURL(frame); |
| 78 for (it = rules.begin(); it != rules.end(); ++it) { |
| 79 if (it->primary_pattern.Matches(primary_url) && |
| 80 it->secondary_pattern.Matches(secondary_url)) { |
| 81 return it->setting; |
| 82 } |
| 83 } |
| 84 NOTREACHED(); |
| 85 return CONTENT_SETTING_DEFAULT; |
| 86 } |
| 87 |
65 } // namespace | 88 } // namespace |
66 | 89 |
67 ContentSettingsObserver::ContentSettingsObserver( | 90 ContentSettingsObserver::ContentSettingsObserver( |
68 content::RenderView* render_view) | 91 content::RenderView* render_view) |
69 : content::RenderViewObserver(render_view), | 92 : content::RenderViewObserver(render_view), |
70 content::RenderViewObserverTracker<ContentSettingsObserver>(render_view), | 93 content::RenderViewObserverTracker<ContentSettingsObserver>(render_view), |
71 default_content_settings_(NULL), | 94 content_setting_rules_(NULL), |
72 image_setting_rules_(NULL), | |
73 plugins_temporarily_allowed_(false) { | 95 plugins_temporarily_allowed_(false) { |
74 ClearBlockedContentSettings(); | 96 ClearBlockedContentSettings(); |
75 } | 97 } |
76 | 98 |
77 ContentSettingsObserver::~ContentSettingsObserver() { | 99 ContentSettingsObserver::~ContentSettingsObserver() { |
78 } | 100 } |
79 | 101 |
80 void ContentSettingsObserver::SetContentSettings( | 102 void ContentSettingsObserver::SetContentSettingRules( |
81 const ContentSettings& settings) { | 103 const RendererContentSettingRules* content_setting_rules) { |
82 current_content_settings_ = settings; | 104 content_setting_rules_ = content_setting_rules; |
83 } | |
84 | |
85 void ContentSettingsObserver::SetDefaultContentSettings( | |
86 const ContentSettings* settings) { | |
87 default_content_settings_ = settings; | |
88 } | |
89 | |
90 void ContentSettingsObserver::SetImageSettingRules( | |
91 const ContentSettingsForOneType* image_setting_rules) { | |
92 image_setting_rules_ = image_setting_rules; | |
93 } | |
94 | |
95 ContentSetting ContentSettingsObserver::GetContentSetting( | |
96 ContentSettingsType type) { | |
97 // Don't call this for plug-ins. | |
98 DCHECK_NE(CONTENT_SETTINGS_TYPE_PLUGINS, type); | |
99 return current_content_settings_.settings[type]; | |
100 } | 105 } |
101 | 106 |
102 void ContentSettingsObserver::DidBlockContentType( | 107 void ContentSettingsObserver::DidBlockContentType( |
103 ContentSettingsType settings_type, | 108 ContentSettingsType settings_type, |
104 const std::string& resource_identifier) { | 109 const std::string& resource_identifier) { |
105 // Always send a message when |resource_identifier| is not empty, to tell the | 110 // Always send a message when |resource_identifier| is not empty, to tell the |
106 // browser which resource was blocked (otherwise the browser will only show | 111 // browser which resource was blocked (otherwise the browser will only show |
107 // the first resource to be blocked, and none that are blocked at a later | 112 // the first resource to be blocked, and none that are blocked at a later |
108 // time). | 113 // time). |
109 if (!content_blocked_[settings_type] || !resource_identifier.empty()) { | 114 if (!content_blocked_[settings_type] || !resource_identifier.empty()) { |
110 content_blocked_[settings_type] = true; | 115 content_blocked_[settings_type] = true; |
111 Send(new ChromeViewHostMsg_ContentBlocked(routing_id(), settings_type, | 116 Send(new ChromeViewHostMsg_ContentBlocked(routing_id(), settings_type, |
112 resource_identifier)); | 117 resource_identifier)); |
113 } | 118 } |
114 } | 119 } |
115 | 120 |
116 bool ContentSettingsObserver::OnMessageReceived(const IPC::Message& message) { | 121 bool ContentSettingsObserver::OnMessageReceived(const IPC::Message& message) { |
117 bool handled = true; | 122 bool handled = true; |
118 IPC_BEGIN_MESSAGE_MAP(ContentSettingsObserver, message) | 123 IPC_BEGIN_MESSAGE_MAP(ContentSettingsObserver, message) |
119 // Don't swallow LoadBlockedPlugins messages, as they're sent to every | 124 // Don't swallow LoadBlockedPlugins messages, as they're sent to every |
120 // blocked plugin. | 125 // blocked plugin. |
121 IPC_MESSAGE_HANDLER_GENERIC(ChromeViewMsg_LoadBlockedPlugins, | 126 IPC_MESSAGE_HANDLER_GENERIC(ChromeViewMsg_LoadBlockedPlugins, |
122 OnLoadBlockedPlugins(); handled = false) | 127 OnLoadBlockedPlugins(); handled = false) |
123 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetContentSettingsForLoadingURL, | |
124 OnSetContentSettingsForLoadingURL) | |
125 IPC_MESSAGE_UNHANDLED(handled = false) | 128 IPC_MESSAGE_UNHANDLED(handled = false) |
126 IPC_END_MESSAGE_MAP() | 129 IPC_END_MESSAGE_MAP() |
127 return handled; | 130 return handled; |
128 } | 131 } |
129 | 132 |
130 void ContentSettingsObserver::DidCommitProvisionalLoad( | 133 void ContentSettingsObserver::DidCommitProvisionalLoad( |
131 WebFrame* frame, bool is_new_navigation) { | 134 WebFrame* frame, bool is_new_navigation) { |
132 if (frame->parent()) | 135 if (frame->parent()) |
133 return; // Not a top-level navigation. | 136 return; // Not a top-level navigation. |
134 | 137 |
135 NavigationState* state = NavigationState::FromDataSource(frame->dataSource()); | 138 NavigationState* state = NavigationState::FromDataSource(frame->dataSource()); |
136 if (!state->was_within_same_page()) { | 139 if (!state->was_within_same_page()) { |
137 // Clear "block" flags for the new page. This needs to happen before any of | 140 // Clear "block" flags for the new page. This needs to happen before any of |
138 // allowScripts(), allowImage(), allowPlugins() is called for the new page | 141 // |AllowScript()|, |AllowScriptFromSource()|, |AllowImage()|, or |
139 // so that these functions can correctly detect that a piece of content | 142 // |AllowPlugins()| is called for the new page so that these functions can |
140 // flipped from "not blocked" to "blocked". | 143 // correctly detect that a piece of content flipped from "not blocked" to |
| 144 // "blocked". |
141 ClearBlockedContentSettings(); | 145 ClearBlockedContentSettings(); |
142 plugins_temporarily_allowed_ = false; | 146 plugins_temporarily_allowed_ = false; |
143 } | 147 } |
144 | 148 |
145 GURL url = frame->document().url(); | 149 GURL url = frame->document().url(); |
146 | |
147 if (frame->document().securityOrigin().toString() == "null" && | |
148 !url.SchemeIs(chrome::kFileScheme)) { | |
149 // The Frame has a unique security origin. Instead of granting the frame | |
150 // privileges based on it's URL, we fall back to the default content | |
151 // settings. | |
152 | |
153 // We exempt file URLs here because we sandbox them by default, but folks | |
154 // might reasonably want to supply non-default content settings for various | |
155 // file URLs. | |
156 if (default_content_settings_) | |
157 SetContentSettings(*default_content_settings_); | |
158 return; | |
159 } | |
160 | |
161 // If we start failing this DCHECK, please makes sure we don't regress | 150 // If we start failing this DCHECK, please makes sure we don't regress |
162 // this bug: http://code.google.com/p/chromium/issues/detail?id=79304 | 151 // this bug: http://code.google.com/p/chromium/issues/detail?id=79304 |
163 DCHECK(!url.SchemeIs(chrome::kDataScheme)); | 152 DCHECK(frame->document().securityOrigin().toString() == "null" || |
164 | 153 !url.SchemeIs(chrome::kDataScheme)); |
165 // Set content settings. Default them from the parent window if one exists. | |
166 // This makes sure about:blank windows work as expected. | |
167 HostContentSettings::iterator host_content_settings = | |
168 host_content_settings_.find(url); | |
169 if (host_content_settings != host_content_settings_.end()) { | |
170 SetContentSettings(host_content_settings->second); | |
171 | |
172 // These content settings were merely recorded transiently for this load. | |
173 // We can erase them now. If at some point we reload this page, the | |
174 // browser will send us new, up-to-date content settings. | |
175 host_content_settings_.erase(host_content_settings); | |
176 } else if (frame->opener()) { | |
177 // The opener's view is not guaranteed to be non-null (it could be | |
178 // detached from its page but not yet destructed). | |
179 if (WebView* opener_view = frame->opener()->view()) { | |
180 content::RenderView* opener = | |
181 content::RenderView::FromWebView(opener_view); | |
182 ContentSettingsObserver* observer = ContentSettingsObserver::Get(opener); | |
183 SetContentSettings(observer->current_content_settings_); | |
184 } | |
185 } | |
186 } | 154 } |
187 | 155 |
188 bool ContentSettingsObserver::AllowDatabase(WebFrame* frame, | 156 bool ContentSettingsObserver::AllowDatabase(WebFrame* frame, |
189 const WebString& name, | 157 const WebString& name, |
190 const WebString& display_name, | 158 const WebString& display_name, |
191 unsigned long estimated_size) { | 159 unsigned long estimated_size) { |
192 if (frame->document().securityOrigin().isEmpty() || | 160 if (frame->document().securityOrigin().isEmpty() || |
193 frame->top()->document().securityOrigin().isEmpty()) | 161 frame->top()->document().securityOrigin().isEmpty()) |
194 return false; // Uninitialized document. | 162 return false; // Uninitialized document. |
195 | 163 |
(...skipping 17 matching lines...) Expand all Loading... |
213 return result; | 181 return result; |
214 } | 182 } |
215 | 183 |
216 bool ContentSettingsObserver::AllowImage(WebFrame* frame, | 184 bool ContentSettingsObserver::AllowImage(WebFrame* frame, |
217 bool enabled_per_settings, | 185 bool enabled_per_settings, |
218 const WebURL& image_url) { | 186 const WebURL& image_url) { |
219 if (IsWhitelistedForContentSettings(frame)) | 187 if (IsWhitelistedForContentSettings(frame)) |
220 return true; | 188 return true; |
221 | 189 |
222 bool allow = enabled_per_settings; | 190 bool allow = enabled_per_settings; |
223 const GURL& primary_url = GetOriginOrURL(frame); | 191 if (content_setting_rules_ && enabled_per_settings) { |
224 GURL secondary_url(image_url); | 192 GURL secondary_url(image_url); |
225 if (image_setting_rules_ && | 193 allow = GetContentSettingFromRules( |
226 enabled_per_settings) { | 194 content_setting_rules_->image_rules, |
227 ContentSettingsForOneType::const_iterator it; | 195 frame, secondary_url) != CONTENT_SETTING_BLOCK; |
228 for (it = image_setting_rules_->begin(); | |
229 it != image_setting_rules_->end(); ++it) { | |
230 if (it->primary_pattern.Matches(primary_url) && | |
231 it->secondary_pattern.Matches(secondary_url)) { | |
232 allow = (it->setting != CONTENT_SETTING_BLOCK); | |
233 break; | |
234 } | |
235 } | |
236 } | 196 } |
237 | 197 |
238 if (!allow) | 198 if (!allow) |
239 DidBlockContentType(CONTENT_SETTINGS_TYPE_IMAGES, std::string()); | 199 DidBlockContentType(CONTENT_SETTINGS_TYPE_IMAGES, std::string()); |
240 return allow; | 200 return allow; |
241 } | 201 } |
242 | 202 |
243 bool ContentSettingsObserver::AllowIndexedDB(WebFrame* frame, | 203 bool ContentSettingsObserver::AllowIndexedDB(WebFrame* frame, |
244 const WebString& name, | 204 const WebString& name, |
245 const WebSecurityOrigin& origin) { | 205 const WebSecurityOrigin& origin) { |
246 if (frame->document().securityOrigin().isEmpty() || | 206 if (frame->document().securityOrigin().isEmpty() || |
247 frame->top()->document().securityOrigin().isEmpty()) | 207 frame->top()->document().securityOrigin().isEmpty()) |
248 return false; // Uninitialized document. | 208 return false; // Uninitialized document. |
249 | 209 |
250 bool result = false; | 210 bool result = false; |
251 Send(new ChromeViewHostMsg_AllowIndexedDB( | 211 Send(new ChromeViewHostMsg_AllowIndexedDB( |
252 routing_id(), GURL(frame->document().securityOrigin().toString()), | 212 routing_id(), GURL(frame->document().securityOrigin().toString()), |
253 GURL(frame->top()->document().securityOrigin().toString()), | 213 GURL(frame->top()->document().securityOrigin().toString()), |
254 name, &result)); | 214 name, &result)); |
255 return result; | 215 return result; |
256 } | 216 } |
257 | 217 |
258 bool ContentSettingsObserver::AllowPlugins(WebFrame* frame, | 218 bool ContentSettingsObserver::AllowPlugins(WebFrame* frame, |
259 bool enabled_per_settings) { | 219 bool enabled_per_settings) { |
260 return enabled_per_settings; | 220 return enabled_per_settings; |
261 } | 221 } |
262 | 222 |
263 bool ContentSettingsObserver::AllowScript(WebFrame* frame, | 223 bool ContentSettingsObserver::AllowScript(WebFrame* frame, |
264 bool enabled_per_settings) { | 224 bool enabled_per_settings) { |
265 if (enabled_per_settings && | 225 if (!enabled_per_settings) |
266 AllowContentType(CONTENT_SETTINGS_TYPE_JAVASCRIPT)) { | 226 return false; |
267 return true; | 227 |
| 228 std::map<WebFrame*, bool>::const_iterator it = |
| 229 cached_script_permissions_.find(frame); |
| 230 if (it != cached_script_permissions_.end()) |
| 231 return it->second; |
| 232 |
| 233 // Evaluate the content setting rules before |
| 234 // |IsWhitelistedForContentSettings|; if there is only the default rule |
| 235 // allowing all scripts, it's quicker this way. |
| 236 bool allow = true; |
| 237 if (content_setting_rules_) { |
| 238 ContentSetting setting = GetContentSettingFromRules( |
| 239 content_setting_rules_->script_rules, |
| 240 frame, |
| 241 GURL(frame->document().securityOrigin().toString())); |
| 242 allow = setting != CONTENT_SETTING_BLOCK; |
268 } | 243 } |
| 244 allow = allow || IsWhitelistedForContentSettings(frame); |
269 | 245 |
270 if (IsWhitelistedForContentSettings(frame)) | 246 cached_script_permissions_[frame] = allow; |
271 return true; | 247 return allow; |
| 248 } |
272 | 249 |
273 return false; // Other protocols fall through here. | 250 bool ContentSettingsObserver::AllowScriptFromSource( |
| 251 WebFrame* frame, |
| 252 bool enabled_per_settings, |
| 253 const WebKit::WebURL& script_url) { |
| 254 if (!enabled_per_settings) |
| 255 return false; |
| 256 |
| 257 bool allow = true; |
| 258 if (content_setting_rules_) { |
| 259 ContentSetting setting = GetContentSettingFromRules( |
| 260 content_setting_rules_->script_rules, |
| 261 frame, |
| 262 GURL(script_url)); |
| 263 allow = setting != CONTENT_SETTING_BLOCK; |
| 264 } |
| 265 return allow || IsWhitelistedForContentSettings(frame); |
274 } | 266 } |
275 | 267 |
276 bool ContentSettingsObserver::AllowStorage(WebFrame* frame, bool local) { | 268 bool ContentSettingsObserver::AllowStorage(WebFrame* frame, bool local) { |
277 if (frame->document().securityOrigin().isEmpty() || | 269 if (frame->document().securityOrigin().isEmpty() || |
278 frame->top()->document().securityOrigin().isEmpty()) | 270 frame->top()->document().securityOrigin().isEmpty()) |
279 return false; // Uninitialized document. | 271 return false; // Uninitialized document. |
280 bool result = false; | 272 bool result = false; |
281 | 273 |
282 StoragePermissionsKey key( | 274 StoragePermissionsKey key( |
283 GURL(frame->document().securityOrigin().toString()), local); | 275 GURL(frame->document().securityOrigin().toString()), local); |
(...skipping 12 matching lines...) Expand all Loading... |
296 } | 288 } |
297 | 289 |
298 void ContentSettingsObserver::DidNotAllowPlugins(WebFrame* frame) { | 290 void ContentSettingsObserver::DidNotAllowPlugins(WebFrame* frame) { |
299 DidBlockContentType(CONTENT_SETTINGS_TYPE_PLUGINS, std::string()); | 291 DidBlockContentType(CONTENT_SETTINGS_TYPE_PLUGINS, std::string()); |
300 } | 292 } |
301 | 293 |
302 void ContentSettingsObserver::DidNotAllowScript(WebFrame* frame) { | 294 void ContentSettingsObserver::DidNotAllowScript(WebFrame* frame) { |
303 DidBlockContentType(CONTENT_SETTINGS_TYPE_JAVASCRIPT, std::string()); | 295 DidBlockContentType(CONTENT_SETTINGS_TYPE_JAVASCRIPT, std::string()); |
304 } | 296 } |
305 | 297 |
306 void ContentSettingsObserver::OnSetContentSettingsForLoadingURL( | |
307 const GURL& url, | |
308 const ContentSettings& content_settings) { | |
309 host_content_settings_[url] = content_settings; | |
310 } | |
311 | |
312 void ContentSettingsObserver::OnLoadBlockedPlugins() { | 298 void ContentSettingsObserver::OnLoadBlockedPlugins() { |
313 plugins_temporarily_allowed_ = true; | 299 plugins_temporarily_allowed_ = true; |
314 } | 300 } |
315 | 301 |
316 bool ContentSettingsObserver::AllowContentType( | |
317 ContentSettingsType settings_type) { | |
318 // CONTENT_SETTING_ASK is only valid for cookies. | |
319 return current_content_settings_.settings[settings_type] != | |
320 CONTENT_SETTING_BLOCK; | |
321 } | |
322 | |
323 void ContentSettingsObserver::ClearBlockedContentSettings() { | 302 void ContentSettingsObserver::ClearBlockedContentSettings() { |
324 for (size_t i = 0; i < arraysize(content_blocked_); ++i) | 303 for (size_t i = 0; i < arraysize(content_blocked_); ++i) |
325 content_blocked_[i] = false; | 304 content_blocked_[i] = false; |
326 cached_storage_permissions_.clear(); | 305 cached_storage_permissions_.clear(); |
| 306 cached_script_permissions_.clear(); |
327 } | 307 } |
OLD | NEW |