| 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 |