blob: 42e16bc5849a27967270706249cbcf58e7b35604 [file] [log] [blame]
// Copyright 2017 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 <cmath>
#include <functional>
#include <string>
#include "components/client_hints/browser/client_hints.h"
#include "base/metrics/histogram_macros.h"
#include "base/time/time.h"
#include "components/client_hints/common/client_hints.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings_utils.h"
#include "components/policy/core/common/policy_pref_names.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/content_features.h"
#include "third_party/blink/public/common/loader/network_utils.h"
namespace client_hints {
ClientHints::ClientHints(
content::BrowserContext* context,
network::NetworkQualityTracker* network_quality_tracker,
HostContentSettingsMap* settings_map,
const blink::UserAgentMetadata& user_agent_metadata,
PrefService* pref_service)
: context_(context),
network_quality_tracker_(network_quality_tracker),
settings_map_(settings_map),
user_agent_metadata_(user_agent_metadata),
pref_service_(pref_service) {
DCHECK(context_);
DCHECK(network_quality_tracker_);
DCHECK(settings_map_);
}
ClientHints::~ClientHints() = default;
network::NetworkQualityTracker* ClientHints::GetNetworkQualityTracker() {
return network_quality_tracker_;
}
void ClientHints::GetAllowedClientHintsFromSource(
const GURL& url,
blink::WebEnabledClientHints* client_hints) {
ContentSettingsForOneType client_hints_rules;
settings_map_->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
std::string(), &client_hints_rules);
client_hints::GetAllowedClientHintsFromSource(url, client_hints_rules,
client_hints);
}
bool ClientHints::IsJavaScriptAllowed(const GURL& url) {
return settings_map_->GetContentSetting(
url, url, ContentSettingsType::JAVASCRIPT, std::string()) !=
CONTENT_SETTING_BLOCK;
}
bool ClientHints::UserAgentClientHintEnabled() {
// TODO(crbug.com/1097591): This extra path check is only here because the
// pref is not being registered in //weblayer.
bool pref_enabled = true;
if (pref_service_->HasPrefPath(
policy::policy_prefs::kUserAgentClientHintsEnabled)) {
pref_enabled = pref_service_->GetBoolean(
policy::policy_prefs::kUserAgentClientHintsEnabled);
}
return pref_enabled &&
base::FeatureList::IsEnabled(features::kUserAgentClientHint);
}
blink::UserAgentMetadata ClientHints::GetUserAgentMetadata() {
return user_agent_metadata_;
}
void ClientHints::PersistClientHints(
const url::Origin& primary_origin,
const std::vector<network::mojom::WebClientHintsType>& client_hints,
base::TimeDelta expiration_duration) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
const GURL primary_url = primary_origin.GetURL();
// TODO(tbansal): crbug.com/735518. Consider killing the renderer that sent
// the malformed IPC.
if (!primary_url.is_valid() ||
!blink::network_utils::IsOriginSecure(primary_url))
return;
if (!IsJavaScriptAllowed(primary_url))
return;
DCHECK_LE(
client_hints.size(),
static_cast<size_t>(network::mojom::WebClientHintsType::kMaxValue) + 1);
if (client_hints.size() >
(static_cast<size_t>(network::mojom::WebClientHintsType::kMaxValue) +
1)) {
// Return early if the list does not have the right number of values.
// Persisting wrong number of values to the disk may cause errors when
// reading them back in the future.
return;
}
if (expiration_duration <= base::TimeDelta::FromSeconds(0))
return;
base::Value::ListStorage expiration_times_list;
expiration_times_list.reserve(client_hints.size());
// Use wall clock since the expiration time would be persisted across embedder
// restarts.
double expiration_time =
(base::Time::Now() + expiration_duration).ToDoubleT();
for (const auto& entry : client_hints)
expiration_times_list.push_back(base::Value(static_cast<int>(entry)));
auto expiration_times_dictionary = std::make_unique<base::DictionaryValue>();
expiration_times_dictionary->SetKey(
"client_hints", base::Value(std::move(expiration_times_list)));
expiration_times_dictionary->SetDoubleKey("expiration_time", expiration_time);
// TODO(tbansal): crbug.com/735518. Disable updates to client hints settings
// when cookies are disabled for |primary_origin|.
settings_map_->SetWebsiteSettingDefaultScope(
primary_url, GURL(), ContentSettingsType::CLIENT_HINTS, std::string(),
std::move(expiration_times_dictionary),
{base::Time(), content_settings::SessionModel::UserSession});
UMA_HISTOGRAM_EXACT_LINEAR("ClientHints.UpdateEventCount", 1, 2);
UMA_HISTOGRAM_CUSTOM_TIMES(
"ClientHints.PersistDuration", expiration_duration,
base::TimeDelta::FromSeconds(1),
// TODO(crbug.com/949034): Rename and fix this histogram to have some
// intended max value. We throw away the 32 most-significant bits of the
// 64-bit time delta in milliseconds. Before it happened silently in
// histogram.cc, now it is explicit here. The previous value of 365 days
// effectively turns into roughly 17 days when getting cast to int.
base::TimeDelta::FromMilliseconds(
static_cast<int>(base::TimeDelta::FromDays(365).InMilliseconds())),
100);
UMA_HISTOGRAM_COUNTS_100("ClientHints.UpdateSize", client_hints.size());
}
} // namespace client_hints