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