1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
|
// Copyright 2019 The Chromium Authors
// 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/content_settings_manager_impl.h"
#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
#include "base/task/thread_pool.h"
#include "components/content_settings/browser/page_specific_content_settings.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/content_settings/core/common/cookie_settings_base.h"
#include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/content_features.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "net/base/features.h"
#include "net/cookies/cookie_util.h"
#include "net/cookies/site_for_cookies.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
using content_settings::PageSpecificContentSettings;
namespace content_settings {
namespace {
using StorageType = mojom::ContentSettingsManager::StorageType;
void OnStorageAccessed(int process_id,
int frame_id,
const GURL& origin_url,
const GURL& top_origin_url,
bool blocked_by_policy,
page_load_metrics::StorageType storage_type) {
content::RenderFrameHost* render_frame_host =
content::RenderFrameHost::FromID(process_id, frame_id);
content::WebContents* web_contents =
content::WebContents::FromRenderFrameHost(render_frame_host);
if (!web_contents)
return;
page_load_metrics::MetricsWebContentsObserver* metrics_observer =
page_load_metrics::MetricsWebContentsObserver::FromWebContents(
web_contents);
if (metrics_observer) {
metrics_observer->OnStorageAccessed(render_frame_host, origin_url,
top_origin_url, blocked_by_policy,
storage_type);
}
}
void NotifyStorageAccess(int render_process_id,
int32_t render_frame_id,
StorageType storage_type,
const url::Origin& top_frame_origin,
bool allowed) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
bool should_notify_pscs = ([storage_type]() {
switch (storage_type) {
case StorageType::DATABASE:
case StorageType::LOCAL_STORAGE:
case StorageType::SESSION_STORAGE:
case StorageType::FILE_SYSTEM:
case StorageType::INDEXED_DB:
case StorageType::CACHE:
return true;
case StorageType::WEB_LOCKS:
// State not persisted, no need to record anything;
return false;
}
})();
auto* rfh =
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
if (!rfh) {
return;
}
auto metrics_type =
([storage_type]() -> absl::optional<page_load_metrics::StorageType> {
switch (storage_type) {
case StorageType::LOCAL_STORAGE:
return page_load_metrics::StorageType::kLocalStorage;
case StorageType::SESSION_STORAGE:
return page_load_metrics::StorageType::kSessionStorage;
case StorageType::FILE_SYSTEM:
return page_load_metrics::StorageType::kFileSystem;
case StorageType::INDEXED_DB:
return page_load_metrics::StorageType::kIndexedDb;
case StorageType::CACHE:
return page_load_metrics::StorageType::kCacheStorage;
case StorageType::DATABASE:
case StorageType::WEB_LOCKS:
return absl::nullopt;
}
})();
if (should_notify_pscs) {
PageSpecificContentSettings::StorageAccessed(
storage_type, render_process_id, render_frame_id, rfh->GetStorageKey(),
!allowed);
}
if (metrics_type) {
OnStorageAccessed(render_process_id, render_frame_id,
rfh->GetLastCommittedURL(), top_frame_origin.GetURL(),
!allowed, metrics_type.value());
}
}
void OnContentBlockedOnUI(int render_process_id,
int32_t render_frame_id,
ContentSettingsType type) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
PageSpecificContentSettings::ContentBlocked(render_process_id,
render_frame_id, type);
}
} // namespace
ContentSettingsManagerImpl::~ContentSettingsManagerImpl() = default;
// static
void ContentSettingsManagerImpl::Create(
content::RenderProcessHost* render_process_host,
mojo::PendingReceiver<content_settings::mojom::ContentSettingsManager>
receiver,
std::unique_ptr<Delegate> delegate) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
base::ThreadPool::CreateSingleThreadTaskRunner(
{base::TaskPriority::USER_BLOCKING})
->PostTask(
FROM_HERE,
base::BindOnce(&ContentSettingsManagerImpl::CreateOnThread,
render_process_host->GetID(), std::move(receiver),
delegate->GetCookieSettings(
render_process_host->GetBrowserContext()),
std::move(delegate)));
}
void ContentSettingsManagerImpl::Clone(
mojo::PendingReceiver<content_settings::mojom::ContentSettingsManager>
receiver) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
mojo::MakeSelfOwnedReceiver(
base::WrapUnique(new ContentSettingsManagerImpl(*this)),
std::move(receiver));
}
void ContentSettingsManagerImpl::AllowStorageAccess(
int32_t render_frame_id,
StorageType storage_type,
const url::Origin& origin,
const net::SiteForCookies& site_for_cookies,
const url::Origin& top_frame_origin,
base::OnceCallback<void(bool)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
GURL url = origin.GetURL();
// TODO(crbug.com/1386190): Consider whether the following check should
// get CookieSettingOverrides from the frame rather than default to none.
CookieSettingsBase::CookieSettingWithMetadata cookie_settings;
bool allowed = cookie_settings_->IsFullCookieAccessAllowed(
url, site_for_cookies, top_frame_origin,
cookie_settings_->SettingOverridesForStorage(), &cookie_settings);
// If storage partitioning is active, third-party partitioned storage is
// allowed by default, and access is only blocked due to general third-party
// cookie blocking (and not due to a user specified pattern) then we'll allow
// storage access.
if (base::FeatureList::IsEnabled(
net::features::kThirdPartyStoragePartitioning) &&
base::FeatureList::IsEnabled(
net::features::kThirdPartyPartitionedStorageAllowedByDefault) &&
!allowed && cookie_settings.BlockedByThirdPartyCookieBlocking()) {
allowed = true;
}
// Allow storage when --test-third-party-cookie-phaseout is used, but ensure
// that only partitioned storage is available. This developer flag is meant to
// simulate Chrome's behavior when 3P cookies are turned down to help
// developers test their site.
if (!allowed && net::cookie_util::IsForceThirdPartyCookieBlockingEnabled()) {
allowed = true;
}
if (delegate_->AllowStorageAccess(render_process_id_, render_frame_id,
storage_type, url, allowed, &callback)) {
DCHECK(!callback);
return;
}
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&NotifyStorageAccess, render_process_id_, render_frame_id,
storage_type, top_frame_origin, allowed));
std::move(callback).Run(allowed);
}
void ContentSettingsManagerImpl::OnContentBlocked(int32_t render_frame_id,
ContentSettingsType type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&OnContentBlockedOnUI, render_process_id_,
render_frame_id, type));
}
ContentSettingsManagerImpl::ContentSettingsManagerImpl(
int render_process_id,
std::unique_ptr<Delegate> delegate,
scoped_refptr<CookieSettings> cookie_settings)
: delegate_(std::move(delegate)),
render_process_id_(render_process_id),
cookie_settings_(cookie_settings) {}
ContentSettingsManagerImpl::ContentSettingsManagerImpl(
const ContentSettingsManagerImpl& other)
: delegate_(other.delegate_->Clone()),
render_process_id_(other.render_process_id_),
cookie_settings_(other.cookie_settings_) {}
// static
void ContentSettingsManagerImpl::CreateOnThread(
int render_process_id,
mojo::PendingReceiver<content_settings::mojom::ContentSettingsManager>
receiver,
scoped_refptr<CookieSettings> cookie_settings,
std::unique_ptr<Delegate> delegate) {
mojo::MakeSelfOwnedReceiver(
base::WrapUnique(new ContentSettingsManagerImpl(
render_process_id, std::move(delegate), cookie_settings)),
std::move(receiver));
}
} // namespace content_settings
|