1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/frame_host/navigation_throttle_runner.h"
6
7 #include "content/browser/devtools/devtools_instrumentation.h"
8 #include "content/browser/frame_host/ancestor_throttle.h"
9 #include "content/browser/frame_host/blocked_scheme_navigation_throttle.h"
10 #include "content/browser/frame_host/form_submission_throttle.h"
11 #include "content/browser/frame_host/mixed_content_navigation_throttle.h"
12 #include "content/browser/frame_host/navigation_request.h"
13 #include "content/browser/frame_host/navigator_delegate.h"
14 #include "content/browser/frame_host/origin_policy_throttle.h"
15 #include "content/browser/frame_host/webui_navigation_throttle.h"
16 #include "content/browser/portal/portal_navigation_throttle.h"
17 #include "content/public/browser/navigation_handle.h"
18
19 namespace content {
20
21 namespace {
22
ExecuteNavigationEvent(NavigationThrottle * throttle,NavigationThrottleRunner::Event event)23 NavigationThrottle::ThrottleCheckResult ExecuteNavigationEvent(
24 NavigationThrottle* throttle,
25 NavigationThrottleRunner::Event event) {
26 switch (event) {
27 case NavigationThrottleRunner::Event::WillStartRequest:
28 return throttle->WillStartRequest();
29 case NavigationThrottleRunner::Event::WillRedirectRequest:
30 return throttle->WillRedirectRequest();
31 case NavigationThrottleRunner::Event::WillFailRequest:
32 return throttle->WillFailRequest();
33 case NavigationThrottleRunner::Event::WillProcessResponse:
34 return throttle->WillProcessResponse();
35 default:
36 NOTREACHED();
37 }
38 NOTREACHED();
39 return NavigationThrottle::CANCEL_AND_IGNORE;
40 }
41
GetEventName(NavigationThrottleRunner::Event event)42 const char* GetEventName(NavigationThrottleRunner::Event event) {
43 switch (event) {
44 case NavigationThrottleRunner::Event::WillStartRequest:
45 return "NavigationThrottle::WillStartRequest";
46 case NavigationThrottleRunner::Event::WillRedirectRequest:
47 return "NavigationThrottle::WillRedirectRequest";
48 case NavigationThrottleRunner::Event::WillFailRequest:
49 return "NavigationThrottle::WillFailRequest";
50 case NavigationThrottleRunner::Event::WillProcessResponse:
51 return "NavigationThrottle::WillProcessResponse";
52 default:
53 NOTREACHED();
54 }
55 return "";
56 }
57
58 } // namespace
59
NavigationThrottleRunner(Delegate * delegate)60 NavigationThrottleRunner::NavigationThrottleRunner(Delegate* delegate)
61 : delegate_(delegate) {}
62
63 NavigationThrottleRunner::~NavigationThrottleRunner() = default;
64
ProcessNavigationEvent(Event event)65 void NavigationThrottleRunner::ProcessNavigationEvent(Event event) {
66 DCHECK_NE(Event::NoEvent, event);
67 current_event_ = event;
68 next_index_ = 0;
69 ProcessInternal();
70 }
71
ResumeProcessingNavigationEvent(NavigationThrottle * deferring_throttle)72 void NavigationThrottleRunner::ResumeProcessingNavigationEvent(
73 NavigationThrottle* deferring_throttle) {
74 DCHECK_EQ(GetDeferringThrottle(), deferring_throttle);
75 ProcessInternal();
76 }
77
CallResumeForTesting()78 void NavigationThrottleRunner::CallResumeForTesting() {
79 ProcessInternal();
80 }
81
RegisterNavigationThrottles()82 void NavigationThrottleRunner::RegisterNavigationThrottles() {
83 // Note: |throttle_| might not be empty. Some NavigationThrottles might have
84 // been registered with RegisterThrottleForTesting. These must reside at the
85 // end of |throttles_|. TestNavigationManagerThrottle expects that the
86 // NavigationThrottles added for test are the last NavigationThrottles to
87 // execute. Take them out while appending the rest of the
88 // NavigationThrottles.
89 std::vector<std::unique_ptr<NavigationThrottle>> testing_throttles =
90 std::move(throttles_);
91
92 // The NavigationRequest associated with the NavigationThrottles this
93 // NavigationThrottleRunner manages.
94 // Unit tests that do not use NavigationRequest should never call
95 // RegisterNavigationThrottles as this function expects |delegate_| to be a
96 // NavigationRequest.
97 NavigationRequest* request = static_cast<NavigationRequest*>(delegate_);
98
99 throttles_ = request->GetDelegate()->CreateThrottlesForNavigation(request);
100
101 // Enforce rules for WebUI navigations.
102 AddThrottle(WebUINavigationThrottle::CreateThrottleForNavigation(request));
103
104 // Check for renderer-inititated main frame navigations to blocked URL schemes
105 // (data, filesystem). This is done early as it may block the main frame
106 // navigation altogether.
107 AddThrottle(
108 BlockedSchemeNavigationThrottle::CreateThrottleForNavigation(request));
109
110 AddThrottle(AncestorThrottle::MaybeCreateThrottleFor(request));
111 AddThrottle(FormSubmissionThrottle::MaybeCreateThrottleFor(request));
112
113 // Check for mixed content. This is done after the AncestorThrottle and the
114 // FormSubmissionThrottle so that when folks block mixed content with a CSP
115 // policy, they don't get a warning. They'll still get a warning in the
116 // console about CSP blocking the load.
117 AddThrottle(
118 MixedContentNavigationThrottle::CreateThrottleForNavigation(request));
119
120 // Handle Origin Policy (if enabled)
121 AddThrottle(OriginPolicyThrottle::MaybeCreateThrottleFor(request));
122
123 // Block certain requests that are not permitted for portals.
124 AddThrottle(PortalNavigationThrottle::MaybeCreateThrottleFor(request));
125
126 for (auto& throttle :
127 devtools_instrumentation::CreateNavigationThrottles(request)) {
128 AddThrottle(std::move(throttle));
129 }
130
131 // Insert all testing NavigationThrottles last.
132 throttles_.insert(throttles_.end(),
133 std::make_move_iterator(testing_throttles.begin()),
134 std::make_move_iterator(testing_throttles.end()));
135 }
136
GetDeferringThrottle() const137 NavigationThrottle* NavigationThrottleRunner::GetDeferringThrottle() const {
138 if (next_index_ == 0)
139 return nullptr;
140 return throttles_[next_index_ - 1].get();
141 }
142
AddThrottle(std::unique_ptr<NavigationThrottle> navigation_throttle)143 void NavigationThrottleRunner::AddThrottle(
144 std::unique_ptr<NavigationThrottle> navigation_throttle) {
145 if (navigation_throttle)
146 throttles_.push_back(std::move(navigation_throttle));
147 }
148
ProcessInternal()149 void NavigationThrottleRunner::ProcessInternal() {
150 DCHECK_NE(Event::NoEvent, current_event_);
151 base::WeakPtr<NavigationThrottleRunner> weak_ref = weak_factory_.GetWeakPtr();
152 for (size_t i = next_index_; i < throttles_.size(); ++i) {
153 TRACE_EVENT1("navigation", GetEventName(current_event_), "throttle",
154 throttles_[i]->GetNameForLogging());
155 NavigationThrottle::ThrottleCheckResult result =
156 ExecuteNavigationEvent(throttles_[i].get(), current_event_);
157 if (!weak_ref) {
158 // The NavigationThrottle execution has destroyed this
159 // NavigationThrottleRunner. Return immediately.
160 return;
161 }
162 TRACE_EVENT_ASYNC_STEP_INTO0(
163 "navigation", "NavigationHandle", delegate_,
164 base::StringPrintf("%s: %s: %d", GetEventName(current_event_),
165 throttles_[i]->GetNameForLogging(),
166 result.action()));
167 switch (result.action()) {
168 case NavigationThrottle::PROCEED:
169 continue;
170
171 case NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE:
172 case NavigationThrottle::BLOCK_REQUEST:
173 case NavigationThrottle::BLOCK_RESPONSE:
174 case NavigationThrottle::CANCEL:
175 case NavigationThrottle::CANCEL_AND_IGNORE:
176 next_index_ = 0;
177 InformDelegate(result);
178 return;
179
180 case NavigationThrottle::DEFER:
181 next_index_ = i + 1;
182 return;
183 }
184 }
185
186 next_index_ = 0;
187 InformDelegate(NavigationThrottle::PROCEED);
188 }
189
InformDelegate(const NavigationThrottle::ThrottleCheckResult & result)190 void NavigationThrottleRunner::InformDelegate(
191 const NavigationThrottle::ThrottleCheckResult& result) {
192 // Now that the event has executed, reset the current event to NoEvent since
193 // we're no longer processing any event. Do it before the call to the
194 // delegate, as it might lead to the deletion of this
195 // NavigationThrottleRunner.
196 Event event = current_event_;
197 current_event_ = Event::NoEvent;
198 delegate_->OnNavigationEventProcessed(event, result);
199 // DO NOT ADD CODE AFTER THIS. The NavigationThrottleRunner might have been
200 // deleted by the previous call.
201 }
202
203 } // namespace content
204