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