• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
IsHostInDomain(const std::string & host,const std::string & domain)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 
GetOriginOrURL(const WebFrame * frame)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 
GetContentSettingFromRules(const ContentSettingsForOneType & rules,const WebFrame * frame,const GURL & secondary_url)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 
ContentSettingsObserver(content::RenderFrame * render_frame,extensions::Dispatcher * extension_dispatcher)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 
~ContentSettingsObserver()178 ContentSettingsObserver::~ContentSettingsObserver() {
179 }
180 
SetContentSettingRules(const RendererContentSettingRules * content_setting_rules)181 void ContentSettingsObserver::SetContentSettingRules(
182     const RendererContentSettingRules* content_setting_rules) {
183   content_setting_rules_ = content_setting_rules;
184 }
185 
IsPluginTemporarilyAllowed(const std::string & identifier)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 
DidBlockContentType(ContentSettingsType settings_type)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 
OnMessageReceived(const IPC::Message & message)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 
DidCommitProvisionalLoad(bool is_new_navigation)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 
allowDatabase(const WebString & name,const WebString & display_name,unsigned long estimated_size)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 
requestFileSystemAccessAsync(const WebPermissionCallbacks & callbacks)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 
allowImage(bool enabled_per_settings,const WebURL & image_url)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 
allowIndexedDB(const WebString & name,const WebSecurityOrigin & origin)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 
allowPlugins(bool enabled_per_settings)333 bool ContentSettingsObserver::allowPlugins(bool enabled_per_settings) {
334   return enabled_per_settings;
335 }
336 
allowScript(bool enabled_per_settings)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 
allowScriptFromSource(bool enabled_per_settings,const blink::WebURL & script_url)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 
allowStorage(bool local)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 
allowReadFromClipboard(bool default_value)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 
allowWriteToClipboard(bool default_value)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 
allowWebComponents(bool default_value)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 
allowMutationEvents(bool default_value)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 
allowPushState()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 
SendInsecureContentSignal(int signal)463 static void SendInsecureContentSignal(int signal) {
464   UMA_HISTOGRAM_ENUMERATION("SSL.InsecureContent", signal,
465                             INSECURE_CONTENT_NUM_EVENTS);
466 }
467 
allowDisplayingInsecureContent(bool allowed_per_settings,const blink::WebSecurityOrigin & origin,const blink::WebURL & resource_url)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 
allowRunningInsecureContent(bool allowed_per_settings,const blink::WebSecurityOrigin & origin,const blink::WebURL & resource_url)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 
didNotAllowPlugins()590 void ContentSettingsObserver::didNotAllowPlugins() {
591   DidBlockContentType(CONTENT_SETTINGS_TYPE_PLUGINS);
592 }
593 
didNotAllowScript()594 void ContentSettingsObserver::didNotAllowScript() {
595   DidBlockContentType(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
596 }
597 
AreNPAPIPluginsBlocked() const598 bool ContentSettingsObserver::AreNPAPIPluginsBlocked() const {
599   return npapi_plugins_blocked_;
600 }
601 
OnLoadBlockedPlugins(const std::string & identifier)602 void ContentSettingsObserver::OnLoadBlockedPlugins(
603     const std::string& identifier) {
604   temporarily_allowed_plugins_.insert(identifier);
605 }
606 
OnSetAsInterstitial()607 void ContentSettingsObserver::OnSetAsInterstitial() {
608   is_interstitial_page_ = true;
609 }
610 
OnNPAPINotSupported()611 void ContentSettingsObserver::OnNPAPINotSupported() {
612   npapi_plugins_blocked_ = true;
613 }
614 
OnSetAllowDisplayingInsecureContent(bool allow)615 void ContentSettingsObserver::OnSetAllowDisplayingInsecureContent(bool allow) {
616   allow_displaying_insecure_content_ = allow;
617 }
618 
OnSetAllowRunningInsecureContent(bool allow)619 void ContentSettingsObserver::OnSetAllowRunningInsecureContent(bool allow) {
620   allow_running_insecure_content_ = allow;
621   OnSetAllowDisplayingInsecureContent(allow);
622 }
623 
OnReloadFrame()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 
OnRequestFileSystemAccessAsyncResponse(int request_id,bool allowed)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 
ClearBlockedContentSettings()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 
GetExtension(const WebSecurityOrigin & origin) const654 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 
IsWhitelistedForContentSettings(WebFrame * frame)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 
IsWhitelistedForContentSettings(const WebSecurityOrigin & origin,const GURL & document_url)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