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. 4 5 #include "chrome/renderer/content_settings_observer.h" 6 7 #include "base/command_line.h" 8 #include "base/metrics/histogram.h" 9 #include "chrome/common/chrome_switches.h" 10 #include "chrome/common/render_messages.h" 11 #include "chrome/common/url_constants.h" 12 #include "content/public/renderer/document_state.h" 13 #include "content/public/renderer/navigation_state.h" 14 #include "content/public/renderer/render_frame.h" 15 #include "content/public/renderer/render_view.h" 16 #include "third_party/WebKit/public/platform/WebPermissionCallbacks.h" 17 #include "third_party/WebKit/public/platform/WebURL.h" 18 #include "third_party/WebKit/public/web/WebDataSource.h" 19 #include "third_party/WebKit/public/web/WebDocument.h" 20 #include "third_party/WebKit/public/web/WebFrameClient.h" 21 #include "third_party/WebKit/public/web/WebLocalFrame.h" 22 #include "third_party/WebKit/public/web/WebSecurityOrigin.h" 23 #include "third_party/WebKit/public/web/WebView.h" 24 25 #if defined(ENABLE_EXTENSIONS) 26 #include "chrome/common/extensions/chrome_extension_messages.h" 27 #include "extensions/common/constants.h" 28 #include "extensions/common/extension.h" 29 #include "extensions/common/permissions/api_permission.h" 30 #include "extensions/common/permissions/permissions_data.h" 31 #include "extensions/renderer/dispatcher.h" 32 #endif 33 34 using blink::WebDataSource; 35 using blink::WebDocument; 36 using blink::WebFrame; 37 using blink::WebPermissionCallbacks; 38 using blink::WebSecurityOrigin; 39 using blink::WebString; 40 using blink::WebURL; 41 using blink::WebView; 42 using content::DocumentState; 43 using content::NavigationState; 44 45 namespace { 46 47 enum { 48 INSECURE_CONTENT_DISPLAY = 0, 49 INSECURE_CONTENT_DISPLAY_HOST_GOOGLE, 50 INSECURE_CONTENT_DISPLAY_HOST_WWW_GOOGLE, 51 INSECURE_CONTENT_DISPLAY_HTML, 52 INSECURE_CONTENT_RUN, 53 INSECURE_CONTENT_RUN_HOST_GOOGLE, 54 INSECURE_CONTENT_RUN_HOST_WWW_GOOGLE, 55 INSECURE_CONTENT_RUN_TARGET_YOUTUBE, 56 INSECURE_CONTENT_RUN_JS, 57 INSECURE_CONTENT_RUN_CSS, 58 INSECURE_CONTENT_RUN_SWF, 59 INSECURE_CONTENT_DISPLAY_HOST_YOUTUBE, 60 INSECURE_CONTENT_RUN_HOST_YOUTUBE, 61 INSECURE_CONTENT_RUN_HOST_GOOGLEUSERCONTENT, 62 INSECURE_CONTENT_DISPLAY_HOST_MAIL_GOOGLE, 63 INSECURE_CONTENT_RUN_HOST_MAIL_GOOGLE, 64 INSECURE_CONTENT_DISPLAY_HOST_PLUS_GOOGLE, 65 INSECURE_CONTENT_RUN_HOST_PLUS_GOOGLE, 66 INSECURE_CONTENT_DISPLAY_HOST_DOCS_GOOGLE, 67 INSECURE_CONTENT_RUN_HOST_DOCS_GOOGLE, 68 INSECURE_CONTENT_DISPLAY_HOST_SITES_GOOGLE, 69 INSECURE_CONTENT_RUN_HOST_SITES_GOOGLE, 70 INSECURE_CONTENT_DISPLAY_HOST_PICASAWEB_GOOGLE, 71 INSECURE_CONTENT_RUN_HOST_PICASAWEB_GOOGLE, 72 INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_READER, 73 INSECURE_CONTENT_RUN_HOST_GOOGLE_READER, 74 INSECURE_CONTENT_DISPLAY_HOST_CODE_GOOGLE, 75 INSECURE_CONTENT_RUN_HOST_CODE_GOOGLE, 76 INSECURE_CONTENT_DISPLAY_HOST_GROUPS_GOOGLE, 77 INSECURE_CONTENT_RUN_HOST_GROUPS_GOOGLE, 78 INSECURE_CONTENT_DISPLAY_HOST_MAPS_GOOGLE, 79 INSECURE_CONTENT_RUN_HOST_MAPS_GOOGLE, 80 INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_SUPPORT, 81 INSECURE_CONTENT_RUN_HOST_GOOGLE_SUPPORT, 82 INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_INTL, 83 INSECURE_CONTENT_RUN_HOST_GOOGLE_INTL, 84 INSECURE_CONTENT_NUM_EVENTS 85 }; 86 87 // Constants for UMA statistic collection. 88 static const char kWWWDotGoogleDotCom[] = "www.google.com"; 89 static const char kMailDotGoogleDotCom[] = "mail.google.com"; 90 static const char kPlusDotGoogleDotCom[] = "plus.google.com"; 91 static const char kDocsDotGoogleDotCom[] = "docs.google.com"; 92 static const char kSitesDotGoogleDotCom[] = "sites.google.com"; 93 static const char kPicasawebDotGoogleDotCom[] = "picasaweb.google.com"; 94 static const char kCodeDotGoogleDotCom[] = "code.google.com"; 95 static const char kGroupsDotGoogleDotCom[] = "groups.google.com"; 96 static const char kMapsDotGoogleDotCom[] = "maps.google.com"; 97 static const char kWWWDotYoutubeDotCom[] = "www.youtube.com"; 98 static const char kDotGoogleUserContentDotCom[] = ".googleusercontent.com"; 99 static const char kGoogleReaderPathPrefix[] = "/reader/"; 100 static const char kGoogleSupportPathPrefix[] = "/support/"; 101 static const char kGoogleIntlPathPrefix[] = "/intl/"; 102 static const char kDotJS[] = ".js"; 103 static const char kDotCSS[] = ".css"; 104 static const char kDotSWF[] = ".swf"; 105 static const char kDotHTML[] = ".html"; 106 107 // Constants for mixed-content blocking. 108 static const char kGoogleDotCom[] = "google.com"; 109 110 static bool IsHostInDomain(const std::string& host, const std::string& domain) { 111 return (EndsWith(host, domain, false) && 112 (host.length() == domain.length() || 113 (host.length() > domain.length() && 114 host[host.length() - domain.length() - 1] == '.'))); 115 } 116 117 GURL GetOriginOrURL(const WebFrame* frame) { 118 WebString top_origin = frame->top()->document().securityOrigin().toString(); 119 // The the |top_origin| is unique ("null") e.g., for file:// URLs. Use the 120 // document URL as the primary URL in those cases. 121 if (top_origin == "null") 122 return frame->top()->document().url(); 123 return GURL(top_origin); 124 } 125 126 ContentSetting GetContentSettingFromRules( 127 const ContentSettingsForOneType& rules, 128 const WebFrame* frame, 129 const GURL& secondary_url) { 130 ContentSettingsForOneType::const_iterator it; 131 // If there is only one rule, it's the default rule and we don't need to match 132 // the patterns. 133 if (rules.size() == 1) { 134 DCHECK(rules[0].primary_pattern == ContentSettingsPattern::Wildcard()); 135 DCHECK(rules[0].secondary_pattern == ContentSettingsPattern::Wildcard()); 136 return rules[0].setting; 137 } 138 const GURL& primary_url = GetOriginOrURL(frame); 139 for (it = rules.begin(); it != rules.end(); ++it) { 140 if (it->primary_pattern.Matches(primary_url) && 141 it->secondary_pattern.Matches(secondary_url)) { 142 return it->setting; 143 } 144 } 145 NOTREACHED(); 146 return CONTENT_SETTING_DEFAULT; 147 } 148 149 } // namespace 150 151 ContentSettingsObserver::ContentSettingsObserver( 152 content::RenderFrame* render_frame, 153 extensions::Dispatcher* extension_dispatcher) 154 : content::RenderFrameObserver(render_frame), 155 content::RenderFrameObserverTracker<ContentSettingsObserver>( 156 render_frame), 157 #if defined(ENABLE_EXTENSIONS) 158 extension_dispatcher_(extension_dispatcher), 159 #endif 160 allow_displaying_insecure_content_(false), 161 allow_running_insecure_content_(false), 162 content_setting_rules_(NULL), 163 is_interstitial_page_(false), 164 npapi_plugins_blocked_(false), 165 current_request_id_(0) { 166 ClearBlockedContentSettings(); 167 render_frame->GetWebFrame()->setPermissionClient(this); 168 169 if (render_frame->GetRenderView()->GetMainRenderFrame() != render_frame) { 170 // Copy all the settings from the main render frame to avoid race conditions 171 // when initializing this data. See http://crbug.com/333308. 172 ContentSettingsObserver* parent = ContentSettingsObserver::Get( 173 render_frame->GetRenderView()->GetMainRenderFrame()); 174 allow_displaying_insecure_content_ = 175 parent->allow_displaying_insecure_content_; 176 allow_running_insecure_content_ = parent->allow_running_insecure_content_; 177 temporarily_allowed_plugins_ = parent->temporarily_allowed_plugins_; 178 is_interstitial_page_ = parent->is_interstitial_page_; 179 npapi_plugins_blocked_ = parent->npapi_plugins_blocked_; 180 } 181 } 182 183 ContentSettingsObserver::~ContentSettingsObserver() { 184 } 185 186 void ContentSettingsObserver::SetContentSettingRules( 187 const RendererContentSettingRules* content_setting_rules) { 188 content_setting_rules_ = content_setting_rules; 189 } 190 191 bool ContentSettingsObserver::IsPluginTemporarilyAllowed( 192 const std::string& identifier) { 193 // If the empty string is in here, it means all plug-ins are allowed. 194 // TODO(bauerb): Remove this once we only pass in explicit identifiers. 195 return (temporarily_allowed_plugins_.find(identifier) != 196 temporarily_allowed_plugins_.end()) || 197 (temporarily_allowed_plugins_.find(std::string()) != 198 temporarily_allowed_plugins_.end()); 199 } 200 201 void ContentSettingsObserver::DidBlockContentType( 202 ContentSettingsType settings_type) { 203 if (!content_blocked_[settings_type]) { 204 content_blocked_[settings_type] = true; 205 Send(new ChromeViewHostMsg_ContentBlocked(routing_id(), settings_type)); 206 } 207 } 208 209 bool ContentSettingsObserver::OnMessageReceived(const IPC::Message& message) { 210 bool handled = true; 211 IPC_BEGIN_MESSAGE_MAP(ContentSettingsObserver, message) 212 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetAsInterstitial, OnSetAsInterstitial) 213 IPC_MESSAGE_HANDLER(ChromeViewMsg_NPAPINotSupported, OnNPAPINotSupported) 214 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetAllowDisplayingInsecureContent, 215 OnSetAllowDisplayingInsecureContent) 216 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetAllowRunningInsecureContent, 217 OnSetAllowRunningInsecureContent) 218 IPC_MESSAGE_HANDLER(ChromeViewMsg_ReloadFrame, OnReloadFrame); 219 IPC_MESSAGE_HANDLER(ChromeViewMsg_RequestFileSystemAccessAsyncResponse, 220 OnRequestFileSystemAccessAsyncResponse) 221 IPC_MESSAGE_UNHANDLED(handled = false) 222 IPC_END_MESSAGE_MAP() 223 if (handled) 224 return true; 225 226 // Don't swallow LoadBlockedPlugins messages, as they're sent to every 227 // blocked plugin. 228 IPC_BEGIN_MESSAGE_MAP(ContentSettingsObserver, message) 229 IPC_MESSAGE_HANDLER(ChromeViewMsg_LoadBlockedPlugins, OnLoadBlockedPlugins) 230 IPC_END_MESSAGE_MAP() 231 232 return false; 233 } 234 235 void ContentSettingsObserver::DidCommitProvisionalLoad(bool is_new_navigation) { 236 WebFrame* frame = render_frame()->GetWebFrame(); 237 if (frame->parent()) 238 return; // Not a top-level navigation. 239 240 DocumentState* document_state = DocumentState::FromDataSource( 241 frame->dataSource()); 242 NavigationState* navigation_state = document_state->navigation_state(); 243 if (!navigation_state->was_within_same_page()) { 244 // Clear "block" flags for the new page. This needs to happen before any of 245 // |allowScript()|, |allowScriptFromSource()|, |allowImage()|, or 246 // |allowPlugins()| is called for the new page so that these functions can 247 // correctly detect that a piece of content flipped from "not blocked" to 248 // "blocked". 249 ClearBlockedContentSettings(); 250 temporarily_allowed_plugins_.clear(); 251 } 252 253 GURL url = frame->document().url(); 254 // If we start failing this DCHECK, please makes sure we don't regress 255 // this bug: http://code.google.com/p/chromium/issues/detail?id=79304 256 DCHECK(frame->document().securityOrigin().toString() == "null" || 257 !url.SchemeIs(url::kDataScheme)); 258 } 259 260 bool ContentSettingsObserver::allowDatabase(const WebString& name, 261 const WebString& display_name, 262 unsigned long estimated_size) { 263 WebFrame* frame = render_frame()->GetWebFrame(); 264 if (frame->document().securityOrigin().isUnique() || 265 frame->top()->document().securityOrigin().isUnique()) 266 return false; 267 268 bool result = false; 269 Send(new ChromeViewHostMsg_AllowDatabase( 270 routing_id(), GURL(frame->document().securityOrigin().toString()), 271 GURL(frame->top()->document().securityOrigin().toString()), 272 name, display_name, &result)); 273 return result; 274 } 275 276 void ContentSettingsObserver::requestFileSystemAccessAsync( 277 const WebPermissionCallbacks& callbacks) { 278 WebFrame* frame = render_frame()->GetWebFrame(); 279 if (frame->document().securityOrigin().isUnique() || 280 frame->top()->document().securityOrigin().isUnique()) { 281 WebPermissionCallbacks permissionCallbacks(callbacks); 282 permissionCallbacks.doDeny(); 283 return; 284 } 285 ++current_request_id_; 286 std::pair<PermissionRequestMap::iterator, bool> insert_result = 287 permission_requests_.insert( 288 std::make_pair(current_request_id_, callbacks)); 289 290 // Verify there are no duplicate insertions. 291 DCHECK(insert_result.second); 292 293 Send(new ChromeViewHostMsg_RequestFileSystemAccessAsync( 294 routing_id(), 295 current_request_id_, 296 GURL(frame->document().securityOrigin().toString()), 297 GURL(frame->top()->document().securityOrigin().toString()))); 298 } 299 300 bool ContentSettingsObserver::allowImage(bool enabled_per_settings, 301 const WebURL& image_url) { 302 bool allow = enabled_per_settings; 303 if (enabled_per_settings) { 304 if (is_interstitial_page_) 305 return true; 306 307 if (IsWhitelistedForContentSettings(render_frame())) 308 return true; 309 310 if (content_setting_rules_) { 311 GURL secondary_url(image_url); 312 allow = 313 GetContentSettingFromRules(content_setting_rules_->image_rules, 314 render_frame()->GetWebFrame(), 315 secondary_url) != CONTENT_SETTING_BLOCK; 316 } 317 } 318 if (!allow) 319 DidBlockContentType(CONTENT_SETTINGS_TYPE_IMAGES); 320 return allow; 321 } 322 323 bool ContentSettingsObserver::allowIndexedDB(const WebString& name, 324 const WebSecurityOrigin& origin) { 325 WebFrame* frame = render_frame()->GetWebFrame(); 326 if (frame->document().securityOrigin().isUnique() || 327 frame->top()->document().securityOrigin().isUnique()) 328 return false; 329 330 bool result = false; 331 Send(new ChromeViewHostMsg_AllowIndexedDB( 332 routing_id(), GURL(frame->document().securityOrigin().toString()), 333 GURL(frame->top()->document().securityOrigin().toString()), 334 name, &result)); 335 return result; 336 } 337 338 bool ContentSettingsObserver::allowPlugins(bool enabled_per_settings) { 339 return enabled_per_settings; 340 } 341 342 bool ContentSettingsObserver::allowScript(bool enabled_per_settings) { 343 if (!enabled_per_settings) 344 return false; 345 if (is_interstitial_page_) 346 return true; 347 348 WebFrame* frame = render_frame()->GetWebFrame(); 349 std::map<WebFrame*, bool>::const_iterator it = 350 cached_script_permissions_.find(frame); 351 if (it != cached_script_permissions_.end()) 352 return it->second; 353 354 // Evaluate the content setting rules before 355 // |IsWhitelistedForContentSettings|; if there is only the default rule 356 // allowing all scripts, it's quicker this way. 357 bool allow = true; 358 if (content_setting_rules_) { 359 ContentSetting setting = GetContentSettingFromRules( 360 content_setting_rules_->script_rules, 361 frame, 362 GURL(frame->document().securityOrigin().toString())); 363 allow = setting != CONTENT_SETTING_BLOCK; 364 } 365 allow = allow || IsWhitelistedForContentSettings(render_frame()); 366 367 cached_script_permissions_[frame] = allow; 368 return allow; 369 } 370 371 bool ContentSettingsObserver::allowScriptFromSource( 372 bool enabled_per_settings, 373 const blink::WebURL& script_url) { 374 if (!enabled_per_settings) 375 return false; 376 if (is_interstitial_page_) 377 return true; 378 379 bool allow = true; 380 if (content_setting_rules_) { 381 ContentSetting setting = 382 GetContentSettingFromRules(content_setting_rules_->script_rules, 383 render_frame()->GetWebFrame(), 384 GURL(script_url)); 385 allow = setting != CONTENT_SETTING_BLOCK; 386 } 387 return allow || IsWhitelistedForContentSettings(render_frame()); 388 } 389 390 bool ContentSettingsObserver::allowStorage(bool local) { 391 WebFrame* frame = render_frame()->GetWebFrame(); 392 if (frame->document().securityOrigin().isUnique() || 393 frame->top()->document().securityOrigin().isUnique()) 394 return false; 395 bool result = false; 396 397 StoragePermissionsKey key( 398 GURL(frame->document().securityOrigin().toString()), local); 399 std::map<StoragePermissionsKey, bool>::const_iterator permissions = 400 cached_storage_permissions_.find(key); 401 if (permissions != cached_storage_permissions_.end()) 402 return permissions->second; 403 404 Send(new ChromeViewHostMsg_AllowDOMStorage( 405 routing_id(), GURL(frame->document().securityOrigin().toString()), 406 GURL(frame->top()->document().securityOrigin().toString()), 407 local, &result)); 408 cached_storage_permissions_[key] = result; 409 return result; 410 } 411 412 bool ContentSettingsObserver::allowReadFromClipboard(bool default_value) { 413 bool allowed = false; 414 #if defined(ENABLE_EXTENSIONS) 415 extensions::ScriptContext* calling_context = 416 extension_dispatcher_->script_context_set().GetCalling(); 417 if (calling_context) { 418 const extensions::Extension* extension = 419 calling_context->effective_extension(); 420 allowed = extension && 421 extension->permissions_data()->HasAPIPermission( 422 extensions::APIPermission::kClipboardRead); 423 } 424 #endif 425 return allowed; 426 } 427 428 bool ContentSettingsObserver::allowWriteToClipboard(bool default_value) { 429 bool allowed = false; 430 #if defined(ENABLE_EXTENSIONS) 431 // All blessed extension pages could historically write to the clipboard, so 432 // preserve that for compatibility. 433 extensions::ScriptContext* calling_context = 434 extension_dispatcher_->script_context_set().GetCalling(); 435 if (calling_context) { 436 if (calling_context->effective_context_type() == 437 extensions::Feature::BLESSED_EXTENSION_CONTEXT) { 438 allowed = true; 439 } else { 440 const extensions::Extension* extension = 441 calling_context->effective_extension(); 442 allowed = extension && 443 extension->permissions_data()->HasAPIPermission( 444 extensions::APIPermission::kClipboardWrite); 445 } 446 } 447 #endif 448 return allowed; 449 } 450 451 bool ContentSettingsObserver::allowMutationEvents(bool default_value) { 452 return IsPlatformApp() ? false : default_value; 453 } 454 455 bool ContentSettingsObserver::allowPushState() { 456 return !IsPlatformApp(); 457 } 458 459 static void SendInsecureContentSignal(int signal) { 460 UMA_HISTOGRAM_ENUMERATION("SSL.InsecureContent", signal, 461 INSECURE_CONTENT_NUM_EVENTS); 462 } 463 464 bool ContentSettingsObserver::allowDisplayingInsecureContent( 465 bool allowed_per_settings, 466 const blink::WebSecurityOrigin& origin, 467 const blink::WebURL& resource_url) { 468 SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY); 469 470 std::string origin_host(origin.host().utf8()); 471 WebFrame* frame = render_frame()->GetWebFrame(); 472 GURL frame_gurl(frame->document().url()); 473 if (IsHostInDomain(origin_host, kGoogleDotCom)) { 474 SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_GOOGLE); 475 if (StartsWithASCII(frame_gurl.path(), kGoogleSupportPathPrefix, false)) { 476 SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_SUPPORT); 477 } else if (StartsWithASCII(frame_gurl.path(), 478 kGoogleIntlPathPrefix, 479 false)) { 480 SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_INTL); 481 } 482 } 483 484 if (origin_host == kWWWDotGoogleDotCom) { 485 SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_WWW_GOOGLE); 486 if (StartsWithASCII(frame_gurl.path(), kGoogleReaderPathPrefix, false)) 487 SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_READER); 488 } else if (origin_host == kMailDotGoogleDotCom) { 489 SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_MAIL_GOOGLE); 490 } else if (origin_host == kPlusDotGoogleDotCom) { 491 SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_PLUS_GOOGLE); 492 } else if (origin_host == kDocsDotGoogleDotCom) { 493 SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_DOCS_GOOGLE); 494 } else if (origin_host == kSitesDotGoogleDotCom) { 495 SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_SITES_GOOGLE); 496 } else if (origin_host == kPicasawebDotGoogleDotCom) { 497 SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_PICASAWEB_GOOGLE); 498 } else if (origin_host == kCodeDotGoogleDotCom) { 499 SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_CODE_GOOGLE); 500 } else if (origin_host == kGroupsDotGoogleDotCom) { 501 SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_GROUPS_GOOGLE); 502 } else if (origin_host == kMapsDotGoogleDotCom) { 503 SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_MAPS_GOOGLE); 504 } else if (origin_host == kWWWDotYoutubeDotCom) { 505 SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_YOUTUBE); 506 } 507 508 GURL resource_gurl(resource_url); 509 if (EndsWith(resource_gurl.path(), kDotHTML, false)) 510 SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HTML); 511 512 if (allowed_per_settings || allow_displaying_insecure_content_) 513 return true; 514 515 Send(new ChromeViewHostMsg_DidBlockDisplayingInsecureContent(routing_id())); 516 517 return false; 518 } 519 520 bool ContentSettingsObserver::allowRunningInsecureContent( 521 bool allowed_per_settings, 522 const blink::WebSecurityOrigin& origin, 523 const blink::WebURL& resource_url) { 524 std::string origin_host(origin.host().utf8()); 525 WebFrame* frame = render_frame()->GetWebFrame(); 526 GURL frame_gurl(frame->document().url()); 527 DCHECK_EQ(frame_gurl.host(), origin_host); 528 529 bool is_google = IsHostInDomain(origin_host, kGoogleDotCom); 530 if (is_google) { 531 SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_GOOGLE); 532 if (StartsWithASCII(frame_gurl.path(), kGoogleSupportPathPrefix, false)) { 533 SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_GOOGLE_SUPPORT); 534 } else if (StartsWithASCII(frame_gurl.path(), 535 kGoogleIntlPathPrefix, 536 false)) { 537 SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_GOOGLE_INTL); 538 } 539 } 540 541 if (origin_host == kWWWDotGoogleDotCom) { 542 SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_WWW_GOOGLE); 543 if (StartsWithASCII(frame_gurl.path(), kGoogleReaderPathPrefix, false)) 544 SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_GOOGLE_READER); 545 } else if (origin_host == kMailDotGoogleDotCom) { 546 SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_MAIL_GOOGLE); 547 } else if (origin_host == kPlusDotGoogleDotCom) { 548 SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_PLUS_GOOGLE); 549 } else if (origin_host == kDocsDotGoogleDotCom) { 550 SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_DOCS_GOOGLE); 551 } else if (origin_host == kSitesDotGoogleDotCom) { 552 SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_SITES_GOOGLE); 553 } else if (origin_host == kPicasawebDotGoogleDotCom) { 554 SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_PICASAWEB_GOOGLE); 555 } else if (origin_host == kCodeDotGoogleDotCom) { 556 SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_CODE_GOOGLE); 557 } else if (origin_host == kGroupsDotGoogleDotCom) { 558 SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_GROUPS_GOOGLE); 559 } else if (origin_host == kMapsDotGoogleDotCom) { 560 SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_MAPS_GOOGLE); 561 } else if (origin_host == kWWWDotYoutubeDotCom) { 562 SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_YOUTUBE); 563 } else if (EndsWith(origin_host, kDotGoogleUserContentDotCom, false)) { 564 SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_GOOGLEUSERCONTENT); 565 } 566 567 GURL resource_gurl(resource_url); 568 if (resource_gurl.host() == kWWWDotYoutubeDotCom) 569 SendInsecureContentSignal(INSECURE_CONTENT_RUN_TARGET_YOUTUBE); 570 571 if (EndsWith(resource_gurl.path(), kDotJS, false)) 572 SendInsecureContentSignal(INSECURE_CONTENT_RUN_JS); 573 else if (EndsWith(resource_gurl.path(), kDotCSS, false)) 574 SendInsecureContentSignal(INSECURE_CONTENT_RUN_CSS); 575 else if (EndsWith(resource_gurl.path(), kDotSWF, false)) 576 SendInsecureContentSignal(INSECURE_CONTENT_RUN_SWF); 577 578 if (!allow_running_insecure_content_ && !allowed_per_settings) { 579 DidBlockContentType(CONTENT_SETTINGS_TYPE_MIXEDSCRIPT); 580 return false; 581 } 582 583 return true; 584 } 585 586 void ContentSettingsObserver::didNotAllowPlugins() { 587 DidBlockContentType(CONTENT_SETTINGS_TYPE_PLUGINS); 588 } 589 590 void ContentSettingsObserver::didNotAllowScript() { 591 DidBlockContentType(CONTENT_SETTINGS_TYPE_JAVASCRIPT); 592 } 593 594 bool ContentSettingsObserver::AreNPAPIPluginsBlocked() const { 595 return npapi_plugins_blocked_; 596 } 597 598 void ContentSettingsObserver::OnLoadBlockedPlugins( 599 const std::string& identifier) { 600 temporarily_allowed_plugins_.insert(identifier); 601 } 602 603 void ContentSettingsObserver::OnSetAsInterstitial() { 604 is_interstitial_page_ = true; 605 } 606 607 void ContentSettingsObserver::OnNPAPINotSupported() { 608 npapi_plugins_blocked_ = true; 609 } 610 611 void ContentSettingsObserver::OnSetAllowDisplayingInsecureContent(bool allow) { 612 allow_displaying_insecure_content_ = allow; 613 } 614 615 void ContentSettingsObserver::OnSetAllowRunningInsecureContent(bool allow) { 616 allow_running_insecure_content_ = allow; 617 OnSetAllowDisplayingInsecureContent(allow); 618 } 619 620 void ContentSettingsObserver::OnReloadFrame() { 621 DCHECK(!render_frame()->GetWebFrame()->parent()) << 622 "Should only be called on the main frame"; 623 render_frame()->GetWebFrame()->reload(); 624 } 625 626 void ContentSettingsObserver::OnRequestFileSystemAccessAsyncResponse( 627 int request_id, 628 bool allowed) { 629 PermissionRequestMap::iterator it = permission_requests_.find(request_id); 630 if (it == permission_requests_.end()) 631 return; 632 633 WebPermissionCallbacks callbacks = it->second; 634 permission_requests_.erase(it); 635 636 if (allowed) { 637 callbacks.doAllow(); 638 return; 639 } 640 callbacks.doDeny(); 641 } 642 643 void ContentSettingsObserver::ClearBlockedContentSettings() { 644 for (size_t i = 0; i < arraysize(content_blocked_); ++i) 645 content_blocked_[i] = false; 646 cached_storage_permissions_.clear(); 647 cached_script_permissions_.clear(); 648 } 649 650 bool ContentSettingsObserver::IsPlatformApp() { 651 #if defined(ENABLE_EXTENSIONS) 652 WebFrame* frame = render_frame()->GetWebFrame(); 653 WebSecurityOrigin origin = frame->document().securityOrigin(); 654 const extensions::Extension* extension = GetExtension(origin); 655 return extension && extension->is_platform_app(); 656 #else 657 return false; 658 #endif 659 } 660 661 #if defined(ENABLE_EXTENSIONS) 662 const extensions::Extension* ContentSettingsObserver::GetExtension( 663 const WebSecurityOrigin& origin) const { 664 if (!EqualsASCII(origin.protocol(), extensions::kExtensionScheme)) 665 return NULL; 666 667 const std::string extension_id = origin.host().utf8().data(); 668 if (!extension_dispatcher_->IsExtensionActive(extension_id)) 669 return NULL; 670 671 return extension_dispatcher_->extensions()->GetByID(extension_id); 672 } 673 #endif 674 675 bool ContentSettingsObserver::IsWhitelistedForContentSettings( 676 content::RenderFrame* frame) { 677 // Whitelist Instant processes. 678 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kInstantProcess)) 679 return true; 680 681 // Whitelist ftp directory listings, as they require JavaScript to function 682 // properly. 683 if (frame->IsFTPDirectoryListing()) 684 return true; 685 686 WebFrame* web_frame = frame->GetWebFrame(); 687 return IsWhitelistedForContentSettings(web_frame->document().securityOrigin(), 688 web_frame->document().url()); 689 } 690 691 bool ContentSettingsObserver::IsWhitelistedForContentSettings( 692 const WebSecurityOrigin& origin, 693 const GURL& document_url) { 694 if (document_url == GURL(content::kUnreachableWebDataURL)) 695 return true; 696 697 if (origin.isUnique()) 698 return false; // Uninitialized document? 699 700 if (EqualsASCII(origin.protocol(), content::kChromeUIScheme)) 701 return true; // Browser UI elements should still work. 702 703 if (EqualsASCII(origin.protocol(), content::kChromeDevToolsScheme)) 704 return true; // DevTools UI elements should still work. 705 706 #if defined(ENABLE_EXTENSIONS) 707 if (EqualsASCII(origin.protocol(), extensions::kExtensionScheme)) 708 return true; 709 #endif 710 711 // TODO(creis, fsamuel): Remove this once the concept of swapped out 712 // RenderFrames goes away. 713 if (document_url == GURL(content::kSwappedOutURL)) 714 return true; 715 716 // If the scheme is file:, an empty file name indicates a directory listing, 717 // which requires JavaScript to function properly. 718 if (EqualsASCII(origin.protocol(), url::kFileScheme)) { 719 return document_url.SchemeIs(url::kFileScheme) && 720 document_url.ExtractFileName().empty(); 721 } 722 723 return false; 724 } 725