Unregister from GCM when the only GCM app is removed
[chromium-blink-merge.git] / chrome / renderer / content_settings_observer.cc
blob55d961be2e406972ed55bb6bb5034729ef45a744
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.
5 #include "chrome/renderer/content_settings_observer.h"
7 #include "base/command_line.h"
8 #include "base/metrics/histogram.h"
9 #include "chrome/common/render_messages.h"
10 #include "content/public/common/url_constants.h"
11 #include "content/public/renderer/document_state.h"
12 #include "content/public/renderer/navigation_state.h"
13 #include "content/public/renderer/render_frame.h"
14 #include "content/public/renderer/render_view.h"
15 #include "third_party/WebKit/public/platform/WebPermissionCallbacks.h"
16 #include "third_party/WebKit/public/platform/WebURL.h"
17 #include "third_party/WebKit/public/web/WebDataSource.h"
18 #include "third_party/WebKit/public/web/WebDocument.h"
19 #include "third_party/WebKit/public/web/WebFrameClient.h"
20 #include "third_party/WebKit/public/web/WebLocalFrame.h"
21 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
22 #include "third_party/WebKit/public/web/WebView.h"
23 #include "url/url_constants.h"
25 #if defined(ENABLE_EXTENSIONS)
26 #include "chrome/common/extensions/chrome_extension_messages.h"
27 #include "extensions/common/constants.h"
28 #include "extensions/common/extension.h"
29 #include "extensions/common/permissions/api_permission.h"
30 #include "extensions/common/permissions/permissions_data.h"
31 #include "extensions/renderer/dispatcher.h"
32 #endif
34 using blink::WebDataSource;
35 using blink::WebDocument;
36 using blink::WebFrame;
37 using blink::WebPermissionCallbacks;
38 using blink::WebSecurityOrigin;
39 using blink::WebString;
40 using blink::WebURL;
41 using blink::WebView;
42 using content::DocumentState;
43 using content::NavigationState;
45 namespace {
47 enum {
48 INSECURE_CONTENT_DISPLAY = 0,
49 INSECURE_CONTENT_DISPLAY_HOST_GOOGLE,
50 INSECURE_CONTENT_DISPLAY_HOST_WWW_GOOGLE,
51 INSECURE_CONTENT_DISPLAY_HTML,
52 INSECURE_CONTENT_RUN,
53 INSECURE_CONTENT_RUN_HOST_GOOGLE,
54 INSECURE_CONTENT_RUN_HOST_WWW_GOOGLE,
55 INSECURE_CONTENT_RUN_TARGET_YOUTUBE,
56 INSECURE_CONTENT_RUN_JS,
57 INSECURE_CONTENT_RUN_CSS,
58 INSECURE_CONTENT_RUN_SWF,
59 INSECURE_CONTENT_DISPLAY_HOST_YOUTUBE,
60 INSECURE_CONTENT_RUN_HOST_YOUTUBE,
61 INSECURE_CONTENT_RUN_HOST_GOOGLEUSERCONTENT,
62 INSECURE_CONTENT_DISPLAY_HOST_MAIL_GOOGLE,
63 INSECURE_CONTENT_RUN_HOST_MAIL_GOOGLE,
64 INSECURE_CONTENT_DISPLAY_HOST_PLUS_GOOGLE,
65 INSECURE_CONTENT_RUN_HOST_PLUS_GOOGLE,
66 INSECURE_CONTENT_DISPLAY_HOST_DOCS_GOOGLE,
67 INSECURE_CONTENT_RUN_HOST_DOCS_GOOGLE,
68 INSECURE_CONTENT_DISPLAY_HOST_SITES_GOOGLE,
69 INSECURE_CONTENT_RUN_HOST_SITES_GOOGLE,
70 INSECURE_CONTENT_DISPLAY_HOST_PICASAWEB_GOOGLE,
71 INSECURE_CONTENT_RUN_HOST_PICASAWEB_GOOGLE,
72 INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_READER,
73 INSECURE_CONTENT_RUN_HOST_GOOGLE_READER,
74 INSECURE_CONTENT_DISPLAY_HOST_CODE_GOOGLE,
75 INSECURE_CONTENT_RUN_HOST_CODE_GOOGLE,
76 INSECURE_CONTENT_DISPLAY_HOST_GROUPS_GOOGLE,
77 INSECURE_CONTENT_RUN_HOST_GROUPS_GOOGLE,
78 INSECURE_CONTENT_DISPLAY_HOST_MAPS_GOOGLE,
79 INSECURE_CONTENT_RUN_HOST_MAPS_GOOGLE,
80 INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_SUPPORT,
81 INSECURE_CONTENT_RUN_HOST_GOOGLE_SUPPORT,
82 INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_INTL,
83 INSECURE_CONTENT_RUN_HOST_GOOGLE_INTL,
84 INSECURE_CONTENT_NUM_EVENTS
87 // Constants for UMA statistic collection.
88 static const char kWWWDotGoogleDotCom[] = "www.google.com";
89 static const char kMailDotGoogleDotCom[] = "mail.google.com";
90 static const char kPlusDotGoogleDotCom[] = "plus.google.com";
91 static const char kDocsDotGoogleDotCom[] = "docs.google.com";
92 static const char kSitesDotGoogleDotCom[] = "sites.google.com";
93 static const char kPicasawebDotGoogleDotCom[] = "picasaweb.google.com";
94 static const char kCodeDotGoogleDotCom[] = "code.google.com";
95 static const char kGroupsDotGoogleDotCom[] = "groups.google.com";
96 static const char kMapsDotGoogleDotCom[] = "maps.google.com";
97 static const char kWWWDotYoutubeDotCom[] = "www.youtube.com";
98 static const char kDotGoogleUserContentDotCom[] = ".googleusercontent.com";
99 static const char kGoogleReaderPathPrefix[] = "/reader/";
100 static const char kGoogleSupportPathPrefix[] = "/support/";
101 static const char kGoogleIntlPathPrefix[] = "/intl/";
102 static const char kDotJS[] = ".js";
103 static const char kDotCSS[] = ".css";
104 static const char kDotSWF[] = ".swf";
105 static const char kDotHTML[] = ".html";
107 // Constants for mixed-content blocking.
108 static const char kGoogleDotCom[] = "google.com";
110 static bool IsHostInDomain(const std::string& host, const std::string& domain) {
111 return (EndsWith(host, domain, false) &&
112 (host.length() == domain.length() ||
113 (host.length() > domain.length() &&
114 host[host.length() - domain.length() - 1] == '.')));
117 GURL GetOriginOrURL(const WebFrame* frame) {
118 WebString top_origin = frame->top()->securityOrigin().toString();
119 // The |top_origin| is unique ("null") e.g., for file:// URLs. Use the
120 // document URL as the primary URL in those cases.
121 // TODO(alexmos): This is broken for --site-per-process, since top() can be a
122 // WebRemoteFrame which does not have a document(), and the WebRemoteFrame's
123 // URL is not replicated.
124 if (top_origin == "null")
125 return frame->top()->document().url();
126 return GURL(top_origin);
129 ContentSetting GetContentSettingFromRules(
130 const ContentSettingsForOneType& rules,
131 const WebFrame* frame,
132 const GURL& secondary_url) {
133 ContentSettingsForOneType::const_iterator it;
134 // If there is only one rule, it's the default rule and we don't need to match
135 // the patterns.
136 if (rules.size() == 1) {
137 DCHECK(rules[0].primary_pattern == ContentSettingsPattern::Wildcard());
138 DCHECK(rules[0].secondary_pattern == ContentSettingsPattern::Wildcard());
139 return rules[0].setting;
141 const GURL& primary_url = GetOriginOrURL(frame);
142 for (it = rules.begin(); it != rules.end(); ++it) {
143 if (it->primary_pattern.Matches(primary_url) &&
144 it->secondary_pattern.Matches(secondary_url)) {
145 return it->setting;
148 NOTREACHED();
149 return CONTENT_SETTING_DEFAULT;
152 } // namespace
154 ContentSettingsObserver::ContentSettingsObserver(
155 content::RenderFrame* render_frame,
156 extensions::Dispatcher* extension_dispatcher,
157 bool should_whitelist)
158 : content::RenderFrameObserver(render_frame),
159 content::RenderFrameObserverTracker<ContentSettingsObserver>(
160 render_frame),
161 #if defined(ENABLE_EXTENSIONS)
162 extension_dispatcher_(extension_dispatcher),
163 #endif
164 allow_displaying_insecure_content_(false),
165 allow_running_insecure_content_(false),
166 content_setting_rules_(NULL),
167 is_interstitial_page_(false),
168 npapi_plugins_blocked_(false),
169 current_request_id_(0),
170 should_whitelist_(should_whitelist) {
171 ClearBlockedContentSettings();
172 render_frame->GetWebFrame()->setPermissionClient(this);
174 if (render_frame->GetRenderView()->GetMainRenderFrame() != render_frame) {
175 // Copy all the settings from the main render frame to avoid race conditions
176 // when initializing this data. See http://crbug.com/333308.
177 ContentSettingsObserver* parent = ContentSettingsObserver::Get(
178 render_frame->GetRenderView()->GetMainRenderFrame());
179 allow_displaying_insecure_content_ =
180 parent->allow_displaying_insecure_content_;
181 allow_running_insecure_content_ = parent->allow_running_insecure_content_;
182 temporarily_allowed_plugins_ = parent->temporarily_allowed_plugins_;
183 is_interstitial_page_ = parent->is_interstitial_page_;
184 npapi_plugins_blocked_ = parent->npapi_plugins_blocked_;
188 ContentSettingsObserver::~ContentSettingsObserver() {
191 void ContentSettingsObserver::SetContentSettingRules(
192 const RendererContentSettingRules* content_setting_rules) {
193 content_setting_rules_ = content_setting_rules;
196 bool ContentSettingsObserver::IsPluginTemporarilyAllowed(
197 const std::string& identifier) {
198 // If the empty string is in here, it means all plug-ins are allowed.
199 // TODO(bauerb): Remove this once we only pass in explicit identifiers.
200 return (temporarily_allowed_plugins_.find(identifier) !=
201 temporarily_allowed_plugins_.end()) ||
202 (temporarily_allowed_plugins_.find(std::string()) !=
203 temporarily_allowed_plugins_.end());
206 void ContentSettingsObserver::DidBlockContentType(
207 ContentSettingsType settings_type) {
208 DidBlockContentType(settings_type, base::string16());
211 void ContentSettingsObserver::DidBlockContentType(
212 ContentSettingsType settings_type,
213 const base::string16& details) {
214 // Send multiple ContentBlocked messages if details are provided.
215 if (!content_blocked_[settings_type] || !details.empty()) {
216 content_blocked_[settings_type] = true;
217 Send(new ChromeViewHostMsg_ContentBlocked(routing_id(), settings_type,
218 details));
222 bool ContentSettingsObserver::OnMessageReceived(const IPC::Message& message) {
223 bool handled = true;
224 IPC_BEGIN_MESSAGE_MAP(ContentSettingsObserver, message)
225 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetAsInterstitial, OnSetAsInterstitial)
226 IPC_MESSAGE_HANDLER(ChromeViewMsg_NPAPINotSupported, OnNPAPINotSupported)
227 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetAllowDisplayingInsecureContent,
228 OnSetAllowDisplayingInsecureContent)
229 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetAllowRunningInsecureContent,
230 OnSetAllowRunningInsecureContent)
231 IPC_MESSAGE_HANDLER(ChromeViewMsg_ReloadFrame, OnReloadFrame);
232 IPC_MESSAGE_HANDLER(ChromeViewMsg_RequestFileSystemAccessAsyncResponse,
233 OnRequestFileSystemAccessAsyncResponse)
234 IPC_MESSAGE_UNHANDLED(handled = false)
235 IPC_END_MESSAGE_MAP()
236 if (handled)
237 return true;
239 // Don't swallow LoadBlockedPlugins messages, as they're sent to every
240 // blocked plugin.
241 IPC_BEGIN_MESSAGE_MAP(ContentSettingsObserver, message)
242 IPC_MESSAGE_HANDLER(ChromeViewMsg_LoadBlockedPlugins, OnLoadBlockedPlugins)
243 IPC_END_MESSAGE_MAP()
245 return false;
248 void ContentSettingsObserver::DidCommitProvisionalLoad(bool is_new_navigation) {
249 WebFrame* frame = render_frame()->GetWebFrame();
250 if (frame->parent())
251 return; // Not a top-level navigation.
253 DocumentState* document_state = DocumentState::FromDataSource(
254 frame->dataSource());
255 NavigationState* navigation_state = document_state->navigation_state();
256 if (!navigation_state->was_within_same_page()) {
257 // Clear "block" flags for the new page. This needs to happen before any of
258 // |allowScript()|, |allowScriptFromSource()|, |allowImage()|, or
259 // |allowPlugins()| is called for the new page so that these functions can
260 // correctly detect that a piece of content flipped from "not blocked" to
261 // "blocked".
262 ClearBlockedContentSettings();
263 temporarily_allowed_plugins_.clear();
266 GURL url = frame->document().url();
267 // If we start failing this DCHECK, please makes sure we don't regress
268 // this bug: http://code.google.com/p/chromium/issues/detail?id=79304
269 DCHECK(frame->document().securityOrigin().toString() == "null" ||
270 !url.SchemeIs(url::kDataScheme));
273 bool ContentSettingsObserver::allowDatabase(const WebString& name,
274 const WebString& display_name,
275 unsigned long estimated_size) {
276 WebFrame* frame = render_frame()->GetWebFrame();
277 if (frame->securityOrigin().isUnique() ||
278 frame->top()->securityOrigin().isUnique())
279 return false;
281 bool result = false;
282 Send(new ChromeViewHostMsg_AllowDatabase(
283 routing_id(), GURL(frame->securityOrigin().toString()),
284 GURL(frame->top()->securityOrigin().toString()), name, display_name,
285 &result));
286 return result;
289 void ContentSettingsObserver::requestFileSystemAccessAsync(
290 const WebPermissionCallbacks& callbacks) {
291 WebFrame* frame = render_frame()->GetWebFrame();
292 if (frame->securityOrigin().isUnique() ||
293 frame->top()->securityOrigin().isUnique()) {
294 WebPermissionCallbacks permissionCallbacks(callbacks);
295 permissionCallbacks.doDeny();
296 return;
298 ++current_request_id_;
299 std::pair<PermissionRequestMap::iterator, bool> insert_result =
300 permission_requests_.insert(
301 std::make_pair(current_request_id_, callbacks));
303 // Verify there are no duplicate insertions.
304 DCHECK(insert_result.second);
306 Send(new ChromeViewHostMsg_RequestFileSystemAccessAsync(
307 routing_id(), current_request_id_,
308 GURL(frame->securityOrigin().toString()),
309 GURL(frame->top()->securityOrigin().toString())));
312 bool ContentSettingsObserver::allowImage(bool enabled_per_settings,
313 const WebURL& image_url) {
314 bool allow = enabled_per_settings;
315 if (enabled_per_settings) {
316 if (is_interstitial_page_)
317 return true;
319 if (IsWhitelistedForContentSettings())
320 return true;
322 if (content_setting_rules_) {
323 GURL secondary_url(image_url);
324 allow =
325 GetContentSettingFromRules(content_setting_rules_->image_rules,
326 render_frame()->GetWebFrame(),
327 secondary_url) != CONTENT_SETTING_BLOCK;
330 if (!allow)
331 DidBlockContentType(CONTENT_SETTINGS_TYPE_IMAGES);
332 return allow;
335 bool ContentSettingsObserver::allowIndexedDB(const WebString& name,
336 const WebSecurityOrigin& origin) {
337 WebFrame* frame = render_frame()->GetWebFrame();
338 if (frame->securityOrigin().isUnique() ||
339 frame->top()->securityOrigin().isUnique())
340 return false;
342 bool result = false;
343 Send(new ChromeViewHostMsg_AllowIndexedDB(
344 routing_id(), GURL(frame->securityOrigin().toString()),
345 GURL(frame->top()->securityOrigin().toString()), name, &result));
346 return result;
349 bool ContentSettingsObserver::allowPlugins(bool enabled_per_settings) {
350 return enabled_per_settings;
353 bool ContentSettingsObserver::allowScript(bool enabled_per_settings) {
354 if (!enabled_per_settings)
355 return false;
356 if (is_interstitial_page_)
357 return true;
359 WebFrame* frame = render_frame()->GetWebFrame();
360 std::map<WebFrame*, bool>::const_iterator it =
361 cached_script_permissions_.find(frame);
362 if (it != cached_script_permissions_.end())
363 return it->second;
365 // Evaluate the content setting rules before
366 // |IsWhitelistedForContentSettings|; if there is only the default rule
367 // allowing all scripts, it's quicker this way.
368 bool allow = true;
369 if (content_setting_rules_) {
370 ContentSetting setting = GetContentSettingFromRules(
371 content_setting_rules_->script_rules,
372 frame,
373 GURL(frame->document().securityOrigin().toString()));
374 allow = setting != CONTENT_SETTING_BLOCK;
376 allow = allow || IsWhitelistedForContentSettings();
378 cached_script_permissions_[frame] = allow;
379 return allow;
382 bool ContentSettingsObserver::allowScriptFromSource(
383 bool enabled_per_settings,
384 const blink::WebURL& script_url) {
385 if (!enabled_per_settings)
386 return false;
387 if (is_interstitial_page_)
388 return true;
390 bool allow = true;
391 if (content_setting_rules_) {
392 ContentSetting setting =
393 GetContentSettingFromRules(content_setting_rules_->script_rules,
394 render_frame()->GetWebFrame(),
395 GURL(script_url));
396 allow = setting != CONTENT_SETTING_BLOCK;
398 return allow || IsWhitelistedForContentSettings();
401 bool ContentSettingsObserver::allowStorage(bool local) {
402 WebFrame* frame = render_frame()->GetWebFrame();
403 if (frame->securityOrigin().isUnique() ||
404 frame->top()->securityOrigin().isUnique())
405 return false;
406 bool result = false;
408 StoragePermissionsKey key(
409 GURL(frame->document().securityOrigin().toString()), local);
410 std::map<StoragePermissionsKey, bool>::const_iterator permissions =
411 cached_storage_permissions_.find(key);
412 if (permissions != cached_storage_permissions_.end())
413 return permissions->second;
415 Send(new ChromeViewHostMsg_AllowDOMStorage(
416 routing_id(), GURL(frame->securityOrigin().toString()),
417 GURL(frame->top()->securityOrigin().toString()), local, &result));
418 cached_storage_permissions_[key] = result;
419 return result;
422 bool ContentSettingsObserver::allowReadFromClipboard(bool default_value) {
423 bool allowed = false;
424 #if defined(ENABLE_EXTENSIONS)
425 extensions::ScriptContext* calling_context =
426 extension_dispatcher_->script_context_set().GetCalling();
427 if (calling_context) {
428 allowed = calling_context->HasAPIPermission(
429 extensions::APIPermission::kClipboardRead);
431 #endif
432 return allowed;
435 bool ContentSettingsObserver::allowWriteToClipboard(bool default_value) {
436 bool allowed = false;
437 #if defined(ENABLE_EXTENSIONS)
438 // All blessed extension pages could historically write to the clipboard, so
439 // preserve that for compatibility.
440 extensions::ScriptContext* calling_context =
441 extension_dispatcher_->script_context_set().GetCalling();
442 if (calling_context) {
443 if (calling_context->effective_context_type() ==
444 extensions::Feature::BLESSED_EXTENSION_CONTEXT) {
445 allowed = true;
446 } else {
447 allowed = calling_context->HasAPIPermission(
448 extensions::APIPermission::kClipboardWrite);
451 #endif
452 return allowed;
455 bool ContentSettingsObserver::allowMutationEvents(bool default_value) {
456 return IsPlatformApp() ? false : default_value;
459 bool ContentSettingsObserver::allowPushState() {
460 return !IsPlatformApp();
463 static void SendInsecureContentSignal(int signal) {
464 UMA_HISTOGRAM_ENUMERATION("SSL.InsecureContent", signal,
465 INSECURE_CONTENT_NUM_EVENTS);
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);
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);
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);
512 GURL resource_gurl(resource_url);
513 if (EndsWith(resource_gurl.path(), kDotHTML, false))
514 SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HTML);
516 if (allowed_per_settings || allow_displaying_insecure_content_)
517 return true;
519 Send(new ChromeViewHostMsg_DidBlockDisplayingInsecureContent(routing_id()));
521 return false;
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);
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);
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);
571 GURL resource_gurl(resource_url);
572 if (resource_gurl.host() == kWWWDotYoutubeDotCom)
573 SendInsecureContentSignal(INSECURE_CONTENT_RUN_TARGET_YOUTUBE);
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);
582 if (!allow_running_insecure_content_ && !allowed_per_settings) {
583 DidBlockContentType(CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, origin.host());
584 return false;
587 return true;
590 void ContentSettingsObserver::didNotAllowPlugins() {
591 DidBlockContentType(CONTENT_SETTINGS_TYPE_PLUGINS);
594 void ContentSettingsObserver::didNotAllowScript() {
595 DidBlockContentType(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
598 bool ContentSettingsObserver::AreNPAPIPluginsBlocked() const {
599 return npapi_plugins_blocked_;
602 void ContentSettingsObserver::OnLoadBlockedPlugins(
603 const std::string& identifier) {
604 temporarily_allowed_plugins_.insert(identifier);
607 void ContentSettingsObserver::OnSetAsInterstitial() {
608 is_interstitial_page_ = true;
611 void ContentSettingsObserver::OnNPAPINotSupported() {
612 npapi_plugins_blocked_ = true;
615 void ContentSettingsObserver::OnSetAllowDisplayingInsecureContent(bool allow) {
616 allow_displaying_insecure_content_ = allow;
619 void ContentSettingsObserver::OnSetAllowRunningInsecureContent(bool allow) {
620 allow_running_insecure_content_ = allow;
621 OnSetAllowDisplayingInsecureContent(allow);
624 void ContentSettingsObserver::OnReloadFrame() {
625 DCHECK(!render_frame()->GetWebFrame()->parent()) <<
626 "Should only be called on the main frame";
627 render_frame()->GetWebFrame()->reload();
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;
637 WebPermissionCallbacks callbacks = it->second;
638 permission_requests_.erase(it);
640 if (allowed) {
641 callbacks.doAllow();
642 return;
644 callbacks.doDeny();
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();
654 bool ContentSettingsObserver::IsPlatformApp() {
655 #if defined(ENABLE_EXTENSIONS)
656 WebFrame* frame = render_frame()->GetWebFrame();
657 WebSecurityOrigin origin = frame->document().securityOrigin();
658 const extensions::Extension* extension = GetExtension(origin);
659 return extension && extension->is_platform_app();
660 #else
661 return false;
662 #endif
665 #if defined(ENABLE_EXTENSIONS)
666 const extensions::Extension* ContentSettingsObserver::GetExtension(
667 const WebSecurityOrigin& origin) const {
668 if (!EqualsASCII(origin.protocol(), extensions::kExtensionScheme))
669 return NULL;
671 const std::string extension_id = origin.host().utf8().data();
672 if (!extension_dispatcher_->IsExtensionActive(extension_id))
673 return NULL;
675 return extension_dispatcher_->extensions()->GetByID(extension_id);
677 #endif
679 bool ContentSettingsObserver::IsWhitelistedForContentSettings() const {
680 if (should_whitelist_)
681 return true;
683 // Whitelist ftp directory listings, as they require JavaScript to function
684 // properly.
685 if (render_frame()->IsFTPDirectoryListing())
686 return true;
688 WebFrame* web_frame = render_frame()->GetWebFrame();
689 return IsWhitelistedForContentSettings(web_frame->document().securityOrigin(),
690 web_frame->document().url());
693 bool ContentSettingsObserver::IsWhitelistedForContentSettings(
694 const WebSecurityOrigin& origin,
695 const GURL& document_url) {
696 if (document_url == GURL(content::kUnreachableWebDataURL))
697 return true;
699 if (origin.isUnique())
700 return false; // Uninitialized document?
702 if (EqualsASCII(origin.protocol(), content::kChromeUIScheme))
703 return true; // Browser UI elements should still work.
705 if (EqualsASCII(origin.protocol(), content::kChromeDevToolsScheme))
706 return true; // DevTools UI elements should still work.
708 #if defined(ENABLE_EXTENSIONS)
709 if (EqualsASCII(origin.protocol(), extensions::kExtensionScheme))
710 return true;
711 #endif
713 // TODO(creis, fsamuel): Remove this once the concept of swapped out
714 // RenderFrames goes away.
715 if (document_url == GURL(content::kSwappedOutURL))
716 return true;
718 // If the scheme is file:, an empty file name indicates a directory listing,
719 // which requires JavaScript to function properly.
720 if (EqualsASCII(origin.protocol(), url::kFileScheme)) {
721 return document_url.SchemeIs(url::kFileScheme) &&
722 document_url.ExtractFileName().empty();
725 return false;