910e62b5创建于 1月15日历史提交
// 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.

#include "content/browser/preloading/prefetch/prefetch_params.h"

#include <string>

#include "base/command_line.h"
#include "base/metrics/field_trial_params.h"
#include "base/no_destructor.h"
#include "base/rand_util.h"
#include "base/strings/strcat.h"
#include "content/browser/preloading/prefetch/prefetch_features.h"
#include "content/browser/preloading/prefetch/prefetch_type.h"
#include "content/browser/preloading/preloading_trigger_type_impl.h"
#include "content/browser/preloading/prerender/prerender_features.h"
#include "content/public/common/content_features.h"

namespace content {

GURL PrefetchProxyHost(const GURL& default_proxy_url) {
  // Command line overrides take priority.
  std::string cmd_line_value =
      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
          "isolated-prerender-tunnel-proxy");
  if (!cmd_line_value.empty()) {
    GURL cmd_line_url(cmd_line_value);
    if (cmd_line_url.is_valid()) {
      return cmd_line_url;
    }
    LOG(ERROR) << "--isolated-prerender-tunnel-proxy value is invalid";
  }

  return default_proxy_url;
}

std::string PrefetchProxyServerExperimentGroup() {
  return base::GetFieldTrialParamValueByFeature(
      features::kPrefetchUseContentRefactor, "server_experiment_group");
}

bool PrefetchAllowAllDomains() {
  return base::GetFieldTrialParamByFeatureAsBool(
             features::kPrefetchUseContentRefactor, "allow_all_domains",
             false) ||
         base::CommandLine::ForCurrentProcess()->HasSwitch(
             "isolated-prerender-allow-all-domains");
}

bool PrefetchAllowAllDomainsForExtendedPreloading() {
  return base::GetFieldTrialParamByFeatureAsBool(
      features::kPrefetchUseContentRefactor,
      "allow_all_domains_for_extended_preloading", true);
}

bool PrefetchServiceSendDecoyRequestForIneligblePrefetch(
    bool disabled_based_on_user_settings) {
  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
          "prefetch-proxy-never-send-decoy-requests-for-testing")) {
    return false;
  }
  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
          "prefetch-proxy-always-send-decoy-requests-for-testing")) {
    return true;
  }

  if (base::GetFieldTrialParamByFeatureAsBool(
          features::kPrefetchUseContentRefactor,
          "disable_decoys_based_on_user_settings", true) &&
      disabled_based_on_user_settings) {
    return false;
  }

  double probability = base::GetFieldTrialParamByFeatureAsDouble(
      features::kPrefetchUseContentRefactor,
      "ineligible_decoy_request_probability", 1.0);

  // Clamp to [0.0, 1.0].
  probability = std::max(0.0, probability);
  probability = std::min(1.0, probability);

  // RandDouble returns [0.0, 1.0) so don't use <= here since that may return
  // true when the probability is supposed to be 0 (i.e.: always false).
  return base::RandDouble() < probability;
}

base::TimeDelta PrefetchTimeoutDuration() {
  return base::Milliseconds(base::GetFieldTrialParamByFeatureAsInt(
      features::kPrefetchUseContentRefactor, "prefetch_timeout_ms",
      10 * 1000 /* 10 seconds */));
}

size_t PrefetchMainframeBodyLengthLimit() {
  return 1024 * base::GetFieldTrialParamByFeatureAsInt(
                    features::kPrefetchUseContentRefactor,
                    "max_mainframe_body_length_kb", 5 * 1024);
}

bool PrefetchStartsSpareRenderer() {
  return base::CommandLine::ForCurrentProcess()->HasSwitch(
             "isolated-prerender-start-spare-renderer") ||
         base::GetFieldTrialParamByFeatureAsBool(
             features::kPrefetchUseContentRefactor, "start_spare_renderer",
             true);
}

base::TimeDelta PrefetchContainerDefaultTtlInPrefetchService() {
  // A value of 0 or less, indicates that |PrefetchService| should keep the
  // prefetch forever.
  return base::Seconds(base::GetFieldTrialParamByFeatureAsInt(
      features::kPrefetchUseContentRefactor, "prefetch_container_lifetime_s",
      10 * 60 /* 10 minutes */));
}

bool PrefetchServiceHTMLOnly() {
  return base::GetFieldTrialParamByFeatureAsBool(
      features::kPrefetchUseContentRefactor, "html_only", false);
}

bool ShouldPrefetchBypassProxyForTestHost(std::string_view host) {
  static const base::NoDestructor<std::string> bypass(
      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
          "bypass-prefetch-proxy-for-host"));
  if (bypass->empty()) {
    return false;
  }
  return host == *bypass;
}

base::TimeDelta PrefetchCacheableDuration() {
  return base::Seconds(base::GetFieldTrialParamByFeatureAsInt(
      features::kPrefetchUseContentRefactor, "cacheable_duration", 300));
}

bool PrefetchProbingEnabled() {
  return base::GetFieldTrialParamByFeatureAsBool(
      features::kPrefetchCanaryCheckerParams, "must_probe_origin", true);
}

bool PrefetchCanaryCheckEnabled() {
  return base::GetFieldTrialParamByFeatureAsBool(
      features::kPrefetchCanaryCheckerParams, "do_canary", true);
}

bool PrefetchTLSCanaryCheckEnabled() {
  return base::GetFieldTrialParamByFeatureAsBool(
      features::kPrefetchCanaryCheckerParams, "do_tls_canary", false);
}

GURL PrefetchTLSCanaryCheckURL(const GURL& default_tls_canary_check_url) {
  GURL url(base::GetFieldTrialParamValueByFeature(
      features::kPrefetchCanaryCheckerParams, "tls_canary_url"));
  if (url.is_valid())
    return url;

  return default_tls_canary_check_url;
}

GURL PrefetchDNSCanaryCheckURL(const GURL& default_dns_canary_check_url) {
  GURL url(base::GetFieldTrialParamValueByFeature(
      features::kPrefetchCanaryCheckerParams, "dns_canary_url"));
  if (url.is_valid())
    return url;

  return default_dns_canary_check_url;
}

base::TimeDelta PrefetchCanaryCheckCacheLifetime() {
  return base::Hours(base::GetFieldTrialParamByFeatureAsInt(
      features::kPrefetchCanaryCheckerParams, "canary_cache_hours", 24));
}

base::TimeDelta PrefetchCanaryCheckTimeout() {
  return base::Milliseconds(base::GetFieldTrialParamByFeatureAsInt(
      features::kPrefetchCanaryCheckerParams, "canary_check_timeout_ms",
      5 * 1000 /* 5 seconds */));
}

int PrefetchCanaryCheckRetries() {
  return base::GetFieldTrialParamByFeatureAsInt(
      features::kPrefetchCanaryCheckerParams, "canary_check_retries", 1);
}

base::TimeDelta PrefetchBlockUntilHeadTimeout(
    const PrefetchType& prefetch_type,
    bool should_disable_block_until_head_timeout,
    bool is_nav_prerender) {
  // If the caller of prefetches requests to disable the timeout, follow that.
  if (should_disable_block_until_head_timeout) {
    return base::Seconds(0);
  }

  // Don't set a timeout for prerender because
  //
  // - The intention of prefetch ahead of prerender is not sending additional
  //   fetch request. The options of the behavior of the timeout case are
  //   1. (Current behavior) Making prerender fail, or 2. Falling back to
  //   network.
  // - 1 reduces the prerender activation rate.
  //
  // For more details, see
  // https://docs.google.com/document/d/1ZP7lYrtqZL9jC2xXieNY_UBMJL1sCrfmzTB8K6v4sD4/edit?resourcekey=0-fkbeQhkT3PhBb9FnnPgnZA&tab=t.wphan8fb23kr
  if (!features::kPrerender2FallbackPrefetchUseBlockUntilHeadTimetout.Get() &&
      is_nav_prerender) {
    return base::Seconds(0);
  }

  int timeout_in_milliseconds = 0;
  if (IsSpeculationRuleType(prefetch_type.trigger_type())) {
    switch (prefetch_type.GetEagerness()) {
      case blink::mojom::SpeculationEagerness::kImmediate:
        timeout_in_milliseconds = base::GetFieldTrialParamByFeatureAsInt(
            features::kPrefetchUseContentRefactor,
            "block_until_head_timeout_immediate_prefetch", 1000);
        break;
      case blink::mojom::SpeculationEagerness::kEager:
        timeout_in_milliseconds = base::GetFieldTrialParamByFeatureAsInt(
            features::kPrefetchUseContentRefactor,
            "block_until_head_timeout_eager_prefetch", 1000);
        break;
      case blink::mojom::SpeculationEagerness::kModerate:
        timeout_in_milliseconds = base::GetFieldTrialParamByFeatureAsInt(
            features::kPrefetchUseContentRefactor,
            "block_until_head_timeout_moderate_prefetch", 0);
        break;
      case blink::mojom::SpeculationEagerness::kConservative:
        timeout_in_milliseconds = base::GetFieldTrialParamByFeatureAsInt(
            features::kPrefetchUseContentRefactor,
            "block_until_head_timeout_conservative_prefetch", 0);
        break;
    }
  } else {
    timeout_in_milliseconds = base::GetFieldTrialParamByFeatureAsInt(
        features::kPrefetchUseContentRefactor,
        "block_until_head_timeout_embedder_prefetch", 1000);
  }
  return base::Milliseconds(timeout_in_milliseconds);
}

// These strings (including `embedder_histogram_suffix`) are persisted to logs.
// LINT.IfChange(GetMetricsSuffixTriggerTypeAndEagerness)
std::string GetMetricsSuffixTriggerTypeAndEagerness(
    const PrefetchType prefetch_type,
    const std::optional<std::string>& embedder_histogram_suffix) {
  switch (prefetch_type.trigger_type()) {
    case PreloadingTriggerType::kSpeculationRule:
      switch (prefetch_type.GetEagerness()) {
        case blink::mojom::SpeculationEagerness::kImmediate:
          return "SpeculationRule_Immediate2";
        case blink::mojom::SpeculationEagerness::kEager:
          return "SpeculationRule_Eager2";
        case blink::mojom::SpeculationEagerness::kModerate:
          return "SpeculationRule_Moderate";
        case blink::mojom::SpeculationEagerness::kConservative:
          return "SpeculationRule_Conservative";
      }
    case PreloadingTriggerType::kSpeculationRuleFromIsolatedWorld:
      switch (prefetch_type.GetEagerness()) {
        case blink::mojom::SpeculationEagerness::kImmediate:
          return "SpeculationRule_Immediate2";
        case blink::mojom::SpeculationEagerness::kEager:
          return "SpeculationRule_Eager2";
        case blink::mojom::SpeculationEagerness::kModerate:
          return "SpeculationRuleFromIsolatedWorld_Moderate";
        case blink::mojom::SpeculationEagerness::kConservative:
          return "SpeculationRuleFromIsolatedWorld_Conservative";
      }
    case PreloadingTriggerType::kSpeculationRuleFromAutoSpeculationRules:
      switch (prefetch_type.GetEagerness()) {
        case blink::mojom::SpeculationEagerness::kImmediate:
          return "SpeculationRule_Immediate2";
        case blink::mojom::SpeculationEagerness::kEager:
          return "SpeculationRule_Eager2";
        case blink::mojom::SpeculationEagerness::kModerate:
          return "SpeculationRuleFromAutoSpeculationRules_Moderate";
        case blink::mojom::SpeculationEagerness::kConservative:
          return "SpeculationRuleFromAutoSpeculationRules_Conservative";
      }
    case PreloadingTriggerType::kEmbedder:
      CHECK(!embedder_histogram_suffix.value().empty());
      return base::StrCat({"Embedder_", embedder_histogram_suffix.value()});
  }
}
// LINT.ThenChange(//tools/metrics/histograms/metadata/prefetch/histograms.xml:TriggerTypeAndEagerness)

bool PrefetchNIKScopeEnabled() {
  return base::FeatureList::IsEnabled(features::kPrefetchNIKScope);
}

size_t GetPrefetchDataPipeTeeBodySizeLimit() {
  return static_cast<size_t>(features::kPrefetchReusableBodySizeLimit.Get());
}

bool UsePrefetchScheduler() {
  return base::FeatureList::IsEnabled(features::kPrefetchScheduler) ||
         features::kPrerender2FallbackPrefetchSchedulerPolicy.Get() !=
             features::Prerender2FallbackPrefetchSchedulerPolicy::kNotUse ||
         base::FeatureList::IsEnabled(
             features::kWebViewPrefetchHighestPrefetchPriority) ||
         base::FeatureList::IsEnabled(
             features::kPrefetchMultipleActiveSetSizeLimitForBase);
}

}  // namespace content