blob: 0000f73725d41d3eb6be94bed192fe4431878701 [file] [log] [blame]
// 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 <cstddef>
#include <string>
#include "base/unguessable_token.h"
#include "base/values.h"
#include "net/base/features.h"
#include "net/base/network_isolation_key.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "schemeful_site.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
#include "url/origin.h"
#include "url/url_constants.h"
namespace net {
namespace {
std::string GetSiteDebugString(const absl::optional<SchemefulSite>& site) {
return site ? site->GetDebugString() : "null";
}
} // namespace
NetworkIsolationKey::NetworkIsolationKey(const SchemefulSite& top_frame_site,
const SchemefulSite& frame_site,
const base::UnguessableToken* nonce)
: NetworkIsolationKey(SchemefulSite(top_frame_site),
SchemefulSite(frame_site),
nonce) {}
NetworkIsolationKey::NetworkIsolationKey(SchemefulSite&& top_frame_site,
SchemefulSite&& frame_site,
const base::UnguessableToken* nonce)
: top_frame_site_(std::move(top_frame_site)),
frame_site_(IsFrameSiteEnabled()
? absl::make_optional(std::move(frame_site))
: absl::nullopt),
nonce_(nonce ? absl::make_optional(*nonce) : absl::nullopt) {
DCHECK(!nonce || !nonce->is_empty());
}
NetworkIsolationKey::NetworkIsolationKey(const url::Origin& top_frame_origin,
const url::Origin& frame_origin)
: NetworkIsolationKey(SchemefulSite(top_frame_origin),
SchemefulSite(frame_origin)) {}
NetworkIsolationKey::NetworkIsolationKey() = default;
NetworkIsolationKey::NetworkIsolationKey(
const NetworkIsolationKey& network_isolation_key) = default;
NetworkIsolationKey::NetworkIsolationKey(
NetworkIsolationKey&& network_isolation_key) = default;
NetworkIsolationKey::~NetworkIsolationKey() = default;
NetworkIsolationKey& NetworkIsolationKey::operator=(
const NetworkIsolationKey& network_isolation_key) = default;
NetworkIsolationKey& NetworkIsolationKey::operator=(
NetworkIsolationKey&& network_isolation_key) = default;
NetworkIsolationKey NetworkIsolationKey::CreateTransient() {
SchemefulSite site_with_opaque_origin;
return NetworkIsolationKey(site_with_opaque_origin, site_with_opaque_origin);
}
NetworkIsolationKey NetworkIsolationKey::CreateWithNewFrameSite(
const SchemefulSite& new_frame_site) const {
if (!top_frame_site_)
return NetworkIsolationKey();
NetworkIsolationKey key(top_frame_site_.value(), new_frame_site);
key.nonce_ = nonce_;
return key;
}
absl::optional<std::string> NetworkIsolationKey::ToCacheKeyString() const {
if (IsTransient())
return absl::nullopt;
std::string frame_site_str =
" " + (IsFrameSiteEnabled() ? frame_site_->Serialize()
: top_frame_site_->Serialize());
return top_frame_site_->Serialize() + frame_site_str;
}
std::string NetworkIsolationKey::ToDebugString() const {
// The space-separated serialization of |top_frame_site_| and
// |frame_site_|.
std::string return_string = GetSiteDebugString(top_frame_site_);
return_string += " " + GetSiteDebugString(frame_site_);
if (nonce_.has_value()) {
return_string += " (with nonce " + nonce_->ToString() + ")";
}
return return_string;
}
bool NetworkIsolationKey::IsFullyPopulated() const {
return top_frame_site_.has_value() &&
(!IsFrameSiteEnabled() || frame_site_.has_value());
}
bool NetworkIsolationKey::IsTransient() const {
if (!IsFullyPopulated())
return true;
return IsOpaque();
}
bool NetworkIsolationKey::ToValue(base::Value* out_value) const {
if (IsEmpty()) {
*out_value = base::Value(base::Value::Type::LIST);
return true;
}
if (IsTransient())
return false;
// NetworkIsolationKeys with nonces are now always transient, so serializing
// with nonces isn't strictly needed, but it's used for backwards
// compatibility, Origin::Deserialize() is not compatible with
// SerializeWithNonce().
absl::optional<std::string> top_frame_value =
SerializeSiteWithNonce(*top_frame_site_);
if (!top_frame_value)
return false;
base::Value::List list;
list.Append(std::move(top_frame_value).value());
absl::optional<std::string> frame_value =
IsFrameSiteEnabled() ? SerializeSiteWithNonce(*frame_site_)
: absl::nullopt;
if (frame_value.has_value()) {
// If there is a frame value, append it.
list.Append(std::move(frame_value).value());
} else if (IsFrameSiteEnabled()) {
// If there is supposed to be a frame value but there isn't return false.
return false;
}
// List will have size 1 when frame site is disabled.
*out_value = base::Value(std::move(list));
return true;
}
bool NetworkIsolationKey::FromValue(
const base::Value& value,
NetworkIsolationKey* network_isolation_key) {
if (!value.is_list())
return false;
const base::Value::List& list = value.GetList();
if (list.empty()) {
*network_isolation_key = NetworkIsolationKey();
return true;
}
// When frame site is enabled list must be of size 2 and both values must be
// strings.
// When frame site is disabled for double key `list` can be either be of size
// 2 or of size 1. For backwards compatibility, frame site is allowed to be of
// size 2 when frame site is disabled because a previous expirement set frame
// site equal to a copy of top frame site rather than setting it empty.
if (IsFrameSiteEnabled()) {
if (list.size() != 2 || !list[0].is_string() || !list[1].is_string()) {
return false;
}
} else {
if (list.size() < 0 || list.size() > 2 || !list[0].is_string()) {
return false;
}
}
absl::optional<SchemefulSite> top_frame_site =
SchemefulSite::DeserializeWithNonce(list[0].GetString());
// Opaque origins are currently never serialized to disk, but they used to be.
if (!top_frame_site || top_frame_site->opaque())
return false;
if (list.size() == 1) {
// The value of the frame_site parameter doesn't matter because the
// constructor will default it to nullopt.
*network_isolation_key =
NetworkIsolationKey(std::move(*top_frame_site), net::SchemefulSite());
return true;
}
absl::optional<SchemefulSite> frame_site =
SchemefulSite::DeserializeWithNonce(list[1].GetString());
// Opaque origins are currently never serialized to disk, but they used to be.
if (!frame_site || frame_site->opaque())
return false;
*network_isolation_key =
NetworkIsolationKey(std::move(*top_frame_site), std::move(*frame_site));
return true;
}
const absl::optional<SchemefulSite>& NetworkIsolationKey::GetFrameSite() const {
// Frame site will be empty if double-keying is enabled.
CHECK(NetworkIsolationKey::IsFrameSiteEnabled());
return frame_site_;
}
bool NetworkIsolationKey::IsEmpty() const {
return !top_frame_site_.has_value() && !frame_site_.has_value();
}
bool NetworkIsolationKey::IsFrameSiteEnabled() {
return !base::FeatureList::IsEnabled(
net::features::kForceIsolationInfoFrameOriginToTopLevelFrame);
}
bool NetworkIsolationKey::IsOpaque() const {
return top_frame_site_->opaque() ||
(IsFrameSiteEnabled() && frame_site_->opaque()) || nonce_.has_value();
}
absl::optional<std::string> NetworkIsolationKey::SerializeSiteWithNonce(
const SchemefulSite& site) {
return *(const_cast<SchemefulSite&>(site).SerializeWithNonce());
}
} // namespace net