1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159

content / browser / renderer_host / navigation_throttle_runner.h [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.

#ifndef CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_THROTTLE_RUNNER_H_
#define CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_THROTTLE_RUNNER_H_

#include <stddef.h>

#include <optional>
#include <vector>

#include "base/memory/raw_ptr.h"
#include "base/memory/safety_checks.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "content/common/content_export.h"
#include "content/public/browser/navigation_throttle.h"

namespace content {

// This class owns the set of NavigationThrottles added to a NavigationHandle.
// It is responsible for calling the various sets of events on its
// NavigationThrottle, and notifying its delegate of the results of said events.
class CONTENT_EXPORT NavigationThrottleRunner {
  // Do not remove this macro!
  // The macro is maintained by the memory safety team.
  ADVANCED_MEMORY_SAFETY_CHECKS();

 public:
  // The different event types that can be processed by NavigationThrottles.
  // These values are persisted to logs. Entries should not be renumbered and
  // numeric values should never be reused.
  // This type is also used in the UKM as set in the RecordDeferTimeUKM().
  //
  // LINT.IfChange(Event)
  enum class Event {
    kNoEvent = 0,
    kWillStartRequest = 1,
    kWillRedirectRequest = 2,
    kWillFailRequest = 3,
    kWillProcessResponse = 4,
    kWillCommitWithoutUrlLoader = 5,
    kMaxValue = kWillCommitWithoutUrlLoader,
  };
  // LINT.ThenChange(//tools/metrics/histograms/metadata/navigation/enums.xml:NavigationThrottleEvent)

  class Delegate {
   public:
    // Called when the NavigationThrottleRunner is done processing the
    // navigation event of type |event|. |result| is the final
    // NavigationThrottle::ThrottleCheckResult for this event.
    virtual void OnNavigationEventProcessed(
        Event event,
        NavigationThrottle::ThrottleCheckResult result) = 0;
  };

  NavigationThrottleRunner(Delegate* delegate,
                           int64_t navigation_id,
                           bool is_primary_main_frame);

  NavigationThrottleRunner(const NavigationThrottleRunner&) = delete;
  NavigationThrottleRunner& operator=(const NavigationThrottleRunner&) = delete;

  ~NavigationThrottleRunner();

  // Will call the appropriate NavigationThrottle function based on |event| on
  // all NavigationThrottles owned by this NavigationThrottleRunner.
  void ProcessNavigationEvent(Event event);

  // Resumes calling the appropriate NavigationThrottle functions for |event_|
  // on all NavigationThrottles that have not yet been notified.
  // |resuming_throttle| is the NavigationThrottle that asks for navigation
  // event processing to be resumed; it should be the one currently deferring
  // the navigation.
  void ResumeProcessingNavigationEvent(NavigationThrottle* resuming_throttle);

  // Simulates the navigation resuming. Most callers should just let the
  // deferring NavigationThrottle do the resuming.
  void CallResumeForTesting();

  // Registers the appropriate NavigationThrottles are added for a "standard"
  // navigation (i.e., one with a URLLoader that goes through the
  // WillSendRequest/WillProcessResponse callback sequence).
  void RegisterNavigationThrottles();

  // Registers the appropriate NavigationThrottles for a navigation that can
  // immediately commit because no URLLoader is required (about:blank,
  // about:srcdoc, and most same-document navigations).
  void RegisterNavigationThrottlesForCommitWithoutUrlLoader();

  // Returns the throttle that is currently deferring the navigation (i.e. the
  // throttle at index |next_index_ -1|). If the handle is not deferred, returns
  // nullptr;
  NavigationThrottle* GetDeferringThrottle() const;

  // Takes ownership of |navigation_throttle|. Following this call, any event
  // processed by the NavigationThrottleRunner will be called on
  // |navigation_throttle|.
  void AddThrottle(std::unique_ptr<NavigationThrottle> navigation_throttle);

  void set_first_deferral_callback_for_testing(base::OnceClosure callback) {
    first_deferral_callback_for_testing_ = std::move(callback);
  }

 private:
  void ProcessInternal();
  void InformDelegate(const NavigationThrottle::ThrottleCheckResult& result);

  // Records UKM about the deferring throttle when the navigation is resumed.
  void RecordDeferTimeUKM();

  const raw_ptr<Delegate> delegate_;

  // A list of Throttles registered for this navigation.
  std::vector<std::unique_ptr<NavigationThrottle>> throttles_;

  // The index of the next throttle to check.
  size_t next_index_;

  // The unique id of the navigation which this throttle runner is associated
  // with.
  const int64_t navigation_id_;

  // The time a throttle started deferring the navigation.
  base::Time defer_start_time_;

  // The total duration time that throttles deferred the navigation.
  base::TimeDelta total_defer_duration_time_;
  base::TimeDelta total_defer_duration_time_for_request_;

  // The time this runner started ProcessInternal() for the current_event_.
  // Should be reset when the processing is done.
  std::optional<base::Time> event_process_start_time_;

  // The accumulated time duration this runner took to execute throttles for the
  // current_event_.
  base::TimeDelta event_process_execution_time_;

  // The total count to know how many times a throttle defer the navigation.
  size_t defer_count_ = 0;
  size_t defer_count_for_request_ = 0;

  // This test-only callback will be run the first time a NavigationThrottle
  // defers this navigation.
  base::OnceClosure first_deferral_callback_for_testing_;

  // The event currently being processed.
  Event current_event_ = Event::kNoEvent;

  // Whether the navigation is in the primary main frame.
  bool is_primary_main_frame_ = false;

  base::WeakPtrFactory<NavigationThrottleRunner> weak_factory_{this};
};

}  // namespace content

#endif  // CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_THROTTLE_RUNNER_H_