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