• 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 "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 
IsHostInDomain(const std::string & host,const std::string & domain)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 
GetOriginOrURL(const WebFrame * frame)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 
GetContentSettingFromRules(const ContentSettingsForOneType & rules,const WebFrame * frame,const GURL & secondary_url)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 
ContentSettingsObserver(content::RenderView * render_view,extensions::Dispatcher * extension_dispatcher)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 
~ContentSettingsObserver()159 ContentSettingsObserver::~ContentSettingsObserver() {
160 }
161 
SetContentSettingRules(const RendererContentSettingRules * content_setting_rules)162 void ContentSettingsObserver::SetContentSettingRules(
163     const RendererContentSettingRules* content_setting_rules) {
164   content_setting_rules_ = content_setting_rules;
165 }
166 
IsPluginTemporarilyAllowed(const std::string & identifier)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 
DidBlockContentType(ContentSettingsType settings_type)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 
OnMessageReceived(const IPC::Message & message)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 
DidCommitProvisionalLoad(WebFrame * frame,bool is_new_navigation)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 
allowDatabase(WebFrame * frame,const WebString & name,const WebString & display_name,unsigned long estimated_size)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 
allowFileSystem(WebFrame * frame)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 
allowImage(WebFrame * frame,bool enabled_per_settings,const WebURL & image_url)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 
allowIndexedDB(WebFrame * frame,const WebString & name,const WebSecurityOrigin & origin)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 
allowPlugins(WebFrame * frame,bool enabled_per_settings)298 bool ContentSettingsObserver::allowPlugins(WebFrame* frame,
299                                            bool enabled_per_settings) {
300   return enabled_per_settings;
301 }
302 
allowScript(WebFrame * frame,bool enabled_per_settings)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 
allowScriptFromSource(WebFrame * frame,bool enabled_per_settings,const blink::WebURL & script_url)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 
allowStorage(WebFrame * frame,bool local)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 
allowReadFromClipboard(WebFrame * frame,bool default_value)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 
allowWriteToClipboard(WebFrame * frame,bool default_value)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 
allowWebComponents(WebFrame * frame,bool defaultValue)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 
allowMutationEvents(WebFrame * frame,bool default_value)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 
allowPushState(WebFrame * frame)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 
SendInsecureContentSignal(int signal)424 static void SendInsecureContentSignal(int signal) {
425   UMA_HISTOGRAM_ENUMERATION("SSL.InsecureContent", signal,
426                             INSECURE_CONTENT_NUM_EVENTS);
427 }
428 
allowDisplayingInsecureContent(blink::WebFrame * frame,bool allowed_per_settings,const blink::WebSecurityOrigin & origin,const blink::WebURL & resource_url)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 
allowRunningInsecureContent(blink::WebFrame * frame,bool allowed_per_settings,const blink::WebSecurityOrigin & origin,const blink::WebURL & resource_url)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 
allowWebGLDebugRendererInfo(WebFrame * frame)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 
didNotAllowPlugins(WebFrame * frame)560 void ContentSettingsObserver::didNotAllowPlugins(WebFrame* frame) {
561   DidBlockContentType(CONTENT_SETTINGS_TYPE_PLUGINS);
562 }
563 
didNotAllowScript(WebFrame * frame)564 void ContentSettingsObserver::didNotAllowScript(WebFrame* frame) {
565   DidBlockContentType(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
566 }
567 
AreNPAPIPluginsBlocked() const568 bool ContentSettingsObserver::AreNPAPIPluginsBlocked() const {
569   return npapi_plugins_blocked_;
570 }
571 
OnLoadBlockedPlugins(const std::string & identifier)572 void ContentSettingsObserver::OnLoadBlockedPlugins(
573     const std::string& identifier) {
574   temporarily_allowed_plugins_.insert(identifier);
575 }
576 
OnSetAsInterstitial()577 void ContentSettingsObserver::OnSetAsInterstitial() {
578   is_interstitial_page_ = true;
579 }
580 
OnNPAPINotSupported()581 void ContentSettingsObserver::OnNPAPINotSupported() {
582   npapi_plugins_blocked_ = true;
583 }
584 
OnSetAllowDisplayingInsecureContent(bool allow)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 
OnSetAllowRunningInsecureContent(bool allow)592 void ContentSettingsObserver::OnSetAllowRunningInsecureContent(bool allow) {
593   allow_running_insecure_content_ = allow;
594   OnSetAllowDisplayingInsecureContent(allow);
595 }
596 
597 
ClearBlockedContentSettings()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 
GetExtension(const WebSecurityOrigin & origin) const605 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 
IsWhitelistedForContentSettings(WebFrame * frame)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 
IsWhitelistedForContentSettings(const WebSecurityOrigin & origin,const GURL & document_url)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