blob: 721a608901ff6f90e3aba8e43a27c1ed02dc372f [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_ORIGIN_TRIALS_BROWSER_ORIGIN_TRIALS_H_
#define COMPONENTS_ORIGIN_TRIALS_BROWSER_ORIGIN_TRIALS_H_
#include <map>
#include <memory>
#include <optional>
#include <string>
#include "base/containers/flat_set.h"
#include "base/containers/span.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/origin_trials/common/origin_trials_persistence_provider.h"
#include "content/public/browser/origin_trial_status_change_details.h"
#include "content/public/browser/origin_trials_controller_delegate.h"
#include "third_party/blink/public/common/origin_trials/trial_token_validator.h"
#include "third_party/blink/public/mojom/origin_trials/origin_trial_feature.mojom-shared.h"
using content::OriginTrialStatusChangeDetails;
namespace url {
class Origin;
}
namespace origin_trials {
// Implementation of persistent origin trials for the browser process.
//
// This class manages persistent origin trials, allowing the browser to check
// if a given trial is enabled or not.
//
// Persisting the enabled trials is handled by the `persistence_provider` passed
// in through the constructor.
class OriginTrials : public KeyedService,
public content::OriginTrialsControllerDelegate {
public:
using ObserverMap = std::map<
std::string,
base::ObserverList<content::OriginTrialsControllerDelegate::Observer>>;
OriginTrials(
std::unique_ptr<OriginTrialsPersistenceProvider> persistence_provider,
std::unique_ptr<blink::TrialTokenValidator> token_validator);
OriginTrials(const OriginTrials&) = delete;
OriginTrials(const OriginTrials&&) = delete;
OriginTrials& operator=(const OriginTrials&) = delete;
OriginTrials& operator=(const OriginTrials&&) = delete;
~OriginTrials() override;
// content::OriginTrialsControllerDelegate
void AddObserver(Observer* observer) override;
void RemoveObserver(Observer* observer) override;
void PersistTrialsFromTokens(
const url::Origin& origin,
const url::Origin& partition_origin,
const base::span<const std::string> header_tokens,
const base::Time current_time,
std::optional<ukm::SourceId> source_id) override;
void PersistAdditionalTrialsFromTokens(
const url::Origin& origin,
const url::Origin& partition_origin,
base::span<const url::Origin> script_origins,
const base::span<const std::string> header_tokens,
const base::Time current_time,
std::optional<ukm::SourceId> source_id) override;
bool IsFeaturePersistedForOrigin(const url::Origin& origin,
const url::Origin& partition_origin,
blink::mojom::OriginTrialFeature feature,
const base::Time current_time) override;
base::flat_set<std::string> GetPersistedTrialsForOrigin(
const url::Origin& origin,
const url::Origin& partition_origin,
base::Time current_time) override;
void ClearPersistedTokens() override;
private:
friend class OriginTrialsTest;
std::unique_ptr<OriginTrialsPersistenceProvider> persistence_provider_;
std::unique_ptr<blink::TrialTokenValidator> trial_token_validator_;
ObserverMap observer_map_;
void NotifyStatusChange(const std::string& trial,
const OriginTrialStatusChangeDetails& details);
void NotifyPersistedTokensCleared();
// Returns true if `origin` can use a token made for `token_origin`. For
// `origin` to use `token_origin`'s token, at least one of the following must
// be true:
// - `origin` equals `token_origin`
// - `match_subdomains` is true and `origin` is a subdomain of `token_origin`
// NOTE: This is meant to mirror the logic used in
// `blink::TrialToken::ValidateOrigin()`.
// TODO(crbug.com/40189223): Find a way to share/reuse the logic in
// `blink::TrialToken`. Otherwise, the logic could change in one place and not
// the other.
bool MatchesTokenOrigin(const url::Origin& token_origin,
bool match_subdomains,
const url::Origin& origin) const;
void PersistTokensInternal(const url::Origin& origin,
const url::Origin& partition_origin,
base::span<const url::Origin> script_origins,
const base::span<const std::string> header_tokens,
const base::Time current_time,
std::optional<ukm::SourceId> source_id,
bool append_only);
// Helper to return the still-valid persisted trials, with an optional
// `trial_feature_match` which can be passed to ensure we only validate
// and return the trial if it enables the desired trial feature.
// If no `trial_feature_match` is provided, it will return all persisted
// trials that are still valid.
base::flat_set<std::string> GetPersistedTrialsForOriginWithMatch(
const url::Origin& origin,
const url::Origin& partition_origin,
const base::Time current_time,
const std::optional<blink::mojom::OriginTrialFeature> trial_feature_match)
const;
// Update the stored tokens for `token_origin` with the `new_tokens`,
// partitioned by `partition_site`.
// If `append_only` is set to true, existing tokens for `token_origin` that
// aren't found in `new_tokens` will be cleared, unless they match subdomains,
// in which case they will only be cleared if `document_origin` equals
// `token_origin`.
void UpdatePersistedTokenSet(const url::Origin& document_origin,
const url::Origin& token_origin,
base::span<const blink::TrialToken> new_tokens,
const std::string& partition_site,
std::optional<ukm::SourceId> source_id,
bool append_only);
// Get the 'site' used as the partitioning key for trial tokens.
//
// The key is the eTLD+1 of the `origin`, taking private registries such as
// blogspot.com into account.
static std::string GetTokenPartitionSite(const url::Origin& origin);
};
} // namespace origin_trials
#endif // COMPONENTS_ORIGIN_TRIALS_BROWSER_ORIGIN_TRIALS_H_