12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/content_settings/browser/page_specific_content_settings.h"
- #include <list>
- #include <vector>
- #include "base/command_line.h"
- #include "base/lazy_instance.h"
- #include "base/memory/ptr_util.h"
- #include "base/observer_list.h"
- #include "base/strings/string_util.h"
- #include "base/strings/utf_string_conversions.h"
- #include "build/build_config.h"
- #include "build/chromeos_buildflags.h"
- #include "components/browsing_data/content/cache_storage_helper.h"
- #include "components/browsing_data/content/cookie_helper.h"
- #include "components/browsing_data/content/database_helper.h"
- #include "components/browsing_data/content/file_system_helper.h"
- #include "components/browsing_data/content/indexed_db_helper.h"
- #include "components/browsing_data/content/local_storage_helper.h"
- #include "components/browsing_data/content/service_worker_helper.h"
- #include "components/browsing_data/content/shared_worker_helper.h"
- #include "components/content_settings/common/content_settings_agent.mojom.h"
- #include "components/content_settings/core/browser/content_settings_info.h"
- #include "components/content_settings/core/browser/content_settings_registry.h"
- #include "components/content_settings/core/browser/content_settings_utils.h"
- #include "components/content_settings/core/common/content_settings_utils.h"
- #include "components/prefs/pref_service.h"
- #include "components/privacy_sandbox/canonical_topic.h"
- #include "components/privacy_sandbox/privacy_sandbox_features.h"
- #include "content/public/browser/browser_thread.h"
- #include "content/public/browser/cookie_access_details.h"
- #include "content/public/browser/navigation_handle.h"
- #include "content/public/browser/navigation_handle_user_data.h"
- #include "content/public/browser/page.h"
- #include "content/public/browser/render_frame_host.h"
- #include "content/public/browser/render_process_host.h"
- #include "content/public/browser/render_view_host.h"
- #include "content/public/browser/web_contents.h"
- #include "content/public/browser/web_contents_delegate.h"
- #include "content/public/browser/web_contents_observer.h"
- #include "content/public/browser/web_contents_user_data.h"
- #include "content/public/common/content_constants.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
- #include "third_party/blink/public/common/storage_key/storage_key.h"
- #include "url/origin.h"
- using content::BrowserThread;
- using StorageType =
- content_settings::mojom::ContentSettingsManager::StorageType;
- using LifecycleState = content::RenderFrameHost::LifecycleState;
- namespace content_settings {
- namespace {
- bool WillNavigationCreateNewPageSpecificContentSettingsOnCommit(
- content::NavigationHandle* navigation_handle) {
- return navigation_handle->IsInMainFrame() &&
- !navigation_handle->IsSameDocument() &&
- !navigation_handle->IsServedFromBackForwardCache() &&
- !navigation_handle->IsPrerenderedPageActivation();
- }
- // Keeps track of cookie and service worker access during a navigation.
- // These types of access can happen for the current page or for a new
- // navigation (think cookies sent in the HTTP request or service worker
- // being run to serve a fetch request). A navigation might fail to
- // commit in which case we have to handle it as if it had never
- // occurred. So we cache all cookies and service worker accesses that
- // happen during a navigation and only apply the changes if the
- // navigation commits.
- class InflightNavigationContentSettings
- : public content::NavigationHandleUserData<
- InflightNavigationContentSettings> {
- public:
- ~InflightNavigationContentSettings() override;
- std::vector<content::CookieAccessDetails> cookie_accesses;
- std::vector<std::pair<GURL, content::AllowServiceWorkerResult>>
- service_worker_accesses;
- private:
- explicit InflightNavigationContentSettings(
- content::NavigationHandle& navigation_handle);
- friend class content::NavigationHandleUserData<
- InflightNavigationContentSettings>;
- NAVIGATION_HANDLE_USER_DATA_KEY_DECL();
- };
- // This class attaches to WebContents to listen to events and route them to
- // appropriate PageSpecificContentSettings, store navigation related events
- // until the navigation finishes and then transferring the
- // navigation-associated state to the newly-created page.
- class WebContentsHandler
- : public content::WebContentsObserver,
- public content::WebContentsUserData<WebContentsHandler> {
- public:
- using Delegate = PageSpecificContentSettings::Delegate;
- using SiteDataObserver = PageSpecificContentSettings::SiteDataObserver;
- explicit WebContentsHandler(content::WebContents* web_contents,
- std::unique_ptr<Delegate> delegate);
- ~WebContentsHandler() override;
- // Adds the given |SiteDataObserver|. The |observer| is notified when a
- // locale shared object, like for example a cookie, is accessed.
- void AddSiteDataObserver(SiteDataObserver* observer);
- // Removes the given |SiteDataObserver|.
- void RemoveSiteDataObserver(SiteDataObserver* observer);
- // Notifies all registered |SiteDataObserver|s.
- void NotifySiteDataObservers();
- // Queues update sent while the navigation is still in progress. The update
- // is run after the navigation completes (DidFinishNavigation).
- void AddPendingCommitUpdate(content::GlobalRenderFrameHostId id,
- base::OnceClosure update);
- Delegate* delegate() { return delegate_.get(); }
- private:
- friend class content::WebContentsUserData<WebContentsHandler>;
- // Applies all stored events for the given navigation to the current main
- // document.
- void TransferNavigationContentSettingsToCommittedDocument(
- const InflightNavigationContentSettings& navigation_settings,
- content::RenderFrameHost* rfh);
- // content::WebContentsObserver overrides.
- void ReadyToCommitNavigation(
- content::NavigationHandle* navigation_handle) override;
- void DidFinishNavigation(
- content::NavigationHandle* navigation_handle) override;
- void OnCookiesAccessed(content::NavigationHandle* navigation,
- const content::CookieAccessDetails& details) override;
- void OnCookiesAccessed(content::RenderFrameHost* rfh,
- const content::CookieAccessDetails& details) override;
- // Called when a specific Service Worker scope was accessed.
- // If access was blocked due to the user's content settings,
- // |blocked_by_policy_javascript| or/and |blocked_by_policy_cookie|
- // should be true, and this function should invoke OnContentBlocked for
- // JavaScript or/and cookies respectively.
- void OnServiceWorkerAccessed(
- content::NavigationHandle* navigation,
- const GURL& scope,
- content::AllowServiceWorkerResult allowed) override;
- void OnServiceWorkerAccessed(
- content::RenderFrameHost* frame,
- const GURL& scope,
- content::AllowServiceWorkerResult allowed) override;
- std::unique_ptr<Delegate> delegate_;
- raw_ptr<HostContentSettingsMap> map_;
- // All currently registered |SiteDataObserver|s.
- base::ObserverList<SiteDataObserver>::Unchecked observer_list_;
- std::map<content::GlobalRenderFrameHostId, std::vector<base::OnceClosure>>
- pending_commit_updates_;
- WEB_CONTENTS_USER_DATA_KEY_DECL();
- };
- // Certain notifications for content accesses (script/storage) can be
- // received from the renderer while the RFH is in the kPendingCommit lifecycle
- // state. At this point, no PageSpecificContentSettings object is created (as
- // this only happens in DidFinishNavigation), so we queue up the update until
- // DidFinishNavigation is called. This method returns true if the update is
- // queued, false otherwise.
- template <typename Method, typename... Args>
- bool DelayUntilCommitIfNecessary(content::RenderFrameHost* rfh,
- Method method,
- Args... args) {
- if (!rfh)
- return false;
- if (rfh->GetLifecycleState() == LifecycleState::kPendingCommit) {
- auto* handler = WebContentsHandler::FromWebContents(
- content::WebContents::FromRenderFrameHost(rfh));
- if (!handler)
- return false;
- handler->AddPendingCommitUpdate(rfh->GetGlobalId(),
- base::BindOnce(method, args...));
- return true;
- }
- return false;
- }
- } // namespace
- InflightNavigationContentSettings::InflightNavigationContentSettings(
- content::NavigationHandle&) {}
- InflightNavigationContentSettings::~InflightNavigationContentSettings() =
- default;
- NAVIGATION_HANDLE_USER_DATA_KEY_IMPL(InflightNavigationContentSettings);
- WebContentsHandler::WebContentsHandler(content::WebContents* web_contents,
- std::unique_ptr<Delegate> delegate)
- : WebContentsObserver(web_contents),
- content::WebContentsUserData<WebContentsHandler>(*web_contents),
- delegate_(std::move(delegate)),
- map_(delegate_->GetSettingsMap()) {
- DCHECK(
- !PageSpecificContentSettings::GetForPage(web_contents->GetPrimaryPage()));
- content::PageUserData<PageSpecificContentSettings>::CreateForPage(
- web_contents->GetPrimaryPage(), delegate_.get());
- }
- WebContentsHandler::~WebContentsHandler() {
- for (SiteDataObserver& observer : observer_list_)
- observer.WebContentsDestroyed();
- }
- void WebContentsHandler::TransferNavigationContentSettingsToCommittedDocument(
- const InflightNavigationContentSettings& navigation_settings,
- content::RenderFrameHost* rfh) {
- for (const auto& cookie_access : navigation_settings.cookie_accesses) {
- OnCookiesAccessed(rfh, cookie_access);
- }
- for (const auto& service_worker_access :
- navigation_settings.service_worker_accesses) {
- OnServiceWorkerAccessed(rfh, service_worker_access.first,
- service_worker_access.second);
- }
- }
- void WebContentsHandler::OnCookiesAccessed(
- content::NavigationHandle* navigation,
- const content::CookieAccessDetails& details) {
- if (WillNavigationCreateNewPageSpecificContentSettingsOnCommit(navigation)) {
- auto* inflight_navigation_settings =
- content::NavigationHandleUserData<InflightNavigationContentSettings>::
- GetOrCreateForNavigationHandle(*navigation);
- inflight_navigation_settings->cookie_accesses.push_back(details);
- return;
- }
- // All accesses during main frame navigations should enter the block above and
- // not reach here. We also don't expect any accesses to be made during page
- // activations or same-document navigations.
- DCHECK(navigation->GetParentFrame());
- OnCookiesAccessed(navigation->GetParentFrame()->GetMainFrame(), details);
- }
- void WebContentsHandler::OnCookiesAccessed(
- content::RenderFrameHost* rfh,
- const content::CookieAccessDetails& details) {
- auto* pscs = PageSpecificContentSettings::GetForPage(rfh->GetPage());
- if (pscs)
- pscs->OnCookiesAccessed(details);
- }
- void WebContentsHandler::OnServiceWorkerAccessed(
- content::NavigationHandle* navigation,
- const GURL& scope,
- content::AllowServiceWorkerResult allowed) {
- DCHECK(scope.is_valid());
- if (WillNavigationCreateNewPageSpecificContentSettingsOnCommit(navigation)) {
- auto* inflight_navigation_settings =
- content::NavigationHandleUserData<InflightNavigationContentSettings>::
- GetOrCreateForNavigationHandle(*navigation);
- inflight_navigation_settings->service_worker_accesses.emplace_back(
- std::make_pair(scope, allowed));
- return;
- }
- // All accesses during main frame navigations should enter the block above and
- // not reach here. We also don't expect any accesses to be made during page
- // activations or same-document navigations.
- DCHECK(navigation->GetParentFrame());
- OnServiceWorkerAccessed(navigation->GetParentFrame()->GetMainFrame(), scope,
- allowed);
- }
- void WebContentsHandler::OnServiceWorkerAccessed(
- content::RenderFrameHost* frame,
- const GURL& scope,
- content::AllowServiceWorkerResult allowed) {
- auto* pscs = PageSpecificContentSettings::GetForPage(frame->GetPage());
- if (pscs)
- pscs->OnServiceWorkerAccessed(scope, allowed);
- }
- void WebContentsHandler::ReadyToCommitNavigation(
- content::NavigationHandle* navigation_handle) {
- content::RenderFrameHost* rfh = navigation_handle->GetRenderFrameHost();
- RendererContentSettingRules rules;
- content_settings::GetRendererContentSettingRules(map_, &rules);
- delegate()->SetDefaultRendererContentSettingRules(rfh, &rules);
- const GURL& primary_url =
- navigation_handle->GetParentFrameOrOuterDocument()
- ? navigation_handle->GetParentFrameOrOuterDocument()
- ->GetLastCommittedURL()
- : navigation_handle->GetURL();
- rules.FilterRulesByOutermostMainFrameURL(primary_url);
- mojo::AssociatedRemote<content_settings::mojom::ContentSettingsAgent> agent;
- rfh->GetRemoteAssociatedInterfaces()->GetInterface(&agent);
- // TODO(crbug.com/1187618): We shouldn't be sending the primary patterns here
- // because: a) we have already filtered based on them and they are not needed
- // in the renderer, and b) they could leak the embedder origin to embedded
- // pages like fenced frames.
- agent->SendRendererContentSettingRules(std::move(rules));
- }
- void WebContentsHandler::DidFinishNavigation(
- content::NavigationHandle* navigation_handle) {
- if (!navigation_handle->HasCommitted())
- return;
- if (WillNavigationCreateNewPageSpecificContentSettingsOnCommit(
- navigation_handle)) {
- content::PageUserData<PageSpecificContentSettings>::CreateForPage(
- navigation_handle->GetRenderFrameHost()->GetPage(), delegate_.get());
- InflightNavigationContentSettings* inflight_settings =
- content::NavigationHandleUserData<InflightNavigationContentSettings>::
- GetForNavigationHandle(*navigation_handle);
- if (inflight_settings) {
- TransferNavigationContentSettingsToCommittedDocument(
- *inflight_settings, navigation_handle->GetRenderFrameHost());
- }
- content::GlobalRenderFrameHostId rfh_id =
- navigation_handle->GetRenderFrameHost()->GetGlobalId();
- auto it = pending_commit_updates_.find(rfh_id);
- if (it != pending_commit_updates_.end()) {
- for (auto& update : it->second) {
- std::move(update).Run();
- }
- pending_commit_updates_.erase(it);
- }
- }
- if (navigation_handle->IsPrerenderedPageActivation()) {
- auto* pscs = PageSpecificContentSettings::GetForFrame(
- navigation_handle->GetRenderFrameHost());
- DCHECK(pscs);
- pscs->OnPrerenderingPageActivation();
- }
- if (navigation_handle->IsInPrimaryMainFrame())
- delegate_->UpdateLocationBar();
- }
- void WebContentsHandler::AddSiteDataObserver(SiteDataObserver* observer) {
- observer_list_.AddObserver(observer);
- }
- void WebContentsHandler::RemoveSiteDataObserver(SiteDataObserver* observer) {
- observer_list_.RemoveObserver(observer);
- }
- void WebContentsHandler::NotifySiteDataObservers() {
- for (SiteDataObserver& observer : observer_list_)
- observer.OnSiteDataAccessed();
- }
- void WebContentsHandler::AddPendingCommitUpdate(
- content::GlobalRenderFrameHostId id,
- base::OnceClosure update) {
- #if DCHECK_IS_ON()
- content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(id);
- DCHECK(rfh);
- DCHECK_EQ(rfh->GetLifecycleState(), LifecycleState::kPendingCommit);
- #endif
- pending_commit_updates_[id].push_back(std::move(update));
- }
- WEB_CONTENTS_USER_DATA_KEY_IMPL(WebContentsHandler);
- PageSpecificContentSettings::SiteDataObserver::SiteDataObserver(
- content::WebContents* web_contents)
- : web_contents_(web_contents) {
- // Make sure the handler was attached to the WebContents as some UT might skip
- // this.
- auto* handler = WebContentsHandler::FromWebContents(web_contents_);
- if (handler)
- handler->AddSiteDataObserver(this);
- }
- PageSpecificContentSettings::SiteDataObserver::~SiteDataObserver() {
- if (!web_contents_)
- return;
- auto* handler = WebContentsHandler::FromWebContents(web_contents_);
- if (handler)
- handler->RemoveSiteDataObserver(this);
- }
- void PageSpecificContentSettings::SiteDataObserver::WebContentsDestroyed() {
- web_contents_ = nullptr;
- }
- PageSpecificContentSettings::PendingUpdates::PendingUpdates() = default;
- PageSpecificContentSettings::PendingUpdates::~PendingUpdates() = default;
- PageSpecificContentSettings::PageSpecificContentSettings(content::Page& page,
- Delegate* delegate)
- : content::PageUserData<PageSpecificContentSettings>(page),
- delegate_(delegate),
- map_(delegate_->GetSettingsMap()),
- allowed_local_shared_objects_(GetWebContents()->GetBrowserContext(),
- /*ignore_empty_localstorage=*/true,
- delegate_->GetAdditionalFileSystemTypes(),
- delegate_->GetIsDeletionDisabledCallback()),
- blocked_local_shared_objects_(GetWebContents()->GetBrowserContext(),
- /*ignore_empty_localstorage=*/false,
- delegate_->GetAdditionalFileSystemTypes(),
- delegate_->GetIsDeletionDisabledCallback()),
- microphone_camera_state_(MICROPHONE_CAMERA_NOT_ACCESSED) {
- observation_.Observe(map_.get());
- if (page.GetMainDocument().GetLifecycleState() ==
- LifecycleState::kPrerendering) {
- updates_queued_during_prerender_ = std::make_unique<PendingUpdates>();
- }
- }
- PageSpecificContentSettings::~PageSpecificContentSettings() = default;
- // static
- void PageSpecificContentSettings::CreateForWebContents(
- content::WebContents* web_contents,
- std::unique_ptr<Delegate> delegate) {
- WebContentsHandler::CreateForWebContents(web_contents, std::move(delegate));
- }
- // static
- void PageSpecificContentSettings::DeleteForWebContentsForTest(
- content::WebContents* web_contents) {
- PageSpecificContentSettings::DeleteForPage(web_contents->GetPrimaryPage());
- web_contents->RemoveUserData(WebContentsHandler::UserDataKey());
- }
- // static
- PageSpecificContentSettings* PageSpecificContentSettings::GetForFrame(
- int render_process_id,
- int render_frame_id) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- return GetForFrame(
- content::RenderFrameHost::FromID(render_process_id, render_frame_id));
- }
- // static
- PageSpecificContentSettings* PageSpecificContentSettings::GetForFrame(
- content::RenderFrameHost* rfh) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- return rfh ? PageSpecificContentSettings::GetForPage(rfh->GetPage())
- : nullptr;
- }
- // static
- PageSpecificContentSettings::Delegate*
- PageSpecificContentSettings::GetDelegateForWebContents(
- content::WebContents* web_contents) {
- auto* handler = WebContentsHandler::FromWebContents(web_contents);
- return handler ? handler->delegate() : nullptr;
- }
- // static
- void PageSpecificContentSettings::StorageAccessed(StorageType storage_type,
- int render_process_id,
- int render_frame_id,
- const GURL& url,
- bool blocked_by_policy) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- content::RenderFrameHost* rfh =
- content::RenderFrameHost::FromID(render_process_id, render_frame_id);
- if (DelayUntilCommitIfNecessary(
- rfh, &PageSpecificContentSettings::StorageAccessed, storage_type,
- render_process_id, render_frame_id, url, blocked_by_policy))
- return;
- PageSpecificContentSettings* settings =
- GetForFrame(render_process_id, render_frame_id);
- if (settings)
- settings->OnStorageAccessed(storage_type, url, blocked_by_policy);
- }
- // static
- void PageSpecificContentSettings::ContentBlocked(int render_process_id,
- int render_frame_id,
- ContentSettingsType type) {
- content::RenderFrameHost* rfh =
- content::RenderFrameHost::FromID(render_process_id, render_frame_id);
- if (DelayUntilCommitIfNecessary(rfh,
- &PageSpecificContentSettings::ContentBlocked,
- render_process_id, render_frame_id, type))
- return;
- PageSpecificContentSettings* settings = GetForFrame(rfh);
- if (settings)
- settings->OnContentBlocked(type);
- }
- // static
- void PageSpecificContentSettings::SharedWorkerAccessed(
- int render_process_id,
- int render_frame_id,
- const GURL& worker_url,
- const std::string& name,
- const blink::StorageKey& storage_key,
- bool blocked_by_policy) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- PageSpecificContentSettings* settings =
- GetForFrame(render_process_id, render_frame_id);
- if (settings)
- settings->OnSharedWorkerAccessed(worker_url, name, storage_key,
- blocked_by_policy);
- }
- // static
- void PageSpecificContentSettings::InterestGroupJoined(
- content::RenderFrameHost* rfh,
- const url::Origin api_origin,
- bool blocked_by_policy) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- PageSpecificContentSettings* settings = GetForFrame(rfh);
- if (settings)
- settings->OnInterestGroupJoined(api_origin, blocked_by_policy);
- }
- // static
- void PageSpecificContentSettings::TopicAccessed(
- content::RenderFrameHost* rfh,
- const url::Origin api_origin,
- bool blocked_by_policy,
- privacy_sandbox::CanonicalTopic topic) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- PageSpecificContentSettings* settings = GetForFrame(rfh);
- if (settings)
- settings->OnTopicAccessed(api_origin, blocked_by_policy, topic);
- }
- // static
- content::WebContentsObserver*
- PageSpecificContentSettings::GetWebContentsObserverForTest(
- content::WebContents* web_contents) {
- return WebContentsHandler::FromWebContents(web_contents);
- }
- bool PageSpecificContentSettings::IsContentBlocked(
- ContentSettingsType content_type) const {
- DCHECK_NE(ContentSettingsType::NOTIFICATIONS, content_type)
- << "Notifications settings handled by "
- << "ContentSettingsNotificationsImageModel";
- DCHECK_NE(ContentSettingsType::AUTOMATIC_DOWNLOADS, content_type)
- << "Automatic downloads handled by DownloadRequestLimiter";
- if (content_type == ContentSettingsType::IMAGES ||
- content_type == ContentSettingsType::JAVASCRIPT ||
- content_type == ContentSettingsType::COOKIES ||
- content_type == ContentSettingsType::POPUPS ||
- content_type == ContentSettingsType::MIXEDSCRIPT ||
- content_type == ContentSettingsType::MEDIASTREAM_MIC ||
- content_type == ContentSettingsType::MEDIASTREAM_CAMERA ||
- content_type == ContentSettingsType::PPAPI_BROKER ||
- content_type == ContentSettingsType::MIDI_SYSEX ||
- content_type == ContentSettingsType::ADS ||
- content_type == ContentSettingsType::SOUND ||
- content_type == ContentSettingsType::CLIPBOARD_READ_WRITE ||
- content_type == ContentSettingsType::SENSORS ||
- content_type == ContentSettingsType::GEOLOCATION) {
- const auto& it = content_settings_status_.find(content_type);
- if (it != content_settings_status_.end())
- return it->second.blocked;
- }
- return false;
- }
- bool PageSpecificContentSettings::IsContentAllowed(
- ContentSettingsType content_type) const {
- DCHECK_NE(ContentSettingsType::AUTOMATIC_DOWNLOADS, content_type)
- << "Automatic downloads handled by DownloadRequestLimiter";
- // This method currently only returns meaningful values for the types listed
- // below.
- if (content_type != ContentSettingsType::COOKIES &&
- content_type != ContentSettingsType::MEDIASTREAM_MIC &&
- content_type != ContentSettingsType::MEDIASTREAM_CAMERA &&
- content_type != ContentSettingsType::PPAPI_BROKER &&
- content_type != ContentSettingsType::MIDI_SYSEX &&
- content_type != ContentSettingsType::CLIPBOARD_READ_WRITE &&
- content_type != ContentSettingsType::SENSORS &&
- content_type != ContentSettingsType::GEOLOCATION) {
- return false;
- }
- const auto& it = content_settings_status_.find(content_type);
- if (it != content_settings_status_.end())
- return it->second.allowed;
- return false;
- }
- void PageSpecificContentSettings::OnContentBlocked(ContentSettingsType type) {
- DCHECK(type != ContentSettingsType::MEDIASTREAM_MIC &&
- type != ContentSettingsType::MEDIASTREAM_CAMERA)
- << "Media stream settings handled by OnMediaStreamPermissionSet";
- if (!content_settings::ContentSettingsRegistry::GetInstance()->Get(type))
- return;
- ContentSettingsStatus& status = content_settings_status_[type];
- if (!status.blocked) {
- status.blocked = true;
- MaybeUpdateLocationBar();
- NotifyDelegate(&Delegate::OnContentBlocked, type);
- MaybeUpdateParent(&PageSpecificContentSettings::OnContentBlocked, type);
- }
- }
- void PageSpecificContentSettings::OnContentAllowed(ContentSettingsType type) {
- DCHECK(type != ContentSettingsType::MEDIASTREAM_MIC &&
- type != ContentSettingsType::MEDIASTREAM_CAMERA)
- << "Media stream settings handled by OnMediaStreamPermissionSet";
- bool access_changed = false;
- ContentSettingsStatus& status = content_settings_status_[type];
- // Whether to reset status for the |blocked| setting to avoid ending up
- // with both |allowed| and |blocked| set, which can mean multiple things
- // (allowed setting that got disabled, disabled setting that got enabled).
- bool must_reset_blocked_status = false;
- // For sensors, the status with both allowed/blocked flags set means that
- // access was previously allowed but the last decision was to block.
- // Reset the blocked flag so that the UI will properly indicate that the
- // last decision here instead was to allow sensor access.
- if (type == ContentSettingsType::SENSORS)
- must_reset_blocked_status = true;
- #if BUILDFLAG(IS_ANDROID)
- // content_settings_status_[type].allowed is always set to true in
- // OnContentBlocked, so we have to use
- // content_settings_status_[type].blocked to detect whether the protected
- // media setting has changed.
- if (type == ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER)
- must_reset_blocked_status = true;
- #endif
- if (must_reset_blocked_status && status.blocked) {
- status.blocked = false;
- access_changed = true;
- }
- if (!status.allowed) {
- status.allowed = true;
- access_changed = true;
- NotifyDelegate(&Delegate::OnContentAllowed, type);
- }
- if (access_changed) {
- MaybeUpdateLocationBar();
- MaybeUpdateParent(&PageSpecificContentSettings::OnContentAllowed, type);
- }
- }
- namespace {
- void AddToContainer(browsing_data::LocalSharedObjectsContainer& container,
- StorageType storage_type,
- const GURL& url) {
- url::Origin origin = url::Origin::Create(url);
- switch (storage_type) {
- case StorageType::DATABASE:
- container.databases()->Add(origin);
- return;
- case StorageType::LOCAL_STORAGE:
- // TODO(https://crbug.com/1199077): Pass the real StorageKey into this
- // function directly.
- container.local_storages()->Add(blink::StorageKey(origin));
- return;
- case StorageType::SESSION_STORAGE:
- // TODO(https://crbug.com/1199077): Pass the real StorageKey into this
- // function directly.
- container.session_storages()->Add(blink::StorageKey(origin));
- return;
- case StorageType::INDEXED_DB:
- // TODO(https://crbug.com/1199077): Pass the real StorageKey into this
- // function directly.
- container.indexed_dbs()->Add(blink::StorageKey(origin));
- return;
- case StorageType::CACHE:
- container.cache_storages()->Add(origin);
- return;
- case StorageType::FILE_SYSTEM:
- container.file_systems()->Add(origin);
- return;
- case StorageType::WEB_LOCKS:
- NOTREACHED();
- return;
- }
- }
- } // namespace
- void PageSpecificContentSettings::OnStorageAccessed(
- StorageType storage_type,
- const GURL& url,
- bool blocked_by_policy,
- content::Page* originating_page) {
- originating_page = originating_page ? originating_page : &page();
- if (blocked_by_policy) {
- AddToContainer(blocked_local_shared_objects_, storage_type, url);
- OnContentBlocked(ContentSettingsType::COOKIES);
- } else {
- AddToContainer(allowed_local_shared_objects_, storage_type, url);
- NotifyDelegate(&Delegate::OnStorageAccessAllowed, storage_type,
- url::Origin::Create(url), std::ref(*originating_page));
- OnContentAllowed(ContentSettingsType::COOKIES);
- }
- MaybeUpdateParent(&PageSpecificContentSettings::OnStorageAccessed,
- storage_type, url, blocked_by_policy, originating_page);
- MaybeNotifySiteDataObservers();
- }
- void PageSpecificContentSettings::OnCookiesAccessed(
- const content::CookieAccessDetails& details,
- content::Page* originating_page) {
- originating_page = originating_page ? originating_page : &page();
- if (details.cookie_list.empty())
- return;
- if (details.blocked_by_policy) {
- blocked_local_shared_objects_.cookies()->AddCookies(details);
- OnContentBlocked(ContentSettingsType::COOKIES);
- } else {
- allowed_local_shared_objects_.cookies()->AddCookies(details);
- OnContentAllowed(ContentSettingsType::COOKIES);
- NotifyDelegate(&Delegate::OnCookieAccessAllowed, details.cookie_list,
- std::ref(*originating_page));
- }
- MaybeUpdateParent(&PageSpecificContentSettings::OnCookiesAccessed, details,
- originating_page);
- MaybeNotifySiteDataObservers();
- }
- void PageSpecificContentSettings::OnServiceWorkerAccessed(
- const GURL& scope,
- content::AllowServiceWorkerResult allowed,
- content::Page* originating_page) {
- DCHECK(scope.is_valid());
- originating_page = originating_page ? originating_page : &page();
- if (allowed) {
- allowed_local_shared_objects_.service_workers()->Add(
- url::Origin::Create(scope));
- NotifyDelegate(&Delegate::OnServiceWorkerAccessAllowed,
- url::Origin::Create(scope), std::ref(*originating_page));
- } else {
- blocked_local_shared_objects_.service_workers()->Add(
- url::Origin::Create(scope));
- }
- if (allowed.javascript_blocked_by_policy()) {
- OnContentBlocked(ContentSettingsType::JAVASCRIPT);
- } else {
- OnContentAllowed(ContentSettingsType::JAVASCRIPT);
- }
- if (allowed.cookies_blocked_by_policy()) {
- OnContentBlocked(ContentSettingsType::COOKIES);
- } else {
- OnContentAllowed(ContentSettingsType::COOKIES);
- }
- MaybeUpdateParent(&PageSpecificContentSettings::OnServiceWorkerAccessed,
- scope, allowed, originating_page);
- }
- void PageSpecificContentSettings::OnSharedWorkerAccessed(
- const GURL& worker_url,
- const std::string& name,
- const blink::StorageKey& storage_key,
- bool blocked_by_policy) {
- DCHECK(worker_url.is_valid());
- if (blocked_by_policy) {
- blocked_local_shared_objects_.shared_workers()->AddSharedWorker(
- worker_url, name, storage_key);
- OnContentBlocked(ContentSettingsType::COOKIES);
- } else {
- allowed_local_shared_objects_.shared_workers()->AddSharedWorker(
- worker_url, name, storage_key);
- OnContentAllowed(ContentSettingsType::COOKIES);
- }
- MaybeUpdateParent(&PageSpecificContentSettings::OnSharedWorkerAccessed,
- worker_url, name, storage_key, blocked_by_policy);
- }
- void PageSpecificContentSettings::OnInterestGroupJoined(
- const url::Origin api_origin,
- bool blocked_by_policy) {
- if (blocked_by_policy) {
- blocked_interest_group_api_.push_back(api_origin);
- OnContentBlocked(ContentSettingsType::COOKIES);
- } else {
- allowed_interest_group_api_.push_back(api_origin);
- OnContentAllowed(ContentSettingsType::COOKIES);
- }
- MaybeUpdateParent(&PageSpecificContentSettings::OnInterestGroupJoined,
- api_origin, blocked_by_policy);
- MaybeNotifySiteDataObservers();
- }
- void PageSpecificContentSettings::OnTopicAccessed(
- const url::Origin api_origin,
- bool blocked_by_policy,
- privacy_sandbox::CanonicalTopic topic) {
- // TODO(crbug.com/1286276): Add URL and Topic to local_shared_objects?
- accessed_topics_.insert(topic);
- MaybeUpdateParent(&PageSpecificContentSettings::OnTopicAccessed, api_origin,
- blocked_by_policy, topic);
- }
- #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
- void PageSpecificContentSettings::OnProtectedMediaIdentifierPermissionSet(
- const GURL& requesting_origin,
- bool allowed) {
- if (allowed) {
- OnContentAllowed(ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER);
- } else {
- OnContentBlocked(ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER);
- }
- }
- #endif
- PageSpecificContentSettings::MicrophoneCameraState
- PageSpecificContentSettings::GetMicrophoneCameraState() const {
- return microphone_camera_state_ | delegate_->GetMicrophoneCameraState();
- }
- bool PageSpecificContentSettings::IsMicrophoneCameraStateChanged() const {
- if ((microphone_camera_state_ & MICROPHONE_ACCESSED) &&
- ((microphone_camera_state_ & MICROPHONE_BLOCKED)
- ? !IsContentBlocked(ContentSettingsType::MEDIASTREAM_MIC)
- : !IsContentAllowed(ContentSettingsType::MEDIASTREAM_MIC)))
- return true;
- if ((microphone_camera_state_ & CAMERA_ACCESSED) &&
- ((microphone_camera_state_ & CAMERA_BLOCKED)
- ? !IsContentBlocked(ContentSettingsType::MEDIASTREAM_CAMERA)
- : !IsContentAllowed(ContentSettingsType::MEDIASTREAM_CAMERA)))
- return true;
- return delegate_->IsMicrophoneCameraStateChanged(
- microphone_camera_state_, media_stream_selected_audio_device(),
- media_stream_selected_video_device());
- }
- void PageSpecificContentSettings::OnMediaStreamPermissionSet(
- const GURL& request_origin,
- MicrophoneCameraState new_microphone_camera_state,
- const std::string& media_stream_selected_audio_device,
- const std::string& media_stream_selected_video_device,
- const std::string& media_stream_requested_audio_device,
- const std::string& media_stream_requested_video_device) {
- DCHECK(!IsEmbeddedPage());
- media_stream_access_origin_ = request_origin;
- if (new_microphone_camera_state & MICROPHONE_ACCESSED) {
- media_stream_requested_audio_device_ = media_stream_requested_audio_device;
- media_stream_selected_audio_device_ = media_stream_selected_audio_device;
- bool mic_blocked = (new_microphone_camera_state & MICROPHONE_BLOCKED) != 0;
- ContentSettingsStatus& status =
- content_settings_status_[ContentSettingsType::MEDIASTREAM_MIC];
- if (!status.allowed && !mic_blocked) {
- NotifyDelegate(&Delegate::OnContentAllowed,
- ContentSettingsType::MEDIASTREAM_MIC);
- }
- status.allowed = !mic_blocked;
- status.blocked = mic_blocked;
- }
- if (new_microphone_camera_state & CAMERA_ACCESSED) {
- media_stream_requested_video_device_ = media_stream_requested_video_device;
- media_stream_selected_video_device_ = media_stream_selected_video_device;
- bool cam_blocked = (new_microphone_camera_state & CAMERA_BLOCKED) != 0;
- ContentSettingsStatus& status =
- content_settings_status_[ContentSettingsType::MEDIASTREAM_CAMERA];
- if (!status.allowed && !cam_blocked) {
- NotifyDelegate(&Delegate::OnContentAllowed,
- ContentSettingsType::MEDIASTREAM_CAMERA);
- }
- status.allowed = !cam_blocked;
- status.blocked = cam_blocked;
- }
- if (microphone_camera_state_ != new_microphone_camera_state) {
- microphone_camera_state_ = new_microphone_camera_state;
- MaybeUpdateLocationBar();
- }
- }
- void PageSpecificContentSettings::ClearPopupsBlocked() {
- ContentSettingsStatus& status =
- content_settings_status_[ContentSettingsType::POPUPS];
- status.blocked = false;
- MaybeUpdateLocationBar();
- }
- void PageSpecificContentSettings::OnAudioBlocked() {
- OnContentBlocked(ContentSettingsType::SOUND);
- }
- void PageSpecificContentSettings::SetPepperBrokerAllowed(bool allowed) {
- if (allowed) {
- OnContentAllowed(ContentSettingsType::PPAPI_BROKER);
- } else {
- OnContentBlocked(ContentSettingsType::PPAPI_BROKER);
- }
- }
- void PageSpecificContentSettings::OnContentSettingChanged(
- const ContentSettingsPattern& primary_pattern,
- const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type) {
- if (IsEmbeddedPage())
- return;
- const GURL current_url = page().GetMainDocument().GetLastCommittedURL();
- if (!primary_pattern.Matches(current_url)) {
- return;
- }
- ContentSettingsStatus& status = content_settings_status_[content_type];
- switch (content_type) {
- case ContentSettingsType::MEDIASTREAM_MIC:
- case ContentSettingsType::MEDIASTREAM_CAMERA: {
- const GURL media_origin = media_stream_access_origin();
- ContentSetting setting =
- map_->GetContentSetting(media_origin, media_origin, content_type);
- if (content_type == ContentSettingsType::MEDIASTREAM_MIC &&
- setting == CONTENT_SETTING_ALLOW) {
- mic_was_just_granted_on_site_level_ = true;
- }
- if (content_type == ContentSettingsType::MEDIASTREAM_CAMERA &&
- setting == CONTENT_SETTING_ALLOW) {
- camera_was_just_granted_on_site_level_ = true;
- }
- status.allowed = setting == CONTENT_SETTING_ALLOW;
- status.blocked = setting == CONTENT_SETTING_BLOCK;
- break;
- }
- case ContentSettingsType::GEOLOCATION: {
- ContentSetting geolocation_setting =
- map_->GetContentSetting(current_url, current_url, content_type);
- if (geolocation_setting == CONTENT_SETTING_ALLOW)
- geolocation_was_just_granted_on_site_level_ = true;
- [[fallthrough]];
- }
- case ContentSettingsType::IMAGES:
- case ContentSettingsType::JAVASCRIPT:
- case ContentSettingsType::COOKIES:
- case ContentSettingsType::POPUPS:
- case ContentSettingsType::MIXEDSCRIPT:
- case ContentSettingsType::PPAPI_BROKER:
- case ContentSettingsType::MIDI_SYSEX:
- case ContentSettingsType::ADS:
- case ContentSettingsType::SOUND:
- case ContentSettingsType::CLIPBOARD_READ_WRITE:
- case ContentSettingsType::SENSORS: {
- ContentSetting setting =
- map_->GetContentSetting(current_url, current_url, content_type);
- // If an indicator is shown and the content settings has changed, swap the
- // indicator for the one with the opposite meaning (allowed <=> blocked).
- if (setting == CONTENT_SETTING_BLOCK && status.allowed) {
- status.blocked = false;
- status.allowed = false;
- OnContentBlocked(content_type);
- } else if (setting == CONTENT_SETTING_ALLOW && status.blocked) {
- status.blocked = false;
- status.allowed = false;
- OnContentAllowed(content_type);
- }
- break;
- }
- default:
- break;
- }
- }
- void PageSpecificContentSettings::ClearContentSettingsChangedViaPageInfo() {
- content_settings_changed_via_page_info_.clear();
- }
- void PageSpecificContentSettings::BlockAllContentForTesting() {
- content_settings::ContentSettingsRegistry* registry =
- content_settings::ContentSettingsRegistry::GetInstance();
- for (const content_settings::ContentSettingsInfo* info : *registry) {
- ContentSettingsType type = info->website_settings_info()->type();
- if (type != ContentSettingsType::MEDIASTREAM_MIC &&
- type != ContentSettingsType::MEDIASTREAM_CAMERA) {
- OnContentBlocked(type);
- }
- }
- // Media must be blocked separately, as the generic
- // PageSpecificContentSettings::OnContentBlocked does not apply to them.
- MicrophoneCameraStateFlags media_blocked =
- static_cast<MicrophoneCameraStateFlags>(
- PageSpecificContentSettings::MICROPHONE_ACCESSED |
- PageSpecificContentSettings::MICROPHONE_BLOCKED |
- PageSpecificContentSettings::CAMERA_ACCESSED |
- PageSpecificContentSettings::CAMERA_BLOCKED);
- OnMediaStreamPermissionSet(page().GetMainDocument().GetLastCommittedURL(),
- media_blocked, std::string(), std::string(),
- std::string(), std::string());
- }
- void PageSpecificContentSettings::ContentSettingChangedViaPageInfo(
- ContentSettingsType type) {
- content_settings_changed_via_page_info_.insert(type);
- }
- bool PageSpecificContentSettings::HasContentSettingChangedViaPageInfo(
- ContentSettingsType type) const {
- return content_settings_changed_via_page_info_.find(type) !=
- content_settings_changed_via_page_info_.end();
- }
- bool PageSpecificContentSettings::HasAccessedTopics() const {
- return !GetAccessedTopics().empty();
- }
- std::vector<privacy_sandbox::CanonicalTopic>
- PageSpecificContentSettings::GetAccessedTopics() const {
- if (accessed_topics_.empty() &&
- privacy_sandbox::kPrivacySandboxSettings3ShowSampleDataForTesting.Get() &&
- page().GetMainDocument().GetLastCommittedURL().host() == "example.com") {
- // TODO(crbug.com/1286276): Remove sample topic when API is ready.
- return {privacy_sandbox::CanonicalTopic(
- browsing_topics::Topic(1),
- privacy_sandbox::CanonicalTopic::AVAILABLE_TAXONOMY)};
- }
- return {accessed_topics_.begin(), accessed_topics_.end()};
- }
- bool PageSpecificContentSettings::HasJoinedUserToInterestGroup() const {
- return !allowed_interest_group_api_.empty();
- }
- bool PageSpecificContentSettings::IsPagePrerendering() const {
- // We consider the Page to be prerendering iff
- // |updates_queued_during_prerender_| is non null. Note, the page already may
- // already have exited prerendering as |updates_queued_during_prerender_| is
- // flushed in DidFinishNavigation for the prerender activation but other
- // observers may come before this and call into here. In that case we'll still
- // queue their updates.
- return !!updates_queued_during_prerender_;
- }
- bool PageSpecificContentSettings::IsEmbeddedPage() const {
- return page().GetMainDocument().GetParentOrOuterDocument();
- }
- void PageSpecificContentSettings::OnPrerenderingPageActivation() {
- DCHECK(updates_queued_during_prerender_);
- for (auto& delegate_update :
- updates_queued_during_prerender_->delegate_updates) {
- std::move(delegate_update).Run();
- }
- if (updates_queued_during_prerender_->site_data_accessed) {
- WebContentsHandler::FromWebContents(GetWebContents())
- ->NotifySiteDataObservers();
- }
- updates_queued_during_prerender_.reset();
- }
- void PageSpecificContentSettings::MaybeNotifySiteDataObservers() {
- if (IsEmbeddedPage())
- return;
- if (IsPagePrerendering()) {
- updates_queued_during_prerender_->site_data_accessed = true;
- return;
- }
- WebContentsHandler::FromWebContents(GetWebContents())
- ->NotifySiteDataObservers();
- }
- void PageSpecificContentSettings::MaybeUpdateLocationBar() {
- if (IsEmbeddedPage())
- return;
- if (IsPagePrerendering())
- return;
- delegate_->UpdateLocationBar();
- }
- content::WebContents* PageSpecificContentSettings::GetWebContents() const {
- return content::WebContents::FromRenderFrameHost(&page().GetMainDocument());
- }
- PAGE_USER_DATA_KEY_IMPL(PageSpecificContentSettings);
- } // namespace content_settings
|