chromium/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_read_context.h.tmpl

{% from 'templates/macros.tmpl' import license, source_files_for_generated_file %}
{{license()}}

{{source_files_for_generated_file(template_file, input_files)}}

#ifndef {{header_guard}}
#define {{header_guard}}

#include "base/containers/flat_map.h"
#include "base/containers/span.h"
#include "base/notreached.h"
#include "third_party/blink/public/common/common_export.h"
#include "third_party/blink/public/common/origin_trials/origin_trials.h"
#include "third_party/blink/public/common/origin_trials/trial_token_result.h"
#include "third_party/blink/public/common/origin_trials/trial_token_validator.h"
#include "third_party/blink/public/mojom/runtime_feature_state/runtime_feature.mojom-shared.h"
#include "url/origin.h"

namespace content {
class OriginTrialStateHostImpl;
class RuntimeFeatureStateDocumentData;
}

namespace blink {

// A class to represent a read only copy of RuntimeFeatureState override values.
// This class is not mutable by the browser process but could potentially be
// modified by the renderer process for features which allow origin trial
// overrides.
// See RuntimeFeatureStateContext for additional information.

class BLINK_COMMON_EXPORT RuntimeFeatureStateReadContext {
 public:
  const base::flat_map<blink::mojom::RuntimeFeature, bool>&
  GetFeatureOverrides() const {
    return feature_overrides_;
  }

  {% for feature in browser_read_access_features %}
  bool Is{{feature.name}}Enabled() const {
    return IsEnabled(
        blink::mojom::RuntimeFeature::k{{feature.name}});
  }
  {% endfor %}

  // TODO(https://crbug.com/1410784): Validate the list of `third_party_origins`
  // against the ones the renderer process believes were active.
  {% for feature in browser_read_access_with_third_party_features %}
  bool Is{{feature.name}}EnabledForThirdParty(const base::span<url::Origin>& third_party_origins) const {
    return IsEnabledForThirdParty(
        blink::mojom::RuntimeFeature::k{{feature.name}}, third_party_origins);
  }
  {% endfor %}

 protected:
  bool IsEnabled(blink::mojom::RuntimeFeature feature) const {
    auto override_it = feature_overrides_.find(feature);
    if (override_it != feature_overrides_.end())
      return override_it->second;

    auto initial_it = initial_values_.find(feature);
    CHECK(initial_it != initial_values_.end());
    return initial_it->second;
  }

  bool IsEnabledForThirdParty(blink::mojom::RuntimeFeature feature,
                              const base::span<url::Origin>& third_party_origins) const {
    auto override_it = possible_third_party_feature_overrides_.find(feature);
    if (override_it == possible_third_party_feature_overrides_.end())
      return false;

    blink::TrialTokenValidator validator;
    for (const auto& token : override_it->second) {
      blink::TrialTokenResult result = validator.ValidateTokenAndTrial(
          token, origin(), third_party_origins, base::Time::Now());
      if (result.Status() == blink::OriginTrialTokenStatus::kSuccess &&
          result.ParsedToken()->is_third_party()) {
        return blink::origin_trials::IsTrialValid(result.ParsedToken()->feature_name()) &&
          blink::origin_trials::IsTrialEnabledForBrowserProcessReadAccess(
              result.ParsedToken()->feature_name());
      }
    }
    return false;
  }

  const url::Origin& origin() const {
    CHECK(origin_.has_value());
    return *origin_;
  }

  // Sparse map of overrides collected during initial navigation. This map
  // will be attached to the navigation on commit.
  base::flat_map<blink::mojom::RuntimeFeature, bool> feature_overrides_;

  // Sparse map of overrides that might be needed for third-party contexts.
  // Tokens must be validated once the attempting third-party origin is known.
  base::flat_map<blink::mojom::RuntimeFeature,
                 std::vector<std::string>> possible_third_party_feature_overrides_;

  // Values for all read/write features on context creation.
  base::flat_map<blink::mojom::RuntimeFeature, bool> initial_values_;

  // The last comitted origin from the RenderFrameHost this state is attached
  // to via RuntimeFeatureStateDocumentData. Empty if not yet bound to one.
  std::optional<url::Origin> origin_;

 protected:
  // This class shouldn't be instantiated directly. Use
  // RuntimeFeatureStateContext.
  RuntimeFeatureStateReadContext() = default;

 private:
  // Only OriginTrialStateHostImpl should be able to make changes
  // to the read-only context, when a feature diff is sent from
  // the renderer process to the browser process via IPC. Thus,
  // ApplyFeatureChange() is private but will be called in
  // OriginTrialStateHostImpl instances.
  friend class ::content::OriginTrialStateHostImpl;

  // This function allows OriginTrialStateHostImpl to update the
  // browser process's copy of the feature state
  // (RuntimeFeatureStateReadContext) to match the state found in
  // the renderer process.
  void ApplyFeatureChange(const base::flat_map<blink::mojom::RuntimeFeature,
                                               bool>& modified_features,
                          const base::flat_map<blink::mojom::RuntimeFeature,
                                               std::vector<std::string>>&
                              possible_third_party_features) {
    // Feature values sent from the renderer process take precedence over state
    // held currently in the browser process, so insert_or_assign is used.
    for (auto const& feature : modified_features) {
      feature_overrides_.insert_or_assign(feature.first, feature.second);
    }
    for (auto const& feature : possible_third_party_features) {
      possible_third_party_feature_overrides_.insert_or_assign(feature.first,
                                                               feature.second);
    }
  }

  // RuntimeFeatureStateDocumentData should be able to update the origin used
  // for token validation upon its construction.
  friend class ::content::RuntimeFeatureStateDocumentData;

  void set_origin_on_navigation(const url::Origin& origin,
                                base::PassKey<content::RuntimeFeatureStateDocumentData>) {
    // Ideally this would be set only once for a given
    // RuntimeFeatureStateReadContext, but they are copied and re-used
    // between frames so we have to depend on the function being private.
    origin_ = origin;
  }
};

}  // namespace blink

#endif // {{header_guard}}