blob: 3e300afdbadd7a7649cc34a3e0c27e8700e2b42c [file] [log] [blame]
// Copyright 2015 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 "content/public/browser/site_isolation_policy.h"
#include <algorithm>
#include <iterator>
#include <string>
#include <utility>
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/macros.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/strings/string_split.h"
#include "base/timer/timer.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/resource_type.h"
#include "services/network/public/mojom/network_service.mojom.h"
#include "url/gurl.h"
namespace content {
namespace {
bool IsSiteIsolationDisabled() {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableSiteIsolation)) {
return true;
}
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableSiteIsolationForPolicy)) {
return true;
}
return GetContentClient() &&
GetContentClient()->browser()->ShouldDisableSiteIsolation();
}
} // namespace
// static
bool SiteIsolationPolicy::UseDedicatedProcessesForAllSites() {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSitePerProcess)) {
return true;
}
if (IsSiteIsolationDisabled())
return false;
// The switches above needs to be checked first, because if the
// ContentBrowserClient consults a base::Feature, then it will activate the
// field trial and assigns the client either to a control or an experiment
// group - such assignment should be final.
return GetContentClient() &&
GetContentClient()->browser()->ShouldEnableStrictSiteIsolation();
}
// static
void SiteIsolationPolicy::PopulateURLLoaderFactoryParamsPtrForCORB(
network::mojom::URLLoaderFactoryParams* params) {
// --disable-web-security also disables Cross-Origin Read Blocking (CORB).
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableWebSecurity)) {
params->is_corb_enabled = false;
return;
}
params->is_corb_enabled = true;
params->corb_detachable_resource_type = RESOURCE_TYPE_PREFETCH;
params->corb_excluded_resource_type = RESOURCE_TYPE_PLUGIN_RESOURCE;
}
// static
bool SiteIsolationPolicy::AreIsolatedOriginsEnabled() {
// NOTE: Because it is possible for --isolate-origins to be isolating origins
// at a finer-than-site granularity, we do not suppress --isolate-origins when
// --site-per-process is also enabled.
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kIsolateOrigins)) {
return true;
}
if (IsSiteIsolationDisabled())
return false;
// The feature needs to be checked last, because checking the feature
// activates the field trial and assigns the client either to a control or an
// experiment group - such assignment should be final.
return base::FeatureList::IsEnabled(features::kIsolateOrigins);
}
// static
bool SiteIsolationPolicy::IsErrorPageIsolationEnabled(bool in_main_frame) {
return GetContentClient()->browser()->ShouldIsolateErrorPage(in_main_frame);
}
// static
bool SiteIsolationPolicy::ShouldPdfCompositorBeEnabledForOopifs() {
// TODO(weili): We only create pdf compositor client and use pdf compositor
// service when site-per-process or isolate-origins flag/feature is enabled,
// or top-document-isolation feature is enabled. This may not cover all cases
// where OOPIF is used such as isolate-extensions, but should be good for
// feature testing purpose. Eventually, we will remove this check and use pdf
// compositor service by default for printing.
return AreIsolatedOriginsEnabled() || UseDedicatedProcessesForAllSites();
}
// static
std::vector<url::Origin>
SiteIsolationPolicy::GetIsolatedOriginsFromEnvironment() {
std::string cmdline_arg =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kIsolateOrigins);
std::vector<url::Origin> origins;
if (!cmdline_arg.empty()) {
origins = ParseIsolatedOrigins(cmdline_arg);
UMA_HISTOGRAM_COUNTS_1000("SiteIsolation.IsolateOrigins.Size",
origins.size());
}
// --isolate-origins (both command-line flag and enterprise policy) trumps
// the opt-out flag.
if (IsSiteIsolationDisabled())
return origins;
// The feature needs to be checked last, because checking the feature
// activates the field trial and assigns the client either to a control or an
// experiment group - such assignment should be final.
if (base::FeatureList::IsEnabled(features::kIsolateOrigins)) {
std::string field_trial_arg = base::GetFieldTrialParamValueByFeature(
features::kIsolateOrigins,
features::kIsolateOriginsFieldTrialParamName);
std::vector<url::Origin> field_trial_origins =
ParseIsolatedOrigins(field_trial_arg);
origins.reserve(origins.size() + field_trial_origins.size());
std::move(field_trial_origins.begin(), field_trial_origins.end(),
std::back_inserter(origins));
}
return origins;
}
// static
std::vector<url::Origin> SiteIsolationPolicy::GetIsolatedOrigins() {
std::vector<url::Origin> from_environment =
GetIsolatedOriginsFromEnvironment();
std::vector<url::Origin> from_embedder =
GetContentClient()->browser()->GetOriginsRequiringDedicatedProcess();
std::vector<url::Origin> result = std::move(from_environment);
result.reserve(result.size() + from_embedder.size());
std::move(from_embedder.begin(), from_embedder.end(),
std::back_inserter(result));
return result;
}
// static
std::vector<url::Origin> SiteIsolationPolicy::ParseIsolatedOrigins(
base::StringPiece arg) {
std::vector<base::StringPiece> origin_strings = base::SplitStringPiece(
arg, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
std::vector<url::Origin> origins;
origins.reserve(origin_strings.size());
for (const base::StringPiece& origin_string : origin_strings) {
url::Origin origin = url::Origin::Create(GURL(origin_string));
if (!origin.opaque())
origins.push_back(origin);
}
return origins;
}
// static
void SiteIsolationPolicy::StartRecordingSiteIsolationFlagUsage() {
RecordSiteIsolationFlagUsage();
// Record the flag usage metrics every 24 hours. Even though site isolation
// flags can't change dynamically at runtime, collecting these stats daily
// helps determine the overall population of users who run with a given flag
// on any given day.
static base::NoDestructor<base::RepeatingTimer> update_stats_timer;
update_stats_timer->Start(
FROM_HERE, base::TimeDelta::FromHours(24),
base::BindRepeating(&SiteIsolationPolicy::RecordSiteIsolationFlagUsage));
}
// static
void SiteIsolationPolicy::RecordSiteIsolationFlagUsage() {
// For --site-per-process and --isolate-origins, include flags specified on
// command-line, in chrome://flags, and via enterprise policy (i.e., include
// switches::kSitePerProcess and switches::kIsolateOrigins). Exclude these
// modes being set through field trials (i.e., exclude
// features::kSitePerProcess and features::IsolateOrigins).
UMA_HISTOGRAM_BOOLEAN("SiteIsolation.Flags.IsolateOrigins",
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kIsolateOrigins));
UMA_HISTOGRAM_BOOLEAN("SiteIsolation.Flags.SitePerProcess",
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSitePerProcess));
}
} // namespace content