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