Home | History | Annotate | Download | only in renderer
      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