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_agent_impl.h"
6
7 #include <utility>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/feature_list.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "chrome/common/chrome_features.h"
15 #include "chrome/common/client_hints/client_hints.h"
16 #include "chrome/common/render_messages.h"
17 #include "chrome/common/ssl_insecure_content.h"
18 #include "components/content_settings/core/common/content_settings.h"
19 #include "components/content_settings/core/common/content_settings.mojom.h"
20 #include "components/content_settings/core/common/content_settings_pattern.h"
21 #include "components/content_settings/core/common/content_settings_utils.h"
22 #include "content/public/child/child_thread.h"
23 #include "content/public/common/client_hints.mojom.h"
24 #include "content/public/common/origin_util.h"
25 #include "content/public/common/previews_state.h"
26 #include "content/public/common/url_constants.h"
27 #include "content/public/renderer/document_state.h"
28 #include "content/public/renderer/render_frame.h"
29 #include "content/public/renderer/render_view.h"
30 #include "extensions/buildflags/buildflags.h"
31 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
32 #include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
33 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
34 #include "third_party/blink/public/platform/url_conversion.h"
35 #include "third_party/blink/public/platform/web_client_hints_type.h"
36 #include "third_party/blink/public/platform/web_security_origin.h"
37 #include "third_party/blink/public/platform/web_url.h"
38 #include "third_party/blink/public/web/web_document.h"
39 #include "third_party/blink/public/web/web_local_frame.h"
40 #include "third_party/blink/public/web/web_local_frame_client.h"
41 #include "third_party/blink/public/web/web_view.h"
42 #include "url/gurl.h"
43 #include "url/origin.h"
44 #include "url/url_constants.h"
45
46 #if BUILDFLAG(ENABLE_EXTENSIONS)
47 #include "extensions/common/constants.h"
48 #include "extensions/common/extension.h"
49 #include "extensions/common/permissions/api_permission.h"
50 #include "extensions/common/permissions/permissions_data.h"
51 #include "extensions/renderer/dispatcher.h"
52 #include "extensions/renderer/renderer_extension_registry.h"
53 #endif
54
55 using blink::WebDocument;
56 using blink::WebFrame;
57 using blink::WebLocalFrame;
58 using blink::WebSecurityOrigin;
59 using blink::WebString;
60 using blink::WebURL;
61 using blink::WebView;
62 using content::DocumentState;
63
64 namespace {
65
GetOriginOrURL(const WebFrame * frame)66 GURL GetOriginOrURL(const WebFrame* frame) {
67 url::Origin top_origin = url::Origin(frame->Top()->GetSecurityOrigin());
68 // The |top_origin| is unique ("null") e.g., for file:// URLs. Use the
69 // document URL as the primary URL in those cases.
70 // TODO(alexmos): This is broken for --site-per-process, since top() can be a
71 // WebRemoteFrame which does not have a document(), and the WebRemoteFrame's
72 // URL is not replicated. See https://crbug.com/628759.
73 if (top_origin.opaque() && frame->Top()->IsWebLocalFrame())
74 return frame->Top()->ToWebLocalFrame()->GetDocument().Url();
75 return top_origin.GetURL();
76 }
77
78 // Allow passing both WebURL and GURL here, so that we can early return without
79 // allocating a new backing string if only the default rule matches.
80 template <typename URL>
GetContentSettingFromRules(const ContentSettingsForOneType & rules,const WebFrame * frame,const URL & secondary_url)81 ContentSetting GetContentSettingFromRules(
82 const ContentSettingsForOneType& rules,
83 const WebFrame* frame,
84 const URL& secondary_url) {
85 // If there is only one rule, it's the default rule and we don't need to match
86 // the patterns.
87 if (rules.size() == 1) {
88 DCHECK(rules[0].primary_pattern == ContentSettingsPattern::Wildcard());
89 DCHECK(rules[0].secondary_pattern == ContentSettingsPattern::Wildcard());
90 return rules[0].GetContentSetting();
91 }
92 const GURL& primary_url = GetOriginOrURL(frame);
93 const GURL& secondary_gurl = secondary_url;
94 for (const auto& rule : rules) {
95 if (rule.primary_pattern.Matches(primary_url) &&
96 rule.secondary_pattern.Matches(secondary_gurl)) {
97 return rule.GetContentSetting();
98 }
99 }
100 NOTREACHED();
101 return CONTENT_SETTING_DEFAULT;
102 }
103
IsScriptDisabledForPreview(content::RenderFrame * render_frame)104 bool IsScriptDisabledForPreview(content::RenderFrame* render_frame) {
105 return render_frame->GetPreviewsState() & content::NOSCRIPT_ON;
106 }
107
IsFrameWithOpaqueOrigin(WebFrame * frame)108 bool IsFrameWithOpaqueOrigin(WebFrame* frame) {
109 // Storage access is keyed off the top origin and the frame's origin.
110 // It will be denied any opaque origins so have this method to return early
111 // instead of making a Sync IPC call.
112 return frame->GetSecurityOrigin().IsOpaque() ||
113 frame->Top()->GetSecurityOrigin().IsOpaque();
114 }
115
116 } // namespace
117
ContentSettingsAgentImpl(content::RenderFrame * render_frame,bool should_whitelist,service_manager::BinderRegistry * registry)118 ContentSettingsAgentImpl::ContentSettingsAgentImpl(
119 content::RenderFrame* render_frame,
120 bool should_whitelist,
121 service_manager::BinderRegistry* registry)
122 : content::RenderFrameObserver(render_frame),
123 content::RenderFrameObserverTracker<ContentSettingsAgentImpl>(
124 render_frame),
125 should_whitelist_(should_whitelist) {
126 ClearBlockedContentSettings();
127 render_frame->GetWebFrame()->SetContentSettingsClient(this);
128
129 render_frame->GetAssociatedInterfaceRegistry()->AddInterface(
130 base::Bind(&ContentSettingsAgentImpl::OnContentSettingsAgentRequest,
131 base::Unretained(this)));
132
133 content::RenderFrame* main_frame =
134 render_frame->GetRenderView()->GetMainRenderFrame();
135 // TODO(nasko): The main frame is not guaranteed to be in the same process
136 // with this frame with --site-per-process. This code needs to be updated
137 // to handle this case. See https://crbug.com/496670.
138 if (main_frame && main_frame != render_frame) {
139 // Copy all the settings from the main render frame to avoid race conditions
140 // when initializing this data. See https://crbug.com/333308.
141 ContentSettingsAgentImpl* parent =
142 ContentSettingsAgentImpl::Get(main_frame);
143 allow_running_insecure_content_ = parent->allow_running_insecure_content_;
144 temporarily_allowed_plugins_ = parent->temporarily_allowed_plugins_;
145 is_interstitial_page_ = parent->is_interstitial_page_;
146 }
147 }
148
~ContentSettingsAgentImpl()149 ContentSettingsAgentImpl::~ContentSettingsAgentImpl() {}
150
151 chrome::mojom::ContentSettingsManager&
GetContentSettingsManager()152 ContentSettingsAgentImpl::GetContentSettingsManager() {
153 if (!content_settings_manager_)
154 BindContentSettingsManager(&content_settings_manager_);
155 return *content_settings_manager_;
156 }
157
158 #if BUILDFLAG(ENABLE_EXTENSIONS)
SetExtensionDispatcher(extensions::Dispatcher * extension_dispatcher)159 void ContentSettingsAgentImpl::SetExtensionDispatcher(
160 extensions::Dispatcher* extension_dispatcher) {
161 DCHECK(!extension_dispatcher_)
162 << "SetExtensionDispatcher() should only be called once.";
163 extension_dispatcher_ = extension_dispatcher;
164 }
165 #endif
166
SetContentSettingRules(const RendererContentSettingRules * content_setting_rules)167 void ContentSettingsAgentImpl::SetContentSettingRules(
168 const RendererContentSettingRules* content_setting_rules) {
169 content_setting_rules_ = content_setting_rules;
170 UMA_HISTOGRAM_COUNTS_1M("ClientHints.CountRulesReceived",
171 content_setting_rules_->client_hints_rules.size());
172 }
173
174 const RendererContentSettingRules*
GetContentSettingRules()175 ContentSettingsAgentImpl::GetContentSettingRules() {
176 return content_setting_rules_;
177 }
178
IsPluginTemporarilyAllowed(const std::string & identifier)179 bool ContentSettingsAgentImpl::IsPluginTemporarilyAllowed(
180 const std::string& identifier) {
181 // If the empty string is in here, it means all plugins are allowed.
182 // TODO(bauerb): Remove this once we only pass in explicit identifiers.
183 return base::Contains(temporarily_allowed_plugins_, identifier) ||
184 base::Contains(temporarily_allowed_plugins_, std::string());
185 }
186
DidBlockContentType(ContentSettingsType settings_type)187 void ContentSettingsAgentImpl::DidBlockContentType(
188 ContentSettingsType settings_type) {
189 bool newly_blocked = content_blocked_.insert(settings_type).second;
190 if (newly_blocked)
191 GetContentSettingsManager().OnContentBlocked(routing_id(), settings_type);
192 }
193
BindContentSettingsManager(mojo::Remote<chrome::mojom::ContentSettingsManager> * manager)194 void ContentSettingsAgentImpl::BindContentSettingsManager(
195 mojo::Remote<chrome::mojom::ContentSettingsManager>* manager) {
196 DCHECK(!*manager);
197 content::ChildThread::Get()->BindHostReceiver(
198 manager->BindNewPipeAndPassReceiver());
199 }
200
OnMessageReceived(const IPC::Message & message)201 bool ContentSettingsAgentImpl::OnMessageReceived(const IPC::Message& message) {
202 // Don't swallow LoadBlockedPlugins messages, as they're sent to every
203 // blocked plugin.
204 IPC_BEGIN_MESSAGE_MAP(ContentSettingsAgentImpl, message)
205 IPC_MESSAGE_HANDLER(ChromeViewMsg_LoadBlockedPlugins, OnLoadBlockedPlugins)
206 IPC_END_MESSAGE_MAP()
207 return false;
208 }
209
DidCommitProvisionalLoad(bool is_same_document_navigation,ui::PageTransition transition)210 void ContentSettingsAgentImpl::DidCommitProvisionalLoad(
211 bool is_same_document_navigation,
212 ui::PageTransition transition) {
213 blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
214 if (frame->Parent())
215 return; // Not a top-level navigation.
216
217 if (!is_same_document_navigation) {
218 // Clear "block" flags for the new page. This needs to happen before any of
219 // |allowScript()|, |allowScriptFromSource()|, |allowImage()|, or
220 // |allowPlugins()| is called for the new page so that these functions can
221 // correctly detect that a piece of content flipped from "not blocked" to
222 // "blocked".
223 ClearBlockedContentSettings();
224 temporarily_allowed_plugins_.clear();
225
226 // The BrowserInterfaceBroker is reset on navigation, so we will need to
227 // re-acquire the ContentSettingsManager.
228 content_settings_manager_.reset();
229 }
230
231 GURL url = frame->GetDocument().Url();
232 // If we start failing this DCHECK, please makes sure we don't regress
233 // this bug: http://code.google.com/p/chromium/issues/detail?id=79304
234 DCHECK(frame->GetDocument().GetSecurityOrigin().ToString() == "null" ||
235 !url.SchemeIs(url::kDataScheme));
236 }
237
OnDestruct()238 void ContentSettingsAgentImpl::OnDestruct() {
239 delete this;
240 }
241
SetAllowRunningInsecureContent()242 void ContentSettingsAgentImpl::SetAllowRunningInsecureContent() {
243 allow_running_insecure_content_ = true;
244
245 // Reload if we are the main frame.
246 blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
247 if (!frame->Parent())
248 frame->StartReload(blink::WebFrameLoadType::kReload);
249 }
250
SetAsInterstitial()251 void ContentSettingsAgentImpl::SetAsInterstitial() {
252 is_interstitial_page_ = true;
253 }
254
SetDisabledMixedContentUpgrades()255 void ContentSettingsAgentImpl::SetDisabledMixedContentUpgrades() {
256 mixed_content_autoupgrades_disabled_ = true;
257 }
258
OnContentSettingsAgentRequest(mojo::PendingAssociatedReceiver<chrome::mojom::ContentSettingsAgent> receiver)259 void ContentSettingsAgentImpl::OnContentSettingsAgentRequest(
260 mojo::PendingAssociatedReceiver<chrome::mojom::ContentSettingsAgent>
261 receiver) {
262 receivers_.Add(this, std::move(receiver));
263 }
264
AllowDatabase()265 bool ContentSettingsAgentImpl::AllowDatabase() {
266 return AllowStorageAccess(
267 chrome::mojom::ContentSettingsManager::StorageType::DATABASE);
268 }
269
RequestFileSystemAccessAsync(base::OnceCallback<void (bool)> callback)270 void ContentSettingsAgentImpl::RequestFileSystemAccessAsync(
271 base::OnceCallback<void(bool)> callback) {
272 WebLocalFrame* frame = render_frame()->GetWebFrame();
273 if (IsFrameWithOpaqueOrigin(frame)) {
274 std::move(callback).Run(false);
275 return;
276 }
277
278 GetContentSettingsManager().AllowStorageAccess(
279 routing_id(),
280 chrome::mojom::ContentSettingsManager::StorageType::FILE_SYSTEM,
281 frame->GetSecurityOrigin(),
282 frame->GetDocument().SiteForCookies().RepresentativeUrl(),
283 frame->GetDocument().TopFrameOrigin(), std::move(callback));
284 }
285
AllowImage(bool enabled_per_settings,const WebURL & image_url)286 bool ContentSettingsAgentImpl::AllowImage(bool enabled_per_settings,
287 const WebURL& image_url) {
288 bool allow = enabled_per_settings;
289 if (enabled_per_settings) {
290 if (is_interstitial_page_)
291 return true;
292
293 if (IsWhitelistedForContentSettings())
294 return true;
295
296 if (content_setting_rules_) {
297 allow = GetContentSettingFromRules(content_setting_rules_->image_rules,
298 render_frame()->GetWebFrame(),
299 image_url) != CONTENT_SETTING_BLOCK;
300 }
301 }
302 if (!allow)
303 DidBlockContentType(ContentSettingsType::IMAGES);
304 return allow;
305 }
306
AllowIndexedDB()307 bool ContentSettingsAgentImpl::AllowIndexedDB() {
308 return AllowStorageAccess(
309 chrome::mojom::ContentSettingsManager::StorageType::INDEXED_DB);
310 }
311
AllowCacheStorage()312 bool ContentSettingsAgentImpl::AllowCacheStorage() {
313 return AllowStorageAccess(
314 chrome::mojom::ContentSettingsManager::StorageType::CACHE);
315 }
316
AllowWebLocks()317 bool ContentSettingsAgentImpl::AllowWebLocks() {
318 return AllowStorageAccess(
319 chrome::mojom::ContentSettingsManager::StorageType::WEB_LOCKS);
320 }
321
AllowScript(bool enabled_per_settings)322 bool ContentSettingsAgentImpl::AllowScript(bool enabled_per_settings) {
323 if (!enabled_per_settings)
324 return false;
325 if (IsScriptDisabledForPreview(render_frame()))
326 return false;
327 if (is_interstitial_page_)
328 return true;
329
330 blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
331 const auto it = cached_script_permissions_.find(frame);
332 if (it != cached_script_permissions_.end())
333 return it->second;
334
335 // Evaluate the content setting rules before
336 // IsWhitelistedForContentSettings(); if there is only the default rule
337 // allowing all scripts, it's quicker this way.
338 bool allow = true;
339 if (content_setting_rules_) {
340 ContentSetting setting = GetContentSettingFromRules(
341 content_setting_rules_->script_rules, frame,
342 url::Origin(frame->GetDocument().GetSecurityOrigin()).GetURL());
343 allow = setting != CONTENT_SETTING_BLOCK;
344 }
345 allow = allow || IsWhitelistedForContentSettings();
346
347 cached_script_permissions_[frame] = allow;
348 return allow;
349 }
350
AllowScriptFromSource(bool enabled_per_settings,const blink::WebURL & script_url)351 bool ContentSettingsAgentImpl::AllowScriptFromSource(
352 bool enabled_per_settings,
353 const blink::WebURL& script_url) {
354 if (!enabled_per_settings)
355 return false;
356 if (IsScriptDisabledForPreview(render_frame()))
357 return false;
358 if (is_interstitial_page_)
359 return true;
360
361 bool allow = true;
362 if (content_setting_rules_) {
363 ContentSetting setting =
364 GetContentSettingFromRules(content_setting_rules_->script_rules,
365 render_frame()->GetWebFrame(), script_url);
366 allow = setting != CONTENT_SETTING_BLOCK;
367 }
368 return allow || IsWhitelistedForContentSettings();
369 }
370
AllowStorage(bool local)371 bool ContentSettingsAgentImpl::AllowStorage(bool local) {
372 WebLocalFrame* frame = render_frame()->GetWebFrame();
373 if (IsFrameWithOpaqueOrigin(frame))
374 return false;
375
376 StoragePermissionsKey key(
377 url::Origin(frame->GetDocument().GetSecurityOrigin()).GetURL(), local);
378 const auto permissions = cached_storage_permissions_.find(key);
379 if (permissions != cached_storage_permissions_.end())
380 return permissions->second;
381
382 bool result = false;
383 GetContentSettingsManager().AllowStorageAccess(
384 routing_id(),
385 local
386 ? chrome::mojom::ContentSettingsManager::StorageType::LOCAL_STORAGE
387 : chrome::mojom::ContentSettingsManager::StorageType::SESSION_STORAGE,
388 frame->GetSecurityOrigin(),
389 frame->GetDocument().SiteForCookies().RepresentativeUrl(),
390 frame->GetDocument().TopFrameOrigin(), &result);
391 cached_storage_permissions_[key] = result;
392 return result;
393 }
394
AllowReadFromClipboard(bool default_value)395 bool ContentSettingsAgentImpl::AllowReadFromClipboard(bool default_value) {
396 bool allowed = default_value;
397 #if BUILDFLAG(ENABLE_EXTENSIONS)
398 extensions::ScriptContext* current_context =
399 extension_dispatcher_->script_context_set().GetCurrent();
400 if (current_context) {
401 allowed |= current_context->HasAPIPermission(
402 extensions::APIPermission::kClipboardRead);
403 }
404 #endif
405 return allowed;
406 }
407
AllowWriteToClipboard(bool default_value)408 bool ContentSettingsAgentImpl::AllowWriteToClipboard(bool default_value) {
409 bool allowed = default_value;
410 #if BUILDFLAG(ENABLE_EXTENSIONS)
411 // All blessed extension pages could historically write to the clipboard, so
412 // preserve that for compatibility.
413 extensions::ScriptContext* current_context =
414 extension_dispatcher_->script_context_set().GetCurrent();
415 if (current_context) {
416 if (current_context->effective_context_type() ==
417 extensions::Feature::BLESSED_EXTENSION_CONTEXT &&
418 !current_context->IsForServiceWorker()) {
419 allowed = true;
420 } else {
421 allowed |= current_context->HasAPIPermission(
422 extensions::APIPermission::kClipboardWrite);
423 }
424 }
425 #endif
426 return allowed;
427 }
428
AllowMutationEvents(bool default_value)429 bool ContentSettingsAgentImpl::AllowMutationEvents(bool default_value) {
430 return IsPlatformApp() ? false : default_value;
431 }
432
AllowRunningInsecureContent(bool allowed_per_settings,const blink::WebURL & resource_url)433 bool ContentSettingsAgentImpl::AllowRunningInsecureContent(
434 bool allowed_per_settings,
435 const blink::WebURL& resource_url) {
436 bool allow = allowed_per_settings;
437
438 if (base::FeatureList::IsEnabled(features::kMixedContentSiteSetting)) {
439 if (content_setting_rules_) {
440 auto setting = GetContentSettingFromRules(
441 content_setting_rules_->mixed_content_rules,
442 render_frame()->GetWebFrame(), GURL());
443 allow |= (setting == CONTENT_SETTING_ALLOW);
444 }
445 } else {
446 allow |= allow_running_insecure_content_;
447 if (!allow) {
448 DidBlockContentType(ContentSettingsType::MIXEDSCRIPT);
449 }
450 }
451
452 // Note: this implementation is a mirror of
453 // Browser::ShouldAllowRunningInsecureContent.
454 FilteredReportInsecureContentRan(GURL(resource_url));
455
456 return allow;
457 }
458
AllowPopupsAndRedirects(bool default_value)459 bool ContentSettingsAgentImpl::AllowPopupsAndRedirects(bool default_value) {
460 if (!content_setting_rules_)
461 return default_value;
462 blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
463 return GetContentSettingFromRules(
464 content_setting_rules_->popup_redirect_rules, frame,
465 url::Origin(frame->GetDocument().GetSecurityOrigin()).GetURL()) ==
466 CONTENT_SETTING_ALLOW;
467 }
468
PassiveInsecureContentFound(const blink::WebURL & resource_url)469 void ContentSettingsAgentImpl::PassiveInsecureContentFound(
470 const blink::WebURL& resource_url) {
471 // Note: this implementation is a mirror of
472 // Browser::PassiveInsecureContentFound.
473 ReportInsecureContent(SslInsecureContentType::DISPLAY);
474 FilteredReportInsecureContentDisplayed(GURL(resource_url));
475 }
476
PersistClientHints(const blink::WebEnabledClientHints & enabled_client_hints,base::TimeDelta duration,const blink::WebURL & url)477 void ContentSettingsAgentImpl::PersistClientHints(
478 const blink::WebEnabledClientHints& enabled_client_hints,
479 base::TimeDelta duration,
480 const blink::WebURL& url) {
481 if (duration <= base::TimeDelta())
482 return;
483
484 const GURL primary_url(url);
485 const url::Origin primary_origin = url::Origin::Create(primary_url);
486 if (!content::IsOriginSecure(primary_url))
487 return;
488
489 // TODO(tbansal): crbug.com/735518. Determine if the value should be
490 // merged or overridden. Also, determine if the merger should happen on the
491 // browser side or the renderer. If the value needs to be overridden,
492 // this method should not return early if |update_count| is 0.
493 std::vector<::blink::mojom::WebClientHintsType> client_hints;
494 static constexpr size_t kWebClientHintsCount =
495 static_cast<size_t>(blink::mojom::WebClientHintsType::kMaxValue) + 1;
496 client_hints.reserve(kWebClientHintsCount);
497
498 for (size_t i = 0; i < kWebClientHintsCount; ++i) {
499 if (enabled_client_hints.IsEnabled(
500 static_cast<blink::mojom::WebClientHintsType>(i))) {
501 client_hints.push_back(static_cast<blink::mojom::WebClientHintsType>(i));
502 }
503 }
504 size_t update_count = client_hints.size();
505 if (update_count == 0)
506 return;
507
508 UMA_HISTOGRAM_CUSTOM_TIMES(
509 "ClientHints.PersistDuration", duration, base::TimeDelta::FromSeconds(1),
510 // TODO(crbug.com/949034): Rename and fix this histogram to have some
511 // intended max value. We throw away the 32 most-significant bits of the
512 // 64-bit time delta in milliseconds. Before it happened silently in
513 // histogram.cc, now it is explicit here. The previous value of 365 days
514 // effectively turns into roughly 17 days when getting cast to int.
515 base::TimeDelta::FromMilliseconds(
516 static_cast<int>(base::TimeDelta::FromDays(365).InMilliseconds())),
517 100);
518
519 UMA_HISTOGRAM_COUNTS_100("ClientHints.UpdateSize", update_count);
520
521 // Notify the embedder.
522 mojo::AssociatedRemote<client_hints::mojom::ClientHints> host_observer;
523 render_frame()->GetRemoteAssociatedInterfaces()->GetInterface(&host_observer);
524 host_observer->PersistClientHints(primary_origin, std::move(client_hints),
525 duration);
526 }
527
GetAllowedClientHintsFromSource(const blink::WebURL & url,blink::WebEnabledClientHints * client_hints) const528 void ContentSettingsAgentImpl::GetAllowedClientHintsFromSource(
529 const blink::WebURL& url,
530 blink::WebEnabledClientHints* client_hints) const {
531 if (!content_setting_rules_)
532 return;
533
534 if (content_setting_rules_->client_hints_rules.empty())
535 return;
536
537 client_hints::GetAllowedClientHintsFromSource(
538 url, content_setting_rules_->client_hints_rules, client_hints);
539 }
540
ShouldAutoupgradeMixedContent()541 bool ContentSettingsAgentImpl::ShouldAutoupgradeMixedContent() {
542 if (mixed_content_autoupgrades_disabled_)
543 return false;
544
545 if (content_setting_rules_) {
546 auto setting =
547 GetContentSettingFromRules(content_setting_rules_->mixed_content_rules,
548 render_frame()->GetWebFrame(), GURL());
549 return setting != CONTENT_SETTING_ALLOW;
550 }
551 return false;
552 }
553
DidNotAllowPlugins()554 void ContentSettingsAgentImpl::DidNotAllowPlugins() {
555 DidBlockContentType(ContentSettingsType::PLUGINS);
556 }
557
DidNotAllowScript()558 void ContentSettingsAgentImpl::DidNotAllowScript() {
559 DidBlockContentType(ContentSettingsType::JAVASCRIPT);
560 }
561
OnLoadBlockedPlugins(const std::string & identifier)562 void ContentSettingsAgentImpl::OnLoadBlockedPlugins(
563 const std::string& identifier) {
564 temporarily_allowed_plugins_.insert(identifier);
565 }
566
ClearBlockedContentSettings()567 void ContentSettingsAgentImpl::ClearBlockedContentSettings() {
568 content_blocked_.clear();
569 cached_storage_permissions_.clear();
570 cached_script_permissions_.clear();
571 }
572
IsPlatformApp()573 bool ContentSettingsAgentImpl::IsPlatformApp() {
574 #if BUILDFLAG(ENABLE_EXTENSIONS)
575 blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
576 WebSecurityOrigin origin = frame->GetDocument().GetSecurityOrigin();
577 const extensions::Extension* extension = GetExtension(origin);
578 return extension && extension->is_platform_app();
579 #else
580 return false;
581 #endif
582 }
583
584 #if BUILDFLAG(ENABLE_EXTENSIONS)
GetExtension(const WebSecurityOrigin & origin) const585 const extensions::Extension* ContentSettingsAgentImpl::GetExtension(
586 const WebSecurityOrigin& origin) const {
587 if (origin.Protocol().Ascii() != extensions::kExtensionScheme)
588 return nullptr;
589
590 const std::string extension_id = origin.Host().Utf8().data();
591 if (!extension_dispatcher_->IsExtensionActive(extension_id))
592 return nullptr;
593
594 return extensions::RendererExtensionRegistry::Get()->GetByID(extension_id);
595 }
596 #endif
597
598 // static
IsWhitelistedForContentSettings() const599 bool ContentSettingsAgentImpl::IsWhitelistedForContentSettings() const {
600 if (should_whitelist_)
601 return true;
602
603 // Whitelist ftp directory listings, as they require JavaScript to function
604 // properly.
605 if (render_frame()->IsFTPDirectoryListing())
606 return true;
607
608 const WebDocument& document = render_frame()->GetWebFrame()->GetDocument();
609 return IsWhitelistedForContentSettings(document.GetSecurityOrigin(),
610 document.Url());
611 }
612
IsWhitelistedForContentSettings(const WebSecurityOrigin & origin,const WebURL & document_url)613 bool ContentSettingsAgentImpl::IsWhitelistedForContentSettings(
614 const WebSecurityOrigin& origin,
615 const WebURL& document_url) {
616 if (document_url.GetString() == content::kUnreachableWebDataURL)
617 return true;
618
619 if (origin.IsOpaque())
620 return false; // Uninitialized document?
621
622 blink::WebString protocol = origin.Protocol();
623
624 if (protocol == content::kChromeUIScheme)
625 return true; // Browser UI elements should still work.
626
627 if (protocol == content::kChromeDevToolsScheme)
628 return true; // DevTools UI elements should still work.
629
630 #if BUILDFLAG(ENABLE_EXTENSIONS)
631 if (protocol == extensions::kExtensionScheme)
632 return true;
633 #endif
634
635 // If the scheme is file:, an empty file name indicates a directory listing,
636 // which requires JavaScript to function properly.
637 if (protocol == url::kFileScheme &&
638 document_url.ProtocolIs(url::kFileScheme)) {
639 return GURL(document_url).ExtractFileName().empty();
640 }
641 return false;
642 }
643
AllowStorageAccess(chrome::mojom::ContentSettingsManager::StorageType storage_type)644 bool ContentSettingsAgentImpl::AllowStorageAccess(
645 chrome::mojom::ContentSettingsManager::StorageType storage_type) {
646 WebLocalFrame* frame = render_frame()->GetWebFrame();
647 if (IsFrameWithOpaqueOrigin(frame))
648 return false;
649
650 bool result = false;
651 GetContentSettingsManager().AllowStorageAccess(
652 routing_id(), storage_type, frame->GetSecurityOrigin(),
653 frame->GetDocument().SiteForCookies().RepresentativeUrl(),
654 frame->GetDocument().TopFrameOrigin(), &result);
655 return result;
656 }
657