910e62b5创建于 1月15日历史提交
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_PUBLIC_BROWSER_PROCESS_SELECTION_DEFERRING_CONDITION_H_
#define CONTENT_PUBLIC_BROWSER_PROCESS_SELECTION_DEFERRING_CONDITION_H_

#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/safe_ref.h"
#include "content/common/content_export.h"
#include "content/public/browser/navigation_handle.h"

namespace content {

class NavigationHandle;
class ProcessSelectionUserData;

// Base class to allow clients to prepare inputs that are needed for selecting a
// process during a navigation request, optionally deferring the final process
// selection when necessary. On creation, the implementing class can begin to
// prepare results for the associated NavigationHandle by queuing asynchronous
// tasks. The `ProcessSelectionDeferringCondition` will be notified at
// `NavigationRequest::OnRequestRedirected()` time, giving the class an
// opportunity to schedule additional tasks, or cancel previously queued ones.
// Then, after the network response is received, the navigation will call
// `OnWillSelectFinalProcess()`. At this time, the class can defer by returning
// `Result::kDefer`. If it returns `Result::kDefer`, then it must call the
// provided resume closure in order for the navigation to proceed. Once all
// conditions have resumed, navigation continues from
// `NavigationRequest::SelectFrameHostForOnResponseStarted()`.
//
// `ProcessSelectionDeferringCondition` vs. `NavigationThrottle` and
// `CommitDeferringCondition`: It may seem like either a `NavigationThrottle` or
// a `CommitDeferringCondition` could be used to provide the same functionality
// by deferring in `NavigationThrottle::WillProcessResponse` or
// `CommitDeferringCondition::WillCommitNavigation`, however those hooks occur
// after process selection has been finalized. Another key difference between
// these mechanisms is that `ProcessSelectionDeferringCondition` can only defer
// and is unable to cancel or otherwise influence the navigation request. Most
// potential clients will want to use the `NavigationThrottle` or the
// `CommitDeferringCondition` mechanism for their use-case.
class CONTENT_EXPORT ProcessSelectionDeferringCondition {
 public:
  enum class Result {
    // Returned when the condition is satisfied and the client can synchronously
    // proceed with process selection.
    kProceed,
    // Returned when the condition needs to asynchronously wait before allowing
    // process selection to occur.
    kDefer,
  };

  ProcessSelectionDeferringCondition() = delete;
  explicit ProcessSelectionDeferringCondition(
      NavigationHandle& navigation_handle);
  ProcessSelectionDeferringCondition(
      const ProcessSelectionDeferringCondition& other) = delete;
  ProcessSelectionDeferringCondition& operator=(
      const ProcessSelectionDeferringCondition& other) = delete;
  virtual ~ProcessSelectionDeferringCondition();

  // Called when the navigation request is redirected. This should handle
  // canceling any currently running tasks that are no longer needed, as well as
  // starting new tasks for the redirected request.
  virtual void OnRequestRedirected() {}

  // Called when the navigation request will select the renderer host process.
  // If the condition is ready, return `Result::kProceed` so that the navigation
  // can continue with selecting a final SiteInstance and process; otherwise
  // return `Result::kDefer`. When `kDefer` is returned, the navigation will
  // block until the passed in resume closure is called. NOTE: Avoid deferring
  // whenever possible because this slows page loads. See the comment in
  // NavigationThrottle::ThrottleAction::DEFER for more information.
  virtual Result OnWillSelectFinalProcess(base::OnceClosure resume) = 0;

  NavigationHandle& navigation_handle() const { return *navigation_handle_; }

  // A convenience method to get the ProcessSelectionUserData instance
  // associated with this navigation. Implementers of this class can use this
  // data container to attach any relevant information that needs to be made
  // available to the process selection logic. See `ProcessSelectionUserData`
  // for details about defining and retrieving custom data.
  ProcessSelectionUserData& GetProcessSelectionUserData() {
    return navigation_handle_->GetProcessSelectionUserData();
  }

 private:
  base::SafeRef<NavigationHandle> navigation_handle_;
};
}  // namespace content

#endif  // CONTENT_PUBLIC_BROWSER_PROCESS_SELECTION_DEFERRING_CONDITION_H_