summaryrefslogtreecommitdiff
path: root/chromium/components/content_settings/browser
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-12 14:27:29 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:35:20 +0000
commitc30a6232df03e1efbd9f3b226777b07e087a1122 (patch)
treee992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/components/content_settings/browser
parent7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff)
downloadqtwebengine-chromium-85-based.tar.gz
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/components/content_settings/browser')
-rw-r--r--chromium/components/content_settings/browser/BUILD.gn13
-rw-r--r--chromium/components/content_settings/browser/content_settings_usages_state.cc78
-rw-r--r--chromium/components/content_settings/browser/content_settings_usages_state.h23
-rw-r--r--chromium/components/content_settings/browser/tab_specific_content_settings.cc561
-rw-r--r--chromium/components/content_settings/browser/tab_specific_content_settings.h255
-rw-r--r--chromium/components/content_settings/browser/tab_specific_content_settings_unittest.cc259
-rw-r--r--chromium/components/content_settings/browser/test_tab_specific_content_settings_delegate.cc63
-rw-r--r--chromium/components/content_settings/browser/test_tab_specific_content_settings_delegate.h47
-rw-r--r--chromium/components/content_settings/browser/ui/BUILD.gn21
-rw-r--r--chromium/components/content_settings/browser/ui/cookie_controls_controller.cc161
-rw-r--r--chromium/components/content_settings/browser/ui/cookie_controls_controller.h106
-rw-r--r--chromium/components/content_settings/browser/ui/cookie_controls_view.h25
12 files changed, 1097 insertions, 515 deletions
diff --git a/chromium/components/content_settings/browser/BUILD.gn b/chromium/components/content_settings/browser/BUILD.gn
index 8377ccc4031..a4168a97483 100644
--- a/chromium/components/content_settings/browser/BUILD.gn
+++ b/chromium/components/content_settings/browser/BUILD.gn
@@ -26,11 +26,24 @@ source_set("browser") {
]
}
+source_set("test_support") {
+ testonly = true
+ sources = [
+ "test_tab_specific_content_settings_delegate.cc",
+ "test_tab_specific_content_settings_delegate.h",
+ ]
+ deps = [
+ ":browser",
+ "//content/public/browser",
+ ]
+}
+
source_set("unit_tests") {
testonly = true
sources = [ "tab_specific_content_settings_unittest.cc" ]
deps = [
":browser",
+ ":test_support",
"//base",
"//components/content_settings/core/browser",
"//components/security_state/core",
diff --git a/chromium/components/content_settings/browser/content_settings_usages_state.cc b/chromium/components/content_settings/browser/content_settings_usages_state.cc
index b65036db080..63e75f1af13 100644
--- a/chromium/components/content_settings/browser/content_settings_usages_state.cc
+++ b/chromium/components/content_settings/browser/content_settings_usages_state.cc
@@ -11,9 +11,10 @@
#include "components/url_formatter/url_formatter.h"
ContentSettingsUsagesState::ContentSettingsUsagesState(
- HostContentSettingsMap* host_content_settings_map,
- ContentSettingsType type)
- : host_content_settings_map_(host_content_settings_map), type_(type) {}
+ content_settings::TabSpecificContentSettings::Delegate* delegate_,
+ ContentSettingsType type,
+ const GURL& embedder_url)
+ : delegate_(delegate_), type_(type), embedder_url_(embedder_url) {}
ContentSettingsUsagesState::~ContentSettingsUsagesState() {}
@@ -23,64 +24,67 @@ void ContentSettingsUsagesState::OnPermissionSet(const GURL& requesting_origin,
allowed ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
}
-void ContentSettingsUsagesState::DidNavigate(const GURL& url,
- const GURL& previous_url) {
- embedder_url_ = url;
- if (state_map_.empty())
- return;
- if (previous_url.GetOrigin() != url.GetOrigin()) {
- state_map_.clear();
- return;
- }
- // We're in the same origin, check if there's any icon to be displayed.
- unsigned int tab_state_flags = 0;
- GetDetailedInfo(nullptr, &tab_state_flags);
- if (!(tab_state_flags & TABSTATE_HAS_ANY_ICON))
- state_map_.clear();
-}
-
-void ContentSettingsUsagesState::ClearStateMap() {
- state_map_.clear();
-}
-
void ContentSettingsUsagesState::GetDetailedInfo(
FormattedHostsPerState* formatted_hosts_per_state,
unsigned int* tab_state_flags) const {
DCHECK(tab_state_flags);
DCHECK(embedder_url_.is_valid());
+ // This logic is used only for |ContentSettingsType::GEOLOCATION| and
+ // |ContentSettingsType::MIDI_SYSEX|.
+ DCHECK(type_ == ContentSettingsType::GEOLOCATION ||
+ type_ == ContentSettingsType::MIDI_SYSEX);
ContentSetting default_setting =
- host_content_settings_map_->GetDefaultContentSetting(type_, nullptr);
+ delegate_->GetSettingsMap()->GetDefaultContentSetting(type_, nullptr);
std::set<std::string> formatted_hosts;
std::set<std::string> repeated_formatted_hosts;
- // Build a set of repeated formatted hosts
- for (auto i(state_map_.begin()); i != state_map_.end(); ++i) {
- std::string formatted_host = GURLToFormattedHost(i->first);
+ // Build a set of repeated formatted hosts.
+ for (const auto& i : state_map_) {
+ std::string formatted_host = GURLToFormattedHost(i.first);
if (!formatted_hosts.insert(formatted_host).second) {
repeated_formatted_hosts.insert(formatted_host);
}
}
- for (auto i(state_map_.begin()); i != state_map_.end(); ++i) {
- if (i->second == CONTENT_SETTING_ALLOW)
+ for (const auto& i : state_map_) {
+ const GURL& origin = i.first;
+ // The setting that was applied when the corresponding capability was last
+ // requested.
+ const ContentSetting& effective_setting = i.second;
+
+ if (effective_setting == CONTENT_SETTING_ALLOW)
*tab_state_flags |= TABSTATE_HAS_ANY_ALLOWED;
if (formatted_hosts_per_state) {
- std::string formatted_host = GURLToFormattedHost(i->first);
+ std::string formatted_host = GURLToFormattedHost(origin);
std::string final_formatted_host =
repeated_formatted_hosts.find(formatted_host) ==
repeated_formatted_hosts.end()
? formatted_host
- : i->first.spec();
- (*formatted_hosts_per_state)[i->second].insert(final_formatted_host);
+ : origin.spec();
+ (*formatted_hosts_per_state)[effective_setting].insert(
+ final_formatted_host);
}
- const ContentSetting saved_setting =
- host_content_settings_map_->GetContentSetting(i->first, embedder_url_,
- type_, std::string());
+ ContentSetting saved_setting =
+ delegate_->GetSettingsMap()->GetContentSetting(origin, embedder_url_,
+ type_, std::string());
+ ContentSetting embargo_setting =
+ delegate_->GetEmbargoSetting(origin, type_);
+
+ // |embargo_setting| can be only CONTENT_SETTING_ASK or
+ // CONTENT_SETTING_BLOCK. If |saved_setting| is CONTENT_SETTING_ASK then
+ // the |embargo_setting| takes effect.
+ if (saved_setting == CONTENT_SETTING_ASK)
+ saved_setting = embargo_setting;
+
+ // |effective_setting| can be only CONTENT_SETTING_ALLOW or
+ // CONTENT_SETTING_BLOCK.
+ if (saved_setting != effective_setting)
+ *tab_state_flags |= TABSTATE_HAS_CHANGED;
+
if (saved_setting != default_setting)
*tab_state_flags |= TABSTATE_HAS_EXCEPTION;
- if (saved_setting != i->second)
- *tab_state_flags |= TABSTATE_HAS_CHANGED;
+
if (saved_setting != CONTENT_SETTING_ASK)
*tab_state_flags |= TABSTATE_HAS_ANY_ICON;
}
diff --git a/chromium/components/content_settings/browser/content_settings_usages_state.h b/chromium/components/content_settings/browser/content_settings_usages_state.h
index a34ed720de4..2e68ca9875c 100644
--- a/chromium/components/content_settings/browser/content_settings_usages_state.h
+++ b/chromium/components/content_settings/browser/content_settings_usages_state.h
@@ -9,19 +9,23 @@
#include <set>
#include "base/macros.h"
+#include "components/content_settings/browser/tab_specific_content_settings.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "url/gurl.h"
-class HostContentSettingsMap;
-
-// This class manages a content setting state per tab for a given
+// This class manages a content setting state per page for a given
// |ContentSettingsType|, and provides information and presentation data about
// the content setting usage.
+// TODO(crbug.com/1086363): Move this class into the `content_settings`
+// namespace.
class ContentSettingsUsagesState {
public:
- ContentSettingsUsagesState(HostContentSettingsMap* host_content_settings_map,
- ContentSettingsType type);
+ ContentSettingsUsagesState(
+ content_settings::TabSpecificContentSettings::Delegate* delegate_,
+ ContentSettingsType type,
+ const GURL& embedder_url);
+
~ContentSettingsUsagesState();
typedef std::map<GURL, ContentSetting> StateMap;
@@ -30,12 +34,6 @@ class ContentSettingsUsagesState {
// Sets the state for |requesting_origin|.
void OnPermissionSet(const GURL& requesting_origin, bool allowed);
- // Delegated by WebContents to indicate a navigation has happened and we
- // may need to clear our settings.
- void DidNavigate(const GURL& url, const GURL& previous_url);
-
- void ClearStateMap();
-
enum TabState {
TABSTATE_NONE = 0,
// There's at least one entry with non-default setting.
@@ -57,8 +55,7 @@ class ContentSettingsUsagesState {
private:
std::string GURLToFormattedHost(const GURL& url) const;
-
- HostContentSettingsMap* const host_content_settings_map_;
+ content_settings::TabSpecificContentSettings::Delegate* delegate_;
ContentSettingsType type_;
StateMap state_map_;
GURL embedder_url_;
diff --git a/chromium/components/content_settings/browser/tab_specific_content_settings.cc b/chromium/components/content_settings/browser/tab_specific_content_settings.cc
index b783a2c6fde..95ab944de51 100644
--- a/chromium/components/content_settings/browser/tab_specific_content_settings.cc
+++ b/chromium/components/content_settings/browser/tab_specific_content_settings.cc
@@ -9,6 +9,8 @@
#include "base/command_line.h"
#include "base/lazy_instance.h"
+#include "base/memory/ptr_util.h"
+#include "base/optional.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -22,17 +24,14 @@
#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/browser/content_settings_usages_state.h"
#include "components/content_settings/common/content_settings_agent.mojom.h"
#include "components/content_settings/core/browser/content_settings_details.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/prefs/pref_service.h"
-#include "components/security_state/core/security_state_pref_names.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/navigation_details.h"
-#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
@@ -44,9 +43,6 @@
#include "url/origin.h"
using content::BrowserThread;
-using content::NavigationController;
-using content::NavigationEntry;
-using content::WebContents;
namespace content_settings {
namespace {
@@ -62,60 +58,325 @@ bool ShouldSendUpdatedContentSettingsRulesToRenderer(
return RendererContentSettingRules::IsRendererContentSetting((content_type));
}
+void MaybeSendRendererContentSettingsRules(
+ content::RenderFrameHost* rfh,
+ const HostContentSettingsMap* map,
+ TabSpecificContentSettings::Delegate* delegate) {
+ DCHECK_EQ(rfh, rfh->GetMainFrame());
+ // Only send a message to the renderer if it is initialised and not dead.
+ // Otherwise, the IPC messages will be queued in the browser process,
+ // potentially causing large memory leaks. See https://crbug.com/875937.
+ content::RenderProcessHost* process = rfh->GetProcess();
+ if (!process->IsInitializedAndNotDead())
+ return;
+
+ RendererContentSettingRules rules;
+ GetRendererContentSettingRules(map, &rules);
+ delegate->SetContentSettingRules(process, rules);
+}
+
+bool WillNavigationCreateNewTabSpecificContentSettingsOnCommit(
+ content::NavigationHandle* navigation_handle) {
+ return navigation_handle->IsInMainFrame() &&
+ !navigation_handle->IsSameDocument() &&
+ !navigation_handle->IsServedFromBackForwardCache();
+}
+
} // namespace
TabSpecificContentSettings::SiteDataObserver::SiteDataObserver(
- TabSpecificContentSettings* tab_specific_content_settings)
- : tab_specific_content_settings_(tab_specific_content_settings) {
- tab_specific_content_settings_->AddSiteDataObserver(this);
+ 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 =
+ TabSpecificContentSettings::WebContentsHandler::FromWebContents(
+ web_contents_);
+ if (handler)
+ handler->AddSiteDataObserver(this);
}
TabSpecificContentSettings::SiteDataObserver::~SiteDataObserver() {
- if (tab_specific_content_settings_)
- tab_specific_content_settings_->RemoveSiteDataObserver(this);
+ if (!web_contents_)
+ return;
+ auto* handler =
+ TabSpecificContentSettings::WebContentsHandler::FromWebContents(
+ web_contents_);
+ if (handler)
+ handler->RemoveSiteDataObserver(this);
}
-void TabSpecificContentSettings::SiteDataObserver::ContentSettingsDestroyed() {
- tab_specific_content_settings_ = nullptr;
+void TabSpecificContentSettings::SiteDataObserver::WebContentsDestroyed() {
+ web_contents_ = nullptr;
}
-TabSpecificContentSettings::TabSpecificContentSettings(
- WebContents* tab,
+// static
+void TabSpecificContentSettings::WebContentsHandler::CreateForWebContents(
+ content::WebContents* web_contents,
+ std::unique_ptr<Delegate> delegate) {
+ DCHECK(web_contents);
+ if (TabSpecificContentSettings::WebContentsHandler::FromWebContents(
+ web_contents)) {
+ return;
+ }
+
+ web_contents->SetUserData(
+ TabSpecificContentSettings::WebContentsHandler::UserDataKey(),
+ base::WrapUnique(new TabSpecificContentSettings::WebContentsHandler(
+ web_contents, std::move(delegate))));
+}
+
+TabSpecificContentSettings::WebContentsHandler::WebContentsHandler(
+ content::WebContents* web_contents,
std::unique_ptr<Delegate> delegate)
- : content::WebContentsObserver(tab),
+ : WebContentsObserver(web_contents),
delegate_(std::move(delegate)),
+ map_(delegate_->GetSettingsMap()) {
+ DCHECK(!TabSpecificContentSettings::GetForCurrentDocument(
+ web_contents->GetMainFrame()));
+ content::SetRenderDocumentHostUserData(
+ web_contents->GetMainFrame(), TabSpecificContentSettings::UserDataKey(),
+ base::WrapUnique(new TabSpecificContentSettings(*this, delegate_.get())));
+}
+
+TabSpecificContentSettings::WebContentsHandler::~WebContentsHandler() {
+ for (SiteDataObserver& observer : observer_list_)
+ observer.WebContentsDestroyed();
+}
+
+void TabSpecificContentSettings::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 TabSpecificContentSettings::WebContentsHandler::OnCookiesAccessed(
+ content::NavigationHandle* navigation,
+ const content::CookieAccessDetails& details) {
+ auto it = inflight_navigation_settings_.find(navigation);
+ if (it != inflight_navigation_settings_.end()) {
+ it->second.cookie_accesses.push_back(details);
+ return;
+ }
+ // TODO(carlscab): We should be able to
+ // DHECK(!WillNavigationCreateNewTabSpecificContentSettingsOnCommit) here, but
+ // there is still code that starts a navigation before attaching the tab
+ // helpers in DevConsole related code. So we miss the DidStartNavigation event
+ // for those navigations. (https://crbug.com/1095576)
+ OnCookiesAccessed(web_contents()->GetMainFrame(), details);
+}
+
+void TabSpecificContentSettings::WebContentsHandler::OnCookiesAccessed(
+ content::RenderFrameHost* rfh,
+ const content::CookieAccessDetails& details) {
+ auto* tscs =
+ TabSpecificContentSettings::GetForCurrentDocument(rfh->GetMainFrame());
+ if (tscs)
+ tscs->OnCookiesAccessed(details);
+}
+
+void TabSpecificContentSettings::WebContentsHandler::OnServiceWorkerAccessed(
+ content::NavigationHandle* navigation,
+ const GURL& scope,
+ content::AllowServiceWorkerResult allowed) {
+ DCHECK(scope.is_valid());
+
+ auto it = inflight_navigation_settings_.find(navigation);
+ if (it != inflight_navigation_settings_.end()) {
+ it->second.service_worker_accesses.emplace_back(
+ std::make_pair(scope, allowed));
+ return;
+ }
+ // TODO(carlscab): We should be able to
+ // DHECK(!WillNavigationCreateNewTabSpecificContentSettingsOnCommit) here, but
+ // there is still code that starts a navigation before attaching the tab
+ // helpers in DevConsole related code. So we miss the DidStartNavigation event
+ // for those navigations.
+ OnServiceWorkerAccessed(web_contents()->GetMainFrame(), scope, allowed);
+}
+
+void TabSpecificContentSettings::WebContentsHandler::OnServiceWorkerAccessed(
+ content::RenderFrameHost* frame,
+ const GURL& scope,
+ content::AllowServiceWorkerResult allowed) {
+ auto* tscs =
+ TabSpecificContentSettings::GetForCurrentDocument(frame->GetMainFrame());
+ if (tscs)
+ tscs->OnServiceWorkerAccessed(scope, allowed);
+}
+
+void TabSpecificContentSettings::WebContentsHandler::
+ RenderFrameForInterstitialPageCreated(
+ content::RenderFrameHost* render_frame_host) {
+ // We want to tell the renderer-side code to ignore content settings for this
+ // page.
+ mojo::AssociatedRemote<content_settings::mojom::ContentSettingsAgent>
+ content_settings_agent;
+ render_frame_host->GetRemoteAssociatedInterfaces()->GetInterface(
+ &content_settings_agent);
+ content_settings_agent->SetAsInterstitial();
+}
+
+void TabSpecificContentSettings::WebContentsHandler::DidStartNavigation(
+ content::NavigationHandle* navigation_handle) {
+ if (!WillNavigationCreateNewTabSpecificContentSettingsOnCommit(
+ navigation_handle)) {
+ return;
+ }
+
+ inflight_navigation_settings_.insert(
+ std::make_pair(navigation_handle, InflightNavigationContentSettings()));
+}
+
+void TabSpecificContentSettings::WebContentsHandler::ReadyToCommitNavigation(
+ content::NavigationHandle* navigation_handle) {
+ if (!WillNavigationCreateNewTabSpecificContentSettingsOnCommit(
+ navigation_handle)) {
+ return;
+ }
+
+ // There may be content settings that were updated for the navigated URL.
+ // These would not have been sent before if we're navigating cross-origin.
+ // Ensure up to date rules are sent before navigation commits.
+ MaybeSendRendererContentSettingsRules(
+ navigation_handle->GetWebContents()->GetMainFrame(), map_,
+ delegate_.get());
+}
+
+void TabSpecificContentSettings::WebContentsHandler::DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) {
+ if (!WillNavigationCreateNewTabSpecificContentSettingsOnCommit(
+ navigation_handle)) {
+ return;
+ }
+
+ if (!navigation_handle->HasCommitted()) {
+ inflight_navigation_settings_.erase(navigation_handle);
+ return;
+ }
+
+ auto tscs =
+ base::WrapUnique(new TabSpecificContentSettings(*this, delegate_.get()));
+
+ // TODO(carlscab): This sort of internal. Maybe add a
+ // RenderDocumentHostUserData::Create(RenderFrameHost* rfh, Params...)
+ content::SetRenderDocumentHostUserData(
+ navigation_handle->GetRenderFrameHost(),
+ TabSpecificContentSettings::UserDataKey(), std::move(tscs));
+
+ auto it = inflight_navigation_settings_.find(navigation_handle);
+ if (it != inflight_navigation_settings_.end()) {
+ TransferNavigationContentSettingsToCommittedDocument(
+ it->second, navigation_handle->GetRenderFrameHost());
+ inflight_navigation_settings_.erase(it);
+ }
+
+ delegate_->UpdateLocationBar();
+}
+
+void TabSpecificContentSettings::WebContentsHandler::AppCacheAccessed(
+ const GURL& manifest_url,
+ bool blocked_by_policy) {
+ auto* tscs = TabSpecificContentSettings::GetForCurrentDocument(
+ web_contents()->GetMainFrame());
+ if (tscs)
+ tscs->AppCacheAccessed(manifest_url, blocked_by_policy);
+}
+
+void TabSpecificContentSettings::WebContentsHandler::AddSiteDataObserver(
+ SiteDataObserver* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void TabSpecificContentSettings::WebContentsHandler::RemoveSiteDataObserver(
+ SiteDataObserver* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
+void TabSpecificContentSettings::WebContentsHandler::NotifySiteDataObservers() {
+ for (SiteDataObserver& observer : observer_list_)
+ observer.OnSiteDataAccessed();
+}
+
+TabSpecificContentSettings::WebContentsHandler::
+ InflightNavigationContentSettings::InflightNavigationContentSettings() =
+ default;
+TabSpecificContentSettings::WebContentsHandler::
+ InflightNavigationContentSettings::InflightNavigationContentSettings(
+ const InflightNavigationContentSettings&) = default;
+TabSpecificContentSettings::WebContentsHandler::
+ InflightNavigationContentSettings::InflightNavigationContentSettings(
+ InflightNavigationContentSettings&&) = default;
+
+TabSpecificContentSettings::WebContentsHandler::
+ InflightNavigationContentSettings::~InflightNavigationContentSettings() =
+ default;
+
+TabSpecificContentSettings::WebContentsHandler::
+ InflightNavigationContentSettings&
+ TabSpecificContentSettings::WebContentsHandler::
+ InflightNavigationContentSettings::operator=(
+ InflightNavigationContentSettings&&) = default;
+
+WEB_CONTENTS_USER_DATA_KEY_IMPL(TabSpecificContentSettings::WebContentsHandler)
+
+TabSpecificContentSettings::TabSpecificContentSettings(
+ TabSpecificContentSettings::WebContentsHandler& handler,
+ Delegate* delegate)
+ : handler_(handler),
+ main_frame_(handler_.web_contents()->GetMainFrame()),
+ delegate_(delegate),
+ visible_url_(handler_.web_contents()->GetVisibleURL()),
map_(delegate_->GetSettingsMap()),
- allowed_local_shared_objects_(tab->GetBrowserContext(),
- delegate_->GetAdditionalFileSystemTypes(),
- delegate_->GetIsDeletionDisabledCallback()),
- blocked_local_shared_objects_(tab->GetBrowserContext(),
- delegate_->GetAdditionalFileSystemTypes(),
- delegate_->GetIsDeletionDisabledCallback()),
- geolocation_usages_state_(map_, ContentSettingsType::GEOLOCATION),
- midi_usages_state_(map_, ContentSettingsType::MIDI_SYSEX),
+ allowed_local_shared_objects_(
+ handler_.web_contents()->GetBrowserContext(),
+ delegate_->GetAdditionalFileSystemTypes(),
+ delegate_->GetIsDeletionDisabledCallback()),
+ blocked_local_shared_objects_(
+ handler_.web_contents()->GetBrowserContext(),
+ delegate_->GetAdditionalFileSystemTypes(),
+ delegate_->GetIsDeletionDisabledCallback()),
+ geolocation_usages_state_(std::make_unique<ContentSettingsUsagesState>(
+ delegate_,
+ ContentSettingsType::GEOLOCATION,
+ handler_.web_contents()->GetVisibleURL())),
+ midi_usages_state_(std::make_unique<ContentSettingsUsagesState>(
+ delegate_,
+ ContentSettingsType::MIDI_SYSEX,
+ handler_.web_contents()->GetVisibleURL())),
load_plugins_link_enabled_(true),
microphone_camera_state_(MICROPHONE_CAMERA_NOT_ACCESSED) {
- ClearContentSettingsExceptForNavigationRelatedSettings();
- ClearNavigationRelatedContentSettings();
-
observer_.Add(map_);
}
-TabSpecificContentSettings::~TabSpecificContentSettings() {
- for (SiteDataObserver& observer : observer_list_)
- observer.ContentSettingsDestroyed();
-}
+TabSpecificContentSettings::~TabSpecificContentSettings() = default;
// static
void TabSpecificContentSettings::CreateForWebContents(
content::WebContents* web_contents,
std::unique_ptr<Delegate> delegate) {
- DCHECK(web_contents);
- if (!FromWebContents(web_contents)) {
- web_contents->SetUserData(UserDataKey(),
- base::WrapUnique(new TabSpecificContentSettings(
- web_contents, std::move(delegate))));
+ TabSpecificContentSettings::WebContentsHandler::CreateForWebContents(
+ web_contents, std::move(delegate));
+}
+
+// static
+void TabSpecificContentSettings::DeleteForWebContentsForTest(
+ content::WebContents* web_contents) {
+ if (web_contents->GetMainFrame()) {
+ TabSpecificContentSettings::DeleteForCurrentDocument(
+ web_contents->GetMainFrame());
}
+
+ web_contents->RemoveUserData(
+ TabSpecificContentSettings::WebContentsHandler::UserDataKey());
}
// static
@@ -126,11 +387,18 @@ TabSpecificContentSettings* TabSpecificContentSettings::GetForFrame(
content::RenderFrameHost* frame =
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
- WebContents* web_contents = WebContents::FromRenderFrameHost(frame);
- if (!web_contents)
+ if (!frame)
return nullptr;
+ return TabSpecificContentSettings::GetForCurrentDocument(
+ frame->GetMainFrame());
+}
- return TabSpecificContentSettings::FromWebContents(web_contents);
+// static
+TabSpecificContentSettings* TabSpecificContentSettings::FromWebContents(
+ content::WebContents* web_contents) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ return TabSpecificContentSettings::GetForCurrentDocument(
+ web_contents->GetMainFrame());
}
// static
@@ -197,6 +465,14 @@ void TabSpecificContentSettings::SharedWorkerAccessed(
blocked_by_policy);
}
+// static
+content::WebContentsObserver*
+TabSpecificContentSettings::GetWebContentsObserverForTest(
+ content::WebContents* web_contents) {
+ return TabSpecificContentSettings::WebContentsHandler::FromWebContents(
+ web_contents);
+}
+
bool TabSpecificContentSettings::IsContentBlocked(
ContentSettingsType content_type) const {
DCHECK_NE(ContentSettingsType::GEOLOCATION, content_type)
@@ -330,22 +606,10 @@ void TabSpecificContentSettings::OnDomStorageAccessed(const GURL& url,
else
OnContentAllowed(ContentSettingsType::COOKIES);
- NotifySiteDataObservers();
-}
-
-void TabSpecificContentSettings::OnCookiesAccessed(
- content::NavigationHandle* navigation,
- const content::CookieAccessDetails& details) {
- OnCookiesAccessedImpl(details);
+ handler_.NotifySiteDataObservers();
}
void TabSpecificContentSettings::OnCookiesAccessed(
- content::RenderFrameHost* rfh,
- const content::CookieAccessDetails& details) {
- OnCookiesAccessedImpl(details);
-}
-
-void TabSpecificContentSettings::OnCookiesAccessedImpl(
const content::CookieAccessDetails& details) {
if (details.cookie_list.empty())
return;
@@ -357,7 +621,7 @@ void TabSpecificContentSettings::OnCookiesAccessedImpl(
OnContentAllowed(ContentSettingsType::COOKIES);
}
- NotifySiteDataObservers();
+ handler_.NotifySiteDataObservers();
}
void TabSpecificContentSettings::OnIndexedDBAccessed(const GURL& url,
@@ -370,7 +634,7 @@ void TabSpecificContentSettings::OnIndexedDBAccessed(const GURL& url,
OnContentAllowed(ContentSettingsType::COOKIES);
}
- NotifySiteDataObservers();
+ handler_.NotifySiteDataObservers();
}
void TabSpecificContentSettings::OnCacheStorageAccessed(
@@ -386,36 +650,10 @@ void TabSpecificContentSettings::OnCacheStorageAccessed(
OnContentAllowed(ContentSettingsType::COOKIES);
}
- NotifySiteDataObservers();
+ handler_.NotifySiteDataObservers();
}
void TabSpecificContentSettings::OnServiceWorkerAccessed(
- content::NavigationHandle* navigation,
- const GURL& scope,
- content::AllowServiceWorkerResult allowed) {
- DCHECK(scope.is_valid());
- if (allowed) {
- allowed_local_shared_objects_.service_workers()->Add(
- url::Origin::Create(scope));
- } 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);
- }
-}
-
-void TabSpecificContentSettings::OnServiceWorkerAccessed(
- content::RenderFrameHost* frame,
const GURL& scope,
content::AllowServiceWorkerResult allowed) {
DCHECK(scope.is_valid());
@@ -466,7 +704,7 @@ void TabSpecificContentSettings::OnWebDatabaseAccessed(const GURL& url,
OnContentAllowed(ContentSettingsType::COOKIES);
}
- NotifySiteDataObservers();
+ handler_.NotifySiteDataObservers();
}
void TabSpecificContentSettings::OnFileSystemAccessed(const GURL& url,
@@ -482,13 +720,13 @@ void TabSpecificContentSettings::OnFileSystemAccessed(const GURL& url,
OnContentAllowed(ContentSettingsType::COOKIES);
}
- NotifySiteDataObservers();
+ handler_.NotifySiteDataObservers();
}
void TabSpecificContentSettings::OnGeolocationPermissionSet(
const GURL& requesting_origin,
bool allowed) {
- geolocation_usages_state_.OnPermissionSet(requesting_origin, allowed);
+ geolocation_usages_state_->OnPermissionSet(requesting_origin, allowed);
delegate_->UpdateLocationBar();
}
@@ -564,44 +802,16 @@ void TabSpecificContentSettings::OnMediaStreamPermissionSet(
void TabSpecificContentSettings::OnMidiSysExAccessed(
const GURL& requesting_origin) {
- midi_usages_state_.OnPermissionSet(requesting_origin, true);
+ midi_usages_state_->OnPermissionSet(requesting_origin, true);
OnContentAllowed(ContentSettingsType::MIDI_SYSEX);
}
void TabSpecificContentSettings::OnMidiSysExAccessBlocked(
const GURL& requesting_origin) {
- midi_usages_state_.OnPermissionSet(requesting_origin, false);
+ midi_usages_state_->OnPermissionSet(requesting_origin, false);
OnContentBlocked(ContentSettingsType::MIDI_SYSEX);
}
-void TabSpecificContentSettings::
- ClearContentSettingsExceptForNavigationRelatedSettings() {
- for (auto& status : content_settings_status_) {
- if (status.first == ContentSettingsType::COOKIES ||
- status.first == ContentSettingsType::JAVASCRIPT)
- continue;
- status.second.blocked = false;
- status.second.allowed = false;
- }
- microphone_camera_state_ = MICROPHONE_CAMERA_NOT_ACCESSED;
- camera_was_just_granted_on_site_level_ = false;
- mic_was_just_granted_on_site_level_ = false;
- load_plugins_link_enabled_ = true;
- delegate_->UpdateLocationBar();
-}
-
-void TabSpecificContentSettings::ClearNavigationRelatedContentSettings() {
- blocked_local_shared_objects_.Reset();
- allowed_local_shared_objects_.Reset();
- for (ContentSettingsType type :
- {ContentSettingsType::COOKIES, ContentSettingsType::JAVASCRIPT}) {
- ContentSettingsStatus& status = content_settings_status_[type];
- status.blocked = false;
- status.allowed = false;
- }
- delegate_->UpdateLocationBar();
-}
-
void TabSpecificContentSettings::FlashDownloadBlocked() {
OnContentBlocked(ContentSettingsType::PLUGINS);
}
@@ -635,7 +845,7 @@ void TabSpecificContentSettings::OnContentSettingChanged(
if (!details.update_all() &&
// The visible URL is the URL in the URL field of a tab.
// Currently this should be matched by the |primary_pattern|.
- !details.primary_pattern().Matches(web_contents()->GetVisibleURL())) {
+ !details.primary_pattern().Matches(visible_url_)) {
return;
}
@@ -674,8 +884,7 @@ void TabSpecificContentSettings::OnContentSettingChanged(
case ContentSettingsType::CLIPBOARD_READ_WRITE:
case ContentSettingsType::SENSORS: {
ContentSetting setting = map_->GetContentSetting(
- web_contents()->GetVisibleURL(), web_contents()->GetVisibleURL(),
- content_type, std::string());
+ visible_url_, visible_url_, content_type, std::string());
// 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) {
@@ -696,82 +905,7 @@ void TabSpecificContentSettings::OnContentSettingChanged(
if (!ShouldSendUpdatedContentSettingsRulesToRenderer(content_type))
return;
- MaybeSendRendererContentSettingsRules(web_contents());
-}
-
-void TabSpecificContentSettings::MaybeSendRendererContentSettingsRules(
- content::WebContents* web_contents) {
- // Only send a message to the renderer if it is initialised and not dead.
- // Otherwise, the IPC messages will be queued in the browser process,
- // potentially causing large memory leaks. See https://crbug.com/875937.
- content::RenderProcessHost* process =
- web_contents->GetMainFrame()->GetProcess();
- if (!process->IsInitializedAndNotDead())
- return;
-
- RendererContentSettingRules rules;
- GetRendererContentSettingRules(map_, &rules);
- delegate_->SetContentSettingRules(process, rules);
-}
-
-void TabSpecificContentSettings::RenderFrameForInterstitialPageCreated(
- content::RenderFrameHost* render_frame_host) {
- // We want to tell the renderer-side code to ignore content settings for this
- // page.
- mojo::AssociatedRemote<content_settings::mojom::ContentSettingsAgent>
- content_settings_agent;
- render_frame_host->GetRemoteAssociatedInterfaces()->GetInterface(
- &content_settings_agent);
- content_settings_agent->SetAsInterstitial();
-}
-
-void TabSpecificContentSettings::DidStartNavigation(
- content::NavigationHandle* navigation_handle) {
- if (!navigation_handle->IsInMainFrame() ||
- navigation_handle->IsSameDocument()) {
- return;
- }
-
- ClearNavigationRelatedContentSettings();
-}
-
-void TabSpecificContentSettings::ReadyToCommitNavigation(
- content::NavigationHandle* navigation_handle) {
- if (!navigation_handle->IsInMainFrame() ||
- navigation_handle->IsSameDocument()) {
- return;
- }
-
- PrefService* prefs = delegate_->GetPrefs();
- if (prefs &&
- !prefs->GetBoolean(
- security_state::prefs::kStricterMixedContentTreatmentEnabled)) {
- auto* render_frame_host = navigation_handle->GetRenderFrameHost();
- mojo::AssociatedRemote<content_settings::mojom::ContentSettingsAgent>
- content_settings_agent;
- render_frame_host->GetRemoteAssociatedInterfaces()->GetInterface(
- &content_settings_agent);
- content_settings_agent->SetDisabledMixedContentUpgrades();
- }
-
- // There may be content settings that were updated for the navigated URL.
- // These would not have been sent before if we're navigating cross-origin.
- // Ensure up to date rules are sent before navigation commits.
- MaybeSendRendererContentSettingsRules(navigation_handle->GetWebContents());
-}
-
-void TabSpecificContentSettings::DidFinishNavigation(
- content::NavigationHandle* navigation_handle) {
- if (!navigation_handle->IsInMainFrame() ||
- !navigation_handle->HasCommitted() ||
- navigation_handle->IsSameDocument()) {
- return;
- }
-
- ClearContentSettingsExceptForNavigationRelatedSettings();
- GeolocationDidNavigate(navigation_handle);
- MidiDidNavigate(navigation_handle);
- ClearContentSettingsChangedViaPageInfo();
+ MaybeSendRendererContentSettingsRules(main_frame_, map_, delegate_);
}
void TabSpecificContentSettings::AppCacheAccessed(const GURL& manifest_url,
@@ -787,39 +921,10 @@ void TabSpecificContentSettings::AppCacheAccessed(const GURL& manifest_url,
}
}
-void TabSpecificContentSettings::AddSiteDataObserver(
- SiteDataObserver* observer) {
- observer_list_.AddObserver(observer);
-}
-
-void TabSpecificContentSettings::RemoveSiteDataObserver(
- SiteDataObserver* observer) {
- observer_list_.RemoveObserver(observer);
-}
-
-void TabSpecificContentSettings::NotifySiteDataObservers() {
- for (SiteDataObserver& observer : observer_list_)
- observer.OnSiteDataAccessed();
-}
-
void TabSpecificContentSettings::ClearContentSettingsChangedViaPageInfo() {
content_settings_changed_via_page_info_.clear();
}
-void TabSpecificContentSettings::GeolocationDidNavigate(
- content::NavigationHandle* navigation_handle) {
- geolocation_usages_state_.ClearStateMap();
- geolocation_usages_state_.DidNavigate(navigation_handle->GetURL(),
- navigation_handle->GetPreviousURL());
-}
-
-void TabSpecificContentSettings::MidiDidNavigate(
- content::NavigationHandle* navigation_handle) {
- midi_usages_state_.ClearStateMap();
- midi_usages_state_.DidNavigate(navigation_handle->GetURL(),
- navigation_handle->GetPreviousURL());
-}
-
void TabSpecificContentSettings::BlockAllContentForTesting() {
content_settings::ContentSettingsRegistry* registry =
content_settings::ContentSettingsRegistry::GetInstance();
@@ -834,16 +939,16 @@ void TabSpecificContentSettings::BlockAllContentForTesting() {
// Geolocation and media must be blocked separately, as the generic
// TabSpecificContentSettings::OnContentBlocked does not apply to them.
- OnGeolocationPermissionSet(web_contents()->GetLastCommittedURL(), false);
+ OnGeolocationPermissionSet(main_frame_->GetLastCommittedURL(), false);
MicrophoneCameraStateFlags media_blocked =
static_cast<MicrophoneCameraStateFlags>(
TabSpecificContentSettings::MICROPHONE_ACCESSED |
TabSpecificContentSettings::MICROPHONE_BLOCKED |
TabSpecificContentSettings::CAMERA_ACCESSED |
TabSpecificContentSettings::CAMERA_BLOCKED);
- OnMediaStreamPermissionSet(web_contents()->GetLastCommittedURL(),
- media_blocked, std::string(), std::string(),
- std::string(), std::string());
+ OnMediaStreamPermissionSet(main_frame_->GetLastCommittedURL(), media_blocked,
+ std::string(), std::string(), std::string(),
+ std::string());
}
void TabSpecificContentSettings::ContentSettingChangedViaPageInfo(
@@ -857,6 +962,6 @@ bool TabSpecificContentSettings::HasContentSettingChangedViaPageInfo(
content_settings_changed_via_page_info_.end();
}
-WEB_CONTENTS_USER_DATA_KEY_IMPL(TabSpecificContentSettings)
+RENDER_DOCUMENT_HOST_USER_DATA_KEY_IMPL(TabSpecificContentSettings)
} // namespace content_settings
diff --git a/chromium/components/content_settings/browser/tab_specific_content_settings.h b/chromium/components/content_settings/browser/tab_specific_content_settings.h
index 39583b71436..38529f2676f 100644
--- a/chromium/components/content_settings/browser/tab_specific_content_settings.h
+++ b/chromium/components/content_settings/browser/tab_specific_content_settings.h
@@ -14,17 +14,19 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/scoped_observer.h"
#include "build/build_config.h"
#include "components/browsing_data/content/cookie_helper.h"
#include "components/browsing_data/content/local_shared_objects_container.h"
-#include "components/content_settings/browser/content_settings_usages_state.h"
#include "components/content_settings/core/browser/content_settings_observer.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "content/public/browser/allow_service_worker_result.h"
+#include "content/public/browser/render_document_host_user_data.h"
+#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
@@ -36,6 +38,8 @@ namespace url {
class Origin;
} // namespace url
+class ContentSettingsUsagesState;
+
namespace content_settings {
// TODO(msramek): Media is storing their state in TabSpecificContentSettings:
@@ -44,13 +48,28 @@ namespace content_settings {
// content::WebContentsUserData
// This class manages state about permissions, content settings, cookies and
-// site data for a specific WebContents. It tracks which content was accessed
-// and which content was blocked. Based on this it provides information about
-// which types of content were accessed and blocked.
+// site data for a specific page (main document and all of its child frames). It
+// tracks which content was accessed and which content was blocked. Based on
+// this it provides information about which types of content were accessed and
+// blocked.
+//
+// Tracking is done per main document so instances of this class will be deleted
+// when the main document is deleted. This can happen after the tab navigates
+// away to a new document or when the tab itself is deleted, so you should not
+// keep references to objects of this class.
+//
+// When a page enters the back-forward cache its associated
+// TabSpecificContentSettings are not cleared and will be restored along with
+// the document when navigating back. These stored instances still listen to
+// content settings updates and keep their internal state up to date.
+//
+// Events tied to a main frame navigation will be associated with the newly
+// loaded page once the navigation commits or discarded if it does not.
+//
+// TODO(carlscab): Rename this class to PageSpecificContentSettings
class TabSpecificContentSettings
- : public content::WebContentsObserver,
- public content_settings::Observer,
- public content::WebContentsUserData<TabSpecificContentSettings> {
+ : public content_settings::Observer,
+ public content::RenderDocumentHostUserData<TabSpecificContentSettings> {
public:
// Fields describing the current mic/camera state. If a page has attempted to
// access a device, the XXX_ACCESSED bit will be set. If access was blocked,
@@ -85,6 +104,10 @@ class TabSpecificContentSettings
// Gets the settings map for the current web contents.
virtual HostContentSettingsMap* GetSettingsMap() = 0;
+ virtual ContentSetting GetEmbargoSetting(
+ const GURL& request_origin,
+ ContentSettingsType permission) = 0;
+
// Gets any additional file system types which should be used when
// constructing a browsing_data::FileSystemHelper.
virtual std::vector<storage::FileSystemType>
@@ -114,23 +137,20 @@ class TabSpecificContentSettings
// |TabSpecificContentSettings|.
class SiteDataObserver {
public:
- explicit SiteDataObserver(
- TabSpecificContentSettings* tab_specific_content_settings);
+ explicit SiteDataObserver(content::WebContents* web_contents);
virtual ~SiteDataObserver();
// Called whenever site data is accessed.
virtual void OnSiteDataAccessed() = 0;
- TabSpecificContentSettings* tab_specific_content_settings() {
- return tab_specific_content_settings_;
- }
+ content::WebContents* web_contents() { return web_contents_; }
- // Called when the TabSpecificContentSettings is destroyed; nulls out
+ // Called when the WebContents is destroyed; nulls out
// the local reference.
- void ContentSettingsDestroyed();
+ void WebContentsDestroyed();
private:
- TabSpecificContentSettings* tab_specific_content_settings_;
+ content::WebContents* web_contents_;
DISALLOW_COPY_AND_ASSIGN(SiteDataObserver);
};
@@ -139,10 +159,14 @@ class TabSpecificContentSettings
static void CreateForWebContents(content::WebContents* web_contents,
std::unique_ptr<Delegate> delegate);
+ static void DeleteForWebContentsForTest(content::WebContents* web_contents);
// Returns the object given a RenderFrameHost ids.
static TabSpecificContentSettings* GetForFrame(int render_process_id,
int render_frame_id);
+ // TODO(carlscab): Get rid of this and use GetForFrame instead
+ static TabSpecificContentSettings* FromWebContents(
+ content::WebContents* contents);
// Called when a specific Web database in the current page was accessed. If
// access was blocked due to the user's content settings,
@@ -188,17 +212,15 @@ class TabSpecificContentSettings
const url::Origin& constructor_origin,
bool blocked_by_policy);
- // Resets the |content_settings_status_|, except for
- // information which are needed for navigation: ContentSettingsType::COOKIES
- // for cookies and service workers, and ContentSettingsType::JAVASCRIPT for
- // service workers.
- // Only public for tests.
- void ClearContentSettingsExceptForNavigationRelatedSettings();
+ static content::WebContentsObserver* GetWebContentsObserverForTest(
+ content::WebContents* web_contents);
- // Resets navigation related information (ContentSettingsType::COOKIES and
- // ContentSettingsType::JAVASCRIPT).
- // Only public for tests.
- void ClearNavigationRelatedContentSettings();
+ // Returns a WeakPtr to this instance. Given that TabSpecificContentSettings
+ // instances are tied to a page it is generally unsafe to store these
+ // references, instead a WeakPtr should be used instead.
+ base::WeakPtr<TabSpecificContentSettings> AsWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+ }
// Notifies that a Flash download has been blocked.
void FlashDownloadBlocked();
@@ -259,13 +281,13 @@ class TabSpecificContentSettings
// Returns the ContentSettingsUsagesState that controls the
// geolocation API usage on this page.
const ContentSettingsUsagesState& geolocation_usages_state() const {
- return geolocation_usages_state_;
+ return *geolocation_usages_state_;
}
// Returns the ContentSettingsUsageState that controls the MIDI usage on
// this page.
const ContentSettingsUsagesState& midi_usages_state() const {
- return midi_usages_state_;
+ return *midi_usages_state_;
}
// Returns the |LocalSharedObjectsContainer| instances corresponding to all
@@ -329,12 +351,9 @@ class TabSpecificContentSettings
void OnMidiSysExAccessed(const GURL& reqesting_origin);
void OnMidiSysExAccessBlocked(const GURL& requesting_origin);
- // 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);
+ void OnCookiesAccessed(const content::CookieAccessDetails& details);
+ void OnServiceWorkerAccessed(const GURL& scope,
+ content::AllowServiceWorkerResult allowed);
// Block all content. Used for testing content setting bubbles.
void BlockAllContentForTesting();
@@ -346,45 +365,121 @@ class TabSpecificContentSettings
// since the last navigation.
bool HasContentSettingChangedViaPageInfo(ContentSettingsType type) const;
- Delegate* delegate() { return delegate_.get(); }
+ Delegate* delegate() { return delegate_; }
private:
- friend class content::WebContentsUserData<TabSpecificContentSettings>;
+ friend class content::RenderDocumentHostUserData<TabSpecificContentSettings>;
+
+ // This class attaches to WebContents to listen to events and route them to
+ // appropriate TabSpecificContentSettings, 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:
+ static void CreateForWebContents(content::WebContents* web_contents,
+ std::unique_ptr<Delegate> delegate);
- explicit TabSpecificContentSettings(content::WebContents* tab,
- std::unique_ptr<Delegate> delegate);
+ 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);
- void MaybeSendRendererContentSettingsRules(
- content::WebContents* web_contents);
+ // Removes the given |SiteDataObserver|.
+ void RemoveSiteDataObserver(SiteDataObserver* observer);
- // content::WebContentsObserver overrides.
- void RenderFrameForInterstitialPageCreated(
- content::RenderFrameHost* render_frame_host) override;
- void DidStartNavigation(
- content::NavigationHandle* navigation_handle) override;
- void ReadyToCommitNavigation(
- content::NavigationHandle* navigation_handle) override;
- void DidFinishNavigation(
- content::NavigationHandle* navigation_handle) override;
- void AppCacheAccessed(const GURL& manifest_url,
- bool blocked_by_policy) 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;
+ // Notifies all registered |SiteDataObserver|s.
+ void NotifySiteDataObservers();
+
+ private:
+ friend class content::WebContentsUserData<WebContentsHandler>;
+
+ // 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.
+ struct InflightNavigationContentSettings {
+ InflightNavigationContentSettings();
+ InflightNavigationContentSettings(
+ const InflightNavigationContentSettings&);
+ InflightNavigationContentSettings(InflightNavigationContentSettings&&);
+
+ ~InflightNavigationContentSettings();
+
+ InflightNavigationContentSettings& operator=(
+ InflightNavigationContentSettings&&);
+
+ std::vector<content::CookieAccessDetails> cookie_accesses;
+ std::vector<std::pair<GURL, content::AllowServiceWorkerResult>>
+ service_worker_accesses;
+ };
+
+ // 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 RenderFrameForInterstitialPageCreated(
+ content::RenderFrameHost* render_frame_host) override;
+ void DidStartNavigation(
+ content::NavigationHandle* navigation_handle) override;
+ void ReadyToCommitNavigation(
+ content::NavigationHandle* navigation_handle) override;
+ void DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) override;
+ // TODO(carlscab): Change interface to pass target RenderFrameHost
+ void AppCacheAccessed(const GURL& manifest_url,
+ bool blocked_by_policy) 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_;
+
+ HostContentSettingsMap* map_;
+
+ // All currently registered |SiteDataObserver|s.
+ base::ObserverList<SiteDataObserver>::Unchecked observer_list_;
+
+ // Keeps track of currently inflight navigations. Updates for those are
+ // kept aside until the navigation commits.
+ std::unordered_map<content::NavigationHandle*,
+ InflightNavigationContentSettings>
+ inflight_navigation_settings_;
+
+ WEB_CONTENTS_USER_DATA_KEY_DECL();
+ };
+
+ explicit TabSpecificContentSettings(
+ TabSpecificContentSettings::WebContentsHandler& handler,
+ Delegate* delegate);
+
+ void AppCacheAccessed(const GURL& manifest_url, bool blocked_by_policy);
// content_settings::Observer implementation.
void OnContentSettingChanged(const ContentSettingsPattern& primary_pattern,
@@ -392,25 +487,15 @@ class TabSpecificContentSettings
ContentSettingsType content_type,
const std::string& resource_identifier) override;
- // Notifies all registered |SiteDataObserver|s.
- void NotifySiteDataObservers();
-
// Clears settings changed by the user via PageInfo since the last navigation.
void ClearContentSettingsChangedViaPageInfo();
- // Updates Geolocation settings on navigation.
- void GeolocationDidNavigate(content::NavigationHandle* navigation_handle);
-
- // Updates MIDI settings on navigation.
- void MidiDidNavigate(content::NavigationHandle* navigation_handle);
+ WebContentsHandler& handler_;
+ content::RenderFrameHost* main_frame_;
- // Updates the list of allowed and blocked cookies.
- void OnCookiesAccessedImpl(const content::CookieAccessDetails& details);
+ Delegate* delegate_;
- std::unique_ptr<Delegate> delegate_;
-
- // All currently registered |SiteDataObserver|s.
- base::ObserverList<SiteDataObserver>::Unchecked observer_list_;
+ GURL visible_url_;
struct ContentSettingsStatus {
bool blocked;
@@ -427,10 +512,10 @@ class TabSpecificContentSettings
browsing_data::LocalSharedObjectsContainer blocked_local_shared_objects_;
// Manages information about Geolocation API usage in this page.
- ContentSettingsUsagesState geolocation_usages_state_;
+ std::unique_ptr<ContentSettingsUsagesState> geolocation_usages_state_;
// Manages information about MIDI usages in this page.
- ContentSettingsUsagesState midi_usages_state_;
+ std::unique_ptr<ContentSettingsUsagesState> midi_usages_state_;
// Stores whether the user can load blocked plugins on this page.
bool load_plugins_link_enabled_;
@@ -464,7 +549,9 @@ class TabSpecificContentSettings
// navigation. Used to determine whether to display the settings in page info.
std::set<ContentSettingsType> content_settings_changed_via_page_info_;
- WEB_CONTENTS_USER_DATA_KEY_DECL();
+ RENDER_DOCUMENT_HOST_USER_DATA_KEY_DECL();
+
+ base::WeakPtrFactory<TabSpecificContentSettings> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(TabSpecificContentSettings);
};
diff --git a/chromium/components/content_settings/browser/tab_specific_content_settings_unittest.cc b/chromium/components/content_settings/browser/tab_specific_content_settings_unittest.cc
index 2ac8dc5c645..9477ad9153b 100644
--- a/chromium/components/content_settings/browser/tab_specific_content_settings_unittest.cc
+++ b/chromium/components/content_settings/browser/tab_specific_content_settings_unittest.cc
@@ -9,10 +9,13 @@
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "components/content_settings/browser/test_tab_specific_content_settings_delegate.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/security_state/core/security_state.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "content/public/browser/web_contents_observer.h"
#include "content/public/test/mock_navigation_handle.h"
+#include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_renderer_host.h"
#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_options.h"
@@ -25,9 +28,8 @@ namespace {
class MockSiteDataObserver
: public TabSpecificContentSettings::SiteDataObserver {
public:
- explicit MockSiteDataObserver(
- TabSpecificContentSettings* tab_specific_content_settings)
- : SiteDataObserver(tab_specific_content_settings) {}
+ explicit MockSiteDataObserver(content::WebContents* web_contents)
+ : SiteDataObserver(web_contents) {}
~MockSiteDataObserver() override = default;
@@ -45,11 +47,12 @@ class TabSpecificContentSettingsTest
void SetUp() override {
RenderViewHostTestHarness::SetUp();
HostContentSettingsMap::RegisterProfilePrefs(prefs_.registry());
- security_state::RegisterProfilePrefs(prefs_.registry());
settings_map_ = base::MakeRefCounted<HostContentSettingsMap>(
&prefs_, false, false, false, false);
TabSpecificContentSettings::CreateForWebContents(
- web_contents(), std::make_unique<TestDelegate>(this));
+ web_contents(),
+ std::make_unique<TestTabSpecificContentSettingsDelegate>(
+ &prefs_, settings_map_.get()));
}
void TearDown() override {
@@ -59,57 +62,18 @@ class TabSpecificContentSettingsTest
HostContentSettingsMap* settings_map() { return settings_map_.get(); }
- private:
- class TestDelegate : public TabSpecificContentSettings::Delegate {
- public:
- explicit TestDelegate(TabSpecificContentSettingsTest* test) : test_(test) {}
-
- void UpdateLocationBar() override {}
-
- void SetContentSettingRules(
- content::RenderProcessHost* process,
- const RendererContentSettingRules& rules) override {}
-
- PrefService* GetPrefs() override { return &test_->prefs_; }
-
- HostContentSettingsMap* GetSettingsMap() override {
- return test_->settings_map_.get();
- }
-
- std::vector<storage::FileSystemType> GetAdditionalFileSystemTypes()
- override {
- return {};
- }
-
- browsing_data::CookieHelper::IsDeletionDisabledCallback
- GetIsDeletionDisabledCallback() override {
- return base::NullCallback();
- }
-
- bool IsMicrophoneCameraStateChanged(
- TabSpecificContentSettings::MicrophoneCameraState
- microphone_camera_state,
- const std::string& media_stream_selected_audio_device,
- const std::string& media_stream_selected_video_device) override {
- return false;
- }
-
- TabSpecificContentSettings::MicrophoneCameraState GetMicrophoneCameraState()
- override {
- return TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED;
- }
-
- void OnContentBlocked(ContentSettingsType type) override {}
-
- private:
- TabSpecificContentSettingsTest* test_;
- };
+ content::WebContentsObserver* GetHandle() {
+ return TabSpecificContentSettings::GetWebContentsObserverForTest(
+ web_contents());
+ }
+ private:
sync_preferences::TestingPrefServiceSyncable prefs_;
scoped_refptr<HostContentSettingsMap> settings_map_;
};
TEST_F(TabSpecificContentSettingsTest, BlockedContent) {
+ NavigateAndCommit(GURL("http://google.com"));
TabSpecificContentSettings* content_settings =
TabSpecificContentSettings::FromWebContents(web_contents());
@@ -136,13 +100,14 @@ TEST_F(TabSpecificContentSettingsTest, BlockedContent) {
std::unique_ptr<net::CanonicalCookie> cookie1(net::CanonicalCookie::Create(
origin, "A=B", base::Time::Now(), base::nullopt /* server_time */));
ASSERT_TRUE(cookie1);
- static_cast<content::WebContentsObserver*>(content_settings)
- ->OnCookiesAccessed(web_contents()->GetMainFrame(),
- {content::CookieAccessDetails::Type::kChange,
- origin,
- origin,
- {*cookie1},
- false});
+ GetHandle()->OnCookiesAccessed(web_contents()->GetMainFrame(),
+ {content::CookieAccessDetails::Type::kChange,
+ origin,
+ origin,
+ {*cookie1},
+ false});
+ content_settings =
+ TabSpecificContentSettings::FromWebContents(web_contents());
#if !defined(OS_ANDROID)
content_settings->OnContentBlocked(ContentSettingsType::IMAGES);
#endif
@@ -173,64 +138,54 @@ TEST_F(TabSpecificContentSettingsTest, BlockedContent) {
content_settings->IsContentBlocked(ContentSettingsType::MEDIASTREAM_MIC));
EXPECT_TRUE(content_settings->IsContentBlocked(
ContentSettingsType::MEDIASTREAM_CAMERA));
- static_cast<content::WebContentsObserver*>(content_settings)
- ->OnCookiesAccessed(web_contents()->GetMainFrame(),
- {content::CookieAccessDetails::Type::kChange,
- origin,
- origin,
- {*cookie1},
- false});
+ GetHandle()->OnCookiesAccessed(web_contents()->GetMainFrame(),
+ {content::CookieAccessDetails::Type::kChange,
+ origin,
+ origin,
+ {*cookie1},
+ false});
// Block a cookie.
std::unique_ptr<net::CanonicalCookie> cookie2(net::CanonicalCookie::Create(
origin, "C=D", base::Time::Now(), base::nullopt /* server_time */));
ASSERT_TRUE(cookie2);
- static_cast<content::WebContentsObserver*>(content_settings)
- ->OnCookiesAccessed(web_contents()->GetMainFrame(),
- {content::CookieAccessDetails::Type::kChange,
- origin,
- origin,
- {*cookie2},
- true});
+ GetHandle()->OnCookiesAccessed(web_contents()->GetMainFrame(),
+ {content::CookieAccessDetails::Type::kChange,
+ origin,
+ origin,
+ {*cookie2},
+ true});
EXPECT_TRUE(content_settings->IsContentBlocked(ContentSettingsType::COOKIES));
// Block a javascript during a navigation.
- content::MockNavigationHandle navigation_handle;
- static_cast<content::WebContentsObserver*>(content_settings)
- ->OnServiceWorkerAccessed(
- &navigation_handle, GURL("http://google.com"),
- content::AllowServiceWorkerResult::FromPolicy(true, false));
- EXPECT_TRUE(
+ // Create a pending navigation.
+ std::unique_ptr<content::NavigationSimulator> simulator =
+ content::NavigationSimulator::CreateBrowserInitiated(
+ GURL("http://google.com"), web_contents());
+ simulator->SetTransition(ui::PAGE_TRANSITION_LINK);
+ simulator->Start();
+ GetHandle()->OnServiceWorkerAccessed(
+ simulator->GetNavigationHandle(), GURL("http://google.com"),
+ content::AllowServiceWorkerResult::FromPolicy(true, false));
+ content_settings =
+ TabSpecificContentSettings::FromWebContents(web_contents());
+ EXPECT_FALSE(
content_settings->IsContentBlocked(ContentSettingsType::JAVASCRIPT));
+ simulator->Commit();
+ content_settings =
+ TabSpecificContentSettings::FromWebContents(web_contents());
// Block a javascript when page starts to start ServiceWorker.
- static_cast<content::WebContentsObserver*>(content_settings)
- ->OnServiceWorkerAccessed(
- web_contents()->GetMainFrame(), GURL("http://google.com"),
- content::AllowServiceWorkerResult::FromPolicy(true, false));
+ GetHandle()->OnServiceWorkerAccessed(
+ web_contents()->GetMainFrame(), GURL("http://google.com"),
+ content::AllowServiceWorkerResult::FromPolicy(true, false));
EXPECT_TRUE(
content_settings->IsContentBlocked(ContentSettingsType::JAVASCRIPT));
// Reset blocked content settings.
- content_settings->ClearContentSettingsExceptForNavigationRelatedSettings();
-
- // Reset blocked content settings.
- content_settings->ClearContentSettingsExceptForNavigationRelatedSettings();
-#if !defined(OS_ANDROID)
- EXPECT_FALSE(content_settings->IsContentBlocked(ContentSettingsType::IMAGES));
- EXPECT_FALSE(
- content_settings->IsContentBlocked(ContentSettingsType::PLUGINS));
-#endif
- EXPECT_TRUE(
- content_settings->IsContentBlocked(ContentSettingsType::JAVASCRIPT));
- EXPECT_TRUE(content_settings->IsContentBlocked(ContentSettingsType::COOKIES));
- EXPECT_FALSE(content_settings->IsContentBlocked(ContentSettingsType::POPUPS));
- EXPECT_FALSE(
- content_settings->IsContentBlocked(ContentSettingsType::MEDIASTREAM_MIC));
- EXPECT_FALSE(content_settings->IsContentBlocked(
- ContentSettingsType::MEDIASTREAM_CAMERA));
-
- content_settings->ClearNavigationRelatedContentSettings();
+ NavigateAndCommit(GURL("http://google.com"));
+ content_settings =
+ TabSpecificContentSettings::FromWebContents(web_contents());
#if !defined(OS_ANDROID)
EXPECT_FALSE(content_settings->IsContentBlocked(ContentSettingsType::IMAGES));
EXPECT_FALSE(
@@ -248,6 +203,7 @@ TEST_F(TabSpecificContentSettingsTest, BlockedContent) {
}
TEST_F(TabSpecificContentSettingsTest, BlockedFileSystems) {
+ NavigateAndCommit(GURL("http://google.com"));
TabSpecificContentSettings* content_settings =
TabSpecificContentSettings::FromWebContents(web_contents());
@@ -262,6 +218,7 @@ TEST_F(TabSpecificContentSettingsTest, BlockedFileSystems) {
}
TEST_F(TabSpecificContentSettingsTest, AllowedContent) {
+ NavigateAndCommit(GURL("http://google.com"));
TabSpecificContentSettings* content_settings =
TabSpecificContentSettings::FromWebContents(web_contents());
@@ -281,13 +238,12 @@ TEST_F(TabSpecificContentSettingsTest, AllowedContent) {
std::unique_ptr<net::CanonicalCookie> cookie1(net::CanonicalCookie::Create(
origin, "A=B", base::Time::Now(), base::nullopt /* server_time */));
ASSERT_TRUE(cookie1);
- static_cast<content::WebContentsObserver*>(content_settings)
- ->OnCookiesAccessed(web_contents()->GetMainFrame(),
- {content::CookieAccessDetails::Type::kChange,
- origin,
- origin,
- {*cookie1},
- false});
+ GetHandle()->OnCookiesAccessed(web_contents()->GetMainFrame(),
+ {content::CookieAccessDetails::Type::kChange,
+ origin,
+ origin,
+ {*cookie1},
+ false});
ASSERT_TRUE(content_settings->IsContentAllowed(ContentSettingsType::COOKIES));
ASSERT_FALSE(
content_settings->IsContentBlocked(ContentSettingsType::COOKIES));
@@ -296,18 +252,18 @@ TEST_F(TabSpecificContentSettingsTest, AllowedContent) {
std::unique_ptr<net::CanonicalCookie> cookie2(net::CanonicalCookie::Create(
origin, "C=D", base::Time::Now(), base::nullopt /* server_time */));
ASSERT_TRUE(cookie2);
- static_cast<content::WebContentsObserver*>(content_settings)
- ->OnCookiesAccessed(web_contents()->GetMainFrame(),
- {content::CookieAccessDetails::Type::kChange,
- origin,
- origin,
- {*cookie2},
- true});
+ GetHandle()->OnCookiesAccessed(web_contents()->GetMainFrame(),
+ {content::CookieAccessDetails::Type::kChange,
+ origin,
+ origin,
+ {*cookie2},
+ true});
ASSERT_TRUE(content_settings->IsContentAllowed(ContentSettingsType::COOKIES));
ASSERT_TRUE(content_settings->IsContentBlocked(ContentSettingsType::COOKIES));
}
TEST_F(TabSpecificContentSettingsTest, EmptyCookieList) {
+ NavigateAndCommit(GURL("http://google.com"));
TabSpecificContentSettings* content_settings =
TabSpecificContentSettings::FromWebContents(web_contents());
@@ -315,11 +271,10 @@ TEST_F(TabSpecificContentSettingsTest, EmptyCookieList) {
content_settings->IsContentAllowed(ContentSettingsType::COOKIES));
ASSERT_FALSE(
content_settings->IsContentBlocked(ContentSettingsType::COOKIES));
- static_cast<content::WebContentsObserver*>(content_settings)
- ->OnCookiesAccessed(
- web_contents()->GetMainFrame(),
- {content::CookieAccessDetails::Type::kRead, GURL("http://google.com"),
- GURL("http://google.com"), net::CookieList(), true});
+ GetHandle()->OnCookiesAccessed(
+ web_contents()->GetMainFrame(),
+ {content::CookieAccessDetails::Type::kRead, GURL("http://google.com"),
+ GURL("http://google.com"), net::CookieList(), true});
ASSERT_FALSE(
content_settings->IsContentAllowed(ContentSettingsType::COOKIES));
ASSERT_FALSE(
@@ -327,9 +282,10 @@ TEST_F(TabSpecificContentSettingsTest, EmptyCookieList) {
}
TEST_F(TabSpecificContentSettingsTest, SiteDataObserver) {
+ NavigateAndCommit(GURL("http://google.com"));
TabSpecificContentSettings* content_settings =
TabSpecificContentSettings::FromWebContents(web_contents());
- MockSiteDataObserver mock_observer(content_settings);
+ MockSiteDataObserver mock_observer(web_contents());
EXPECT_CALL(mock_observer, OnSiteDataAccessed()).Times(6);
bool blocked_by_policy = false;
@@ -337,13 +293,12 @@ TEST_F(TabSpecificContentSettingsTest, SiteDataObserver) {
std::unique_ptr<net::CanonicalCookie> cookie(net::CanonicalCookie::Create(
origin, "A=B", base::Time::Now(), base::nullopt /* server_time */));
ASSERT_TRUE(cookie);
- static_cast<content::WebContentsObserver*>(content_settings)
- ->OnCookiesAccessed(web_contents()->GetMainFrame(),
- {content::CookieAccessDetails::Type::kChange,
- origin,
- origin,
- {*cookie},
- blocked_by_policy});
+ GetHandle()->OnCookiesAccessed(web_contents()->GetMainFrame(),
+ {content::CookieAccessDetails::Type::kChange,
+ origin,
+ origin,
+ {*cookie},
+ blocked_by_policy});
net::CookieList cookie_list;
std::unique_ptr<net::CanonicalCookie> other_cookie(
@@ -353,11 +308,10 @@ TEST_F(TabSpecificContentSettingsTest, SiteDataObserver) {
ASSERT_TRUE(other_cookie);
cookie_list.push_back(*other_cookie);
- static_cast<content::WebContentsObserver*>(content_settings)
- ->OnCookiesAccessed(
- web_contents()->GetMainFrame(),
- {content::CookieAccessDetails::Type::kRead, GURL("http://google.com"),
- GURL("http://google.com"), cookie_list, blocked_by_policy});
+ GetHandle()->OnCookiesAccessed(
+ web_contents()->GetMainFrame(),
+ {content::CookieAccessDetails::Type::kRead, GURL("http://google.com"),
+ GURL("http://google.com"), cookie_list, blocked_by_policy});
content_settings->OnFileSystemAccessed(GURL("http://google.com"),
blocked_by_policy);
content_settings->OnIndexedDBAccessed(GURL("http://google.com"),
@@ -369,19 +323,19 @@ TEST_F(TabSpecificContentSettingsTest, SiteDataObserver) {
}
TEST_F(TabSpecificContentSettingsTest, LocalSharedObjectsContainer) {
+ NavigateAndCommit(GURL("http://google.com"));
TabSpecificContentSettings* content_settings =
TabSpecificContentSettings::FromWebContents(web_contents());
bool blocked_by_policy = false;
auto cookie = net::CanonicalCookie::Create(GURL("http://google.com"), "k=v",
base::Time::Now(),
base::nullopt /* server_time */);
- static_cast<content::WebContentsObserver*>(content_settings)
- ->OnCookiesAccessed(web_contents()->GetMainFrame(),
- {content::CookieAccessDetails::Type::kRead,
- GURL("http://google.com"),
- GURL("http://google.com"),
- {*cookie},
- blocked_by_policy});
+ GetHandle()->OnCookiesAccessed(web_contents()->GetMainFrame(),
+ {content::CookieAccessDetails::Type::kRead,
+ GURL("http://google.com"),
+ GURL("http://google.com"),
+ {*cookie},
+ blocked_by_policy});
content_settings->OnFileSystemAccessed(GURL("https://www.google.com"),
blocked_by_policy);
content_settings->OnIndexedDBAccessed(GURL("https://localhost"),
@@ -406,6 +360,7 @@ TEST_F(TabSpecificContentSettingsTest, LocalSharedObjectsContainer) {
}
TEST_F(TabSpecificContentSettingsTest, LocalSharedObjectsContainerCookie) {
+ NavigateAndCommit(GURL("http://google.com"));
TabSpecificContentSettings* content_settings =
TabSpecificContentSettings::FromWebContents(web_contents());
bool blocked_by_policy = false;
@@ -421,24 +376,22 @@ TEST_F(TabSpecificContentSettingsTest, LocalSharedObjectsContainerCookie) {
auto cookie4 = net::CanonicalCookie::Create(
GURL("http://www.google.com"), "k4=v; Domain=.www.google.com",
base::Time::Now(), base::nullopt /* server_time */);
- static_cast<content::WebContentsObserver*>(content_settings)
- ->OnCookiesAccessed(web_contents()->GetMainFrame(),
- {content::CookieAccessDetails::Type::kRead,
- GURL("http://www.google.com"),
- GURL("http://www.google.com"),
- {*cookie1, *cookie2, *cookie3, *cookie4},
- blocked_by_policy});
+ GetHandle()->OnCookiesAccessed(web_contents()->GetMainFrame(),
+ {content::CookieAccessDetails::Type::kRead,
+ GURL("http://www.google.com"),
+ GURL("http://www.google.com"),
+ {*cookie1, *cookie2, *cookie3, *cookie4},
+ blocked_by_policy});
auto cookie5 = net::CanonicalCookie::Create(GURL("https://www.google.com"),
"k5=v", base::Time::Now(),
base::nullopt /* server_time */);
- static_cast<content::WebContentsObserver*>(content_settings)
- ->OnCookiesAccessed(web_contents()->GetMainFrame(),
- {content::CookieAccessDetails::Type::kRead,
- GURL("https://www.google.com"),
- GURL("https://www.google.com"),
- {*cookie5},
- blocked_by_policy});
+ GetHandle()->OnCookiesAccessed(web_contents()->GetMainFrame(),
+ {content::CookieAccessDetails::Type::kRead,
+ GURL("https://www.google.com"),
+ GURL("https://www.google.com"),
+ {*cookie5},
+ blocked_by_policy});
const auto& objects = content_settings->allowed_local_shared_objects();
EXPECT_EQ(5u, objects.GetObjectCount());
diff --git a/chromium/components/content_settings/browser/test_tab_specific_content_settings_delegate.cc b/chromium/components/content_settings/browser/test_tab_specific_content_settings_delegate.cc
new file mode 100644
index 00000000000..bfe9e77af54
--- /dev/null
+++ b/chromium/components/content_settings/browser/test_tab_specific_content_settings_delegate.cc
@@ -0,0 +1,63 @@
+// Copyright 2020 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/test_tab_specific_content_settings_delegate.h"
+
+namespace content_settings {
+
+TestTabSpecificContentSettingsDelegate::TestTabSpecificContentSettingsDelegate(
+ PrefService* prefs,
+ HostContentSettingsMap* settings_map)
+ : prefs_(prefs), settings_map_(settings_map) {}
+
+TestTabSpecificContentSettingsDelegate::
+ ~TestTabSpecificContentSettingsDelegate() = default;
+
+void TestTabSpecificContentSettingsDelegate::UpdateLocationBar() {}
+
+void TestTabSpecificContentSettingsDelegate::SetContentSettingRules(
+ content::RenderProcessHost* process,
+ const RendererContentSettingRules& rules) {}
+
+PrefService* TestTabSpecificContentSettingsDelegate::GetPrefs() {
+ return prefs_;
+}
+
+HostContentSettingsMap*
+TestTabSpecificContentSettingsDelegate::GetSettingsMap() {
+ return settings_map_.get();
+}
+
+ContentSetting TestTabSpecificContentSettingsDelegate::GetEmbargoSetting(
+ const GURL& request_origin,
+ ContentSettingsType permission) {
+ return ContentSetting::CONTENT_SETTING_ASK;
+}
+
+std::vector<storage::FileSystemType>
+TestTabSpecificContentSettingsDelegate::GetAdditionalFileSystemTypes() {
+ return {};
+}
+
+browsing_data::CookieHelper::IsDeletionDisabledCallback
+TestTabSpecificContentSettingsDelegate::GetIsDeletionDisabledCallback() {
+ return base::NullCallback();
+}
+
+bool TestTabSpecificContentSettingsDelegate::IsMicrophoneCameraStateChanged(
+ TabSpecificContentSettings::MicrophoneCameraState microphone_camera_state,
+ const std::string& media_stream_selected_audio_device,
+ const std::string& media_stream_selected_video_device) {
+ return false;
+}
+
+TabSpecificContentSettings::MicrophoneCameraState
+TestTabSpecificContentSettingsDelegate::GetMicrophoneCameraState() {
+ return TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED;
+}
+
+void TestTabSpecificContentSettingsDelegate::OnContentBlocked(
+ ContentSettingsType type) {}
+
+} // namespace content_settings
diff --git a/chromium/components/content_settings/browser/test_tab_specific_content_settings_delegate.h b/chromium/components/content_settings/browser/test_tab_specific_content_settings_delegate.h
new file mode 100644
index 00000000000..9fde1406745
--- /dev/null
+++ b/chromium/components/content_settings/browser/test_tab_specific_content_settings_delegate.h
@@ -0,0 +1,47 @@
+// Copyright 2020 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.
+
+#ifndef COMPONENTS_CONTENT_SETTINGS_BROWSER_TEST_TAB_SPECIFIC_CONTENT_SETTINGS_DELEGATE_H_
+#define COMPONENTS_CONTENT_SETTINGS_BROWSER_TEST_TAB_SPECIFIC_CONTENT_SETTINGS_DELEGATE_H_
+
+#include "base/memory/scoped_refptr.h"
+#include "components/content_settings/browser/tab_specific_content_settings.h"
+
+namespace content_settings {
+
+class TestTabSpecificContentSettingsDelegate
+ : public TabSpecificContentSettings::Delegate {
+ public:
+ TestTabSpecificContentSettingsDelegate(PrefService* prefs,
+ HostContentSettingsMap* settings_map);
+ ~TestTabSpecificContentSettingsDelegate() override;
+
+ // TabSpecificContentSettings::Delegate:
+ void UpdateLocationBar() override;
+ void SetContentSettingRules(
+ content::RenderProcessHost* process,
+ const RendererContentSettingRules& rules) override;
+ PrefService* GetPrefs() override;
+ HostContentSettingsMap* GetSettingsMap() override;
+ ContentSetting GetEmbargoSetting(const GURL& request_origin,
+ ContentSettingsType permission) override;
+ std::vector<storage::FileSystemType> GetAdditionalFileSystemTypes() override;
+ browsing_data::CookieHelper::IsDeletionDisabledCallback
+ GetIsDeletionDisabledCallback() override;
+ bool IsMicrophoneCameraStateChanged(
+ TabSpecificContentSettings::MicrophoneCameraState microphone_camera_state,
+ const std::string& media_stream_selected_audio_device,
+ const std::string& media_stream_selected_video_device) override;
+ TabSpecificContentSettings::MicrophoneCameraState GetMicrophoneCameraState()
+ override;
+ void OnContentBlocked(ContentSettingsType type) override;
+
+ private:
+ PrefService* prefs_;
+ scoped_refptr<HostContentSettingsMap> settings_map_;
+};
+
+} // namespace content_settings
+
+#endif // COMPONENTS_CONTENT_SETTINGS_BROWSER_TEST_TAB_SPECIFIC_CONTENT_SETTINGS_DELEGATE_H_
diff --git a/chromium/components/content_settings/browser/ui/BUILD.gn b/chromium/components/content_settings/browser/ui/BUILD.gn
new file mode 100644
index 00000000000..0f3e91d4da0
--- /dev/null
+++ b/chromium/components/content_settings/browser/ui/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright 2020 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.
+
+source_set("ui") {
+ sources = [
+ "cookie_controls_controller.cc",
+ "cookie_controls_controller.h",
+ "cookie_controls_view.h",
+ ]
+
+ deps = [
+ "//base",
+ "//components/browsing_data/content",
+ "//components/content_settings/browser",
+ "//components/content_settings/core/browser",
+ "//components/prefs",
+ "//content/public/browser",
+ "//content/public/common",
+ ]
+}
diff --git a/chromium/components/content_settings/browser/ui/cookie_controls_controller.cc b/chromium/components/content_settings/browser/ui/cookie_controls_controller.cc
new file mode 100644
index 00000000000..ef908305ac0
--- /dev/null
+++ b/chromium/components/content_settings/browser/ui/cookie_controls_controller.cc
@@ -0,0 +1,161 @@
+// Copyright 2019 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/ui/cookie_controls_controller.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/metrics/user_metrics.h"
+#include "base/metrics/user_metrics_action.h"
+#include "components/browsing_data/content/local_shared_objects_container.h"
+#include "components/content_settings/browser/tab_specific_content_settings.h"
+#include "components/content_settings/browser/ui/cookie_controls_view.h"
+#include "components/content_settings/core/browser/content_settings_utils.h"
+#include "components/content_settings/core/browser/cookie_settings.h"
+#include "components/content_settings/core/common/content_settings.h"
+#include "components/content_settings/core/common/cookie_controls_enforcement.h"
+#include "components/content_settings/core/common/cookie_controls_status.h"
+#include "components/content_settings/core/common/pref_names.h"
+#include "components/prefs/pref_service.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/reload_type.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/url_constants.h"
+
+using base::UserMetricsAction;
+
+namespace content_settings {
+
+CookieControlsController::CookieControlsController(
+ scoped_refptr<CookieSettings> cookie_settings,
+ scoped_refptr<CookieSettings> original_cookie_settings)
+ : cookie_settings_(cookie_settings),
+ original_cookie_settings_(original_cookie_settings) {
+ cookie_observer_.Add(cookie_settings_.get());
+}
+
+CookieControlsController::~CookieControlsController() = default;
+
+void CookieControlsController::OnUiClosing() {
+ auto* web_contents = GetWebContents();
+ if (should_reload_ && web_contents && !web_contents->IsBeingDestroyed())
+ web_contents->GetController().Reload(content::ReloadType::NORMAL, true);
+ should_reload_ = false;
+}
+
+void CookieControlsController::Update(content::WebContents* web_contents) {
+ DCHECK(web_contents);
+ if (!tab_observer_ || GetWebContents() != web_contents)
+ tab_observer_ = std::make_unique<TabObserver>(this, web_contents);
+ auto status = GetStatus(web_contents);
+ int blocked_count = GetBlockedCookieCount();
+ for (auto& observer : observers_)
+ observer.OnStatusChanged(status.first, status.second, blocked_count);
+}
+
+std::pair<CookieControlsStatus, CookieControlsEnforcement>
+CookieControlsController::GetStatus(content::WebContents* web_contents) {
+ if (!cookie_settings_->IsCookieControlsEnabled()) {
+ return {CookieControlsStatus::kDisabled,
+ CookieControlsEnforcement::kNoEnforcement};
+ }
+ const GURL& url = web_contents->GetURL();
+ if (url.SchemeIs(content::kChromeUIScheme) ||
+ url.SchemeIs(kExtensionScheme)) {
+ return {CookieControlsStatus::kDisabled,
+ CookieControlsEnforcement::kNoEnforcement};
+ }
+
+ SettingSource source;
+ bool is_allowed = cookie_settings_->IsThirdPartyAccessAllowed(
+ web_contents->GetURL(), &source);
+
+ CookieControlsStatus status = is_allowed
+ ? CookieControlsStatus::kDisabledForSite
+ : CookieControlsStatus::kEnabled;
+ CookieControlsEnforcement enforcement;
+ if (source == SETTING_SOURCE_POLICY) {
+ enforcement = CookieControlsEnforcement::kEnforcedByPolicy;
+ } else if (is_allowed && original_cookie_settings_ &&
+ original_cookie_settings_->ShouldBlockThirdPartyCookies() &&
+ original_cookie_settings_->IsThirdPartyAccessAllowed(
+ web_contents->GetURL(), nullptr /* source */)) {
+ // TODO(crbug.com/1015767): Rules from regular mode can't be temporarily
+ // overridden in incognito.
+ enforcement = CookieControlsEnforcement::kEnforcedByCookieSetting;
+ } else {
+ enforcement = CookieControlsEnforcement::kNoEnforcement;
+ }
+ return {status, enforcement};
+}
+
+void CookieControlsController::OnCookieBlockingEnabledForSite(
+ bool block_third_party_cookies) {
+ if (block_third_party_cookies) {
+ base::RecordAction(UserMetricsAction("CookieControls.Bubble.TurnOn"));
+ should_reload_ = false;
+ cookie_settings_->ResetThirdPartyCookieSetting(GetWebContents()->GetURL());
+ } else {
+ base::RecordAction(UserMetricsAction("CookieControls.Bubble.TurnOff"));
+ should_reload_ = true;
+ cookie_settings_->SetThirdPartyCookieSetting(
+ GetWebContents()->GetURL(), ContentSetting::CONTENT_SETTING_ALLOW);
+ }
+}
+
+int CookieControlsController::GetBlockedCookieCount() {
+ auto* tscs =
+ content_settings::TabSpecificContentSettings::GetForCurrentDocument(
+ tab_observer_->web_contents()->GetMainFrame());
+ if (tscs) {
+ return tscs->blocked_local_shared_objects().GetObjectCount();
+ } else {
+ return 0;
+ }
+}
+
+void CookieControlsController::PresentBlockedCookieCounter() {
+ int blocked_cookies = GetBlockedCookieCount();
+ for (auto& observer : observers_)
+ observer.OnBlockedCookiesCountChanged(blocked_cookies);
+}
+
+void CookieControlsController::OnThirdPartyCookieBlockingChanged(
+ bool block_third_party_cookies) {
+ if (GetWebContents())
+ Update(GetWebContents());
+}
+
+void CookieControlsController::OnCookieSettingChanged() {
+ if (GetWebContents())
+ Update(GetWebContents());
+}
+
+content::WebContents* CookieControlsController::GetWebContents() {
+ if (!tab_observer_)
+ return nullptr;
+ return tab_observer_->web_contents();
+}
+
+void CookieControlsController::AddObserver(CookieControlsView* obs) {
+ observers_.AddObserver(obs);
+}
+
+void CookieControlsController::RemoveObserver(CookieControlsView* obs) {
+ observers_.RemoveObserver(obs);
+}
+
+CookieControlsController::TabObserver::TabObserver(
+ CookieControlsController* cookie_controls,
+ content::WebContents* web_contents)
+ : content_settings::TabSpecificContentSettings::SiteDataObserver(
+ web_contents),
+ cookie_controls_(cookie_controls) {}
+
+void CookieControlsController::TabObserver::OnSiteDataAccessed() {
+ cookie_controls_->PresentBlockedCookieCounter();
+}
+
+} // namespace content_settings
diff --git a/chromium/components/content_settings/browser/ui/cookie_controls_controller.h b/chromium/components/content_settings/browser/ui/cookie_controls_controller.h
new file mode 100644
index 00000000000..f7aeb504d6d
--- /dev/null
+++ b/chromium/components/content_settings/browser/ui/cookie_controls_controller.h
@@ -0,0 +1,106 @@
+// Copyright 2019 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.
+
+#ifndef COMPONENTS_CONTENT_SETTINGS_BROWSER_UI_COOKIE_CONTROLS_CONTROLLER_H_
+#define COMPONENTS_CONTENT_SETTINGS_BROWSER_UI_COOKIE_CONTROLS_CONTROLLER_H_
+
+#include "base/memory/scoped_refptr.h"
+#include "base/observer_list.h"
+#include "components/content_settings/browser/tab_specific_content_settings.h"
+#include "components/content_settings/core/browser/cookie_settings.h"
+#include "components/content_settings/core/common/cookie_controls_enforcement.h"
+#include "components/content_settings/core/common/cookie_controls_status.h"
+#include "components/prefs/pref_change_registrar.h"
+#include "content/public/browser/web_contents.h"
+
+namespace content {
+class WebContents;
+} // namespace content
+
+namespace content_settings {
+
+class CookieSettings;
+class CookieControlsView;
+
+// Handles the tab specific state for cookie controls.
+class CookieControlsController : content_settings::CookieSettings::Observer {
+ public:
+ CookieControlsController(
+ scoped_refptr<content_settings::CookieSettings> cookie_settings,
+ scoped_refptr<content_settings::CookieSettings> original_cookie_settings);
+ CookieControlsController(const CookieControlsController& other) = delete;
+ CookieControlsController& operator=(const CookieControlsController& other) =
+ delete;
+ ~CookieControlsController() override;
+
+ // Called when the web_contents has changed.
+ void Update(content::WebContents* web_contents);
+
+ // Called when CookieControlsView is closing.
+ void OnUiClosing();
+
+ // Called when the user clicks on the button to enable/disable cookie
+ // blocking.
+ void OnCookieBlockingEnabledForSite(bool block_third_party_cookies);
+
+ void AddObserver(CookieControlsView* obs);
+ void RemoveObserver(CookieControlsView* obs);
+
+ private:
+ // The observed WebContents changes during the lifetime of the
+ // CookieControlsController. SiteDataObserver can't change the observed
+ // object, so we need an inner class that can be recreated when necessary.
+ // TODO(dullweber): Make it possible to change the observed class and maybe
+ // convert SiteDataObserver to a pure virtual interface.
+ class TabObserver
+ : public content_settings::TabSpecificContentSettings::SiteDataObserver {
+ public:
+ TabObserver(CookieControlsController* cookie_controls,
+ content::WebContents* web_contents);
+
+ // TabSpecificContentSettings::SiteDataObserver:
+ void OnSiteDataAccessed() override;
+
+ private:
+ CookieControlsController* cookie_controls_;
+
+ DISALLOW_COPY_AND_ASSIGN(TabObserver);
+ };
+
+ void OnThirdPartyCookieBlockingChanged(
+ bool block_third_party_cookies) override;
+ void OnCookieSettingChanged() override;
+
+ // Determine the CookieControlsStatus based on |web_contents|.
+ std::pair<CookieControlsStatus, CookieControlsEnforcement> GetStatus(
+ content::WebContents* web_contents);
+
+ // Updates the blocked cookie count of |icon_|.
+ void PresentBlockedCookieCounter();
+
+ // Returns the number of blocked cookies.
+ int GetBlockedCookieCount();
+
+ content::WebContents* GetWebContents();
+
+ std::unique_ptr<TabObserver> tab_observer_;
+ scoped_refptr<content_settings::CookieSettings> cookie_settings_;
+ // Cookie_settings for the original profile associated with
+ // |cookie_settings_|, if there is one. For example, in Chrome, this
+ // corresponds to the regular profile when |cookie_settings_| is incognito.
+ // This may be null.
+ scoped_refptr<content_settings::CookieSettings> original_cookie_settings_;
+
+ ScopedObserver<content_settings::CookieSettings,
+ content_settings::CookieSettings::Observer>
+ cookie_observer_{this};
+
+ bool should_reload_ = false;
+
+ base::ObserverList<CookieControlsView> observers_;
+};
+
+} // namespace content_settings
+
+#endif // COMPONENTS_CONTENT_SETTINGS_BROWSER_UI_COOKIE_CONTROLS_CONTROLLER_H_
diff --git a/chromium/components/content_settings/browser/ui/cookie_controls_view.h b/chromium/components/content_settings/browser/ui/cookie_controls_view.h
new file mode 100644
index 00000000000..f833db0b6d7
--- /dev/null
+++ b/chromium/components/content_settings/browser/ui/cookie_controls_view.h
@@ -0,0 +1,25 @@
+// Copyright 2019 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.
+
+#ifndef COMPONENTS_CONTENT_SETTINGS_BROWSER_UI_COOKIE_CONTROLS_VIEW_H_
+#define COMPONENTS_CONTENT_SETTINGS_BROWSER_UI_COOKIE_CONTROLS_VIEW_H_
+
+#include "base/observer_list_types.h"
+#include "components/content_settings/core/common/cookie_controls_enforcement.h"
+#include "components/content_settings/core/common/cookie_controls_status.h"
+
+namespace content_settings {
+
+// Interface for the CookieControls UI.
+class CookieControlsView : public base::CheckedObserver {
+ public:
+ virtual void OnStatusChanged(CookieControlsStatus status,
+ CookieControlsEnforcement enforcement,
+ int blocked_cookies) = 0;
+ virtual void OnBlockedCookiesCountChanged(int blocked_cookies) = 0;
+};
+
+} // namespace content_settings
+
+#endif // COMPONENTS_CONTENT_SETTINGS_BROWSER_UI_COOKIE_CONTROLS_VIEW_H_