OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 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/test/navigation_simulator_impl.h" | |
6 | |
7 #include "content/browser/frame_host/navigation_handle_impl.h" | |
8 #include "content/browser/frame_host/navigation_request.h" | |
9 #include "content/common/frame_messages.h" | |
10 #include "content/public/browser/navigation_throttle.h" | |
11 #include "content/public/browser/web_contents.h" | |
12 #include "content/public/common/browser_side_navigation_policy.h" | |
13 #include "content/test/test_navigation_url_loader.h" | |
14 #include "content/test/test_render_frame_host.h" | |
15 #include "net/url_request/redirect_info.h" | |
16 | |
17 namespace content { | |
18 | |
19 namespace { | |
20 | |
21 class NavigationThrottleCallCounter : public NavigationThrottle { | |
nasko
2017/02/16 18:47:59
This class doesn't seem to count anything, so the
clamy
2017/02/17 17:34:52
Indeed. Renamed it.
| |
22 public: | |
23 NavigationThrottleCallCounter(NavigationHandle* handle, | |
24 const base::Closure& on_will_start_request, | |
25 const base::Closure& on_will_redirect_request, | |
26 const base::Closure& on_will_process_response) | |
27 : NavigationThrottle(handle), | |
28 on_will_start_request_(on_will_start_request), | |
29 on_will_redirect_request_(on_will_redirect_request), | |
30 on_will_process_response_(on_will_process_response) {} | |
31 | |
32 NavigationThrottle::ThrottleCheckResult WillStartRequest() override { | |
33 on_will_start_request_.Run(); | |
34 return NavigationThrottle::PROCEED; | |
35 } | |
36 | |
37 NavigationThrottle::ThrottleCheckResult WillRedirectRequest() override { | |
38 on_will_redirect_request_.Run(); | |
39 return NavigationThrottle::PROCEED; | |
40 } | |
41 | |
42 NavigationThrottle::ThrottleCheckResult WillProcessResponse() override { | |
43 on_will_process_response_.Run(); | |
44 return NavigationThrottle::PROCEED; | |
45 } | |
46 | |
47 private: | |
48 base::Closure on_will_start_request_; | |
49 base::Closure on_will_redirect_request_; | |
50 base::Closure on_will_process_response_; | |
51 }; | |
52 | |
53 } // namespace | |
54 | |
55 NavigationSimulatorImpl::NavigationSimulatorImpl( | |
56 const GURL& original_url, | |
57 TestRenderFrameHost* render_frame_host) | |
58 : WebContentsObserver(WebContents::FromRenderFrameHost(render_frame_host)), | |
59 state_(INITIALIZATION), | |
nasko
2017/02/16 18:47:59
With the newest C++11 goodies, we can initialize t
clamy
2017/02/17 17:34:52
Done.
| |
60 render_frame_host_(render_frame_host), | |
61 handle_(nullptr), | |
62 navigation_url_(original_url), | |
63 transition_(ui::PAGE_TRANSITION_LINK), | |
64 num_did_start_navigation_called_(0), | |
65 num_will_start_request_called_(0), | |
66 num_will_redirect_request_called_(0), | |
67 num_did_redirect_navigation_called_(0), | |
68 num_will_process_response_called_(0), | |
69 num_ready_to_commit_called_(0), | |
70 num_did_finish_navigation_called_(0), | |
71 weak_factory_(this) { | |
72 if (render_frame_host->GetParent()) { | |
73 if (!render_frame_host->frame_tree_node()->has_committed_real_load()) | |
74 transition_ = ui::PAGE_TRANSITION_AUTO_SUBFRAME; | |
75 else | |
76 transition_ = ui::PAGE_TRANSITION_MANUAL_SUBFRAME; | |
77 } | |
78 } | |
79 | |
80 NavigationSimulatorImpl::~NavigationSimulatorImpl() {} | |
81 | |
82 void NavigationSimulatorImpl::Start() { | |
83 CHECK(state_ == INITIALIZATION) | |
84 << "NavigationSimulator::Start should only be called once."; | |
85 state_ = STARTED; | |
86 | |
87 if (IsBrowserSideNavigationEnabled()) { | |
88 render_frame_host_->SendRendererInitiatedNavigationRequest(navigation_url_, | |
89 true); | |
90 NavigationRequest* request = | |
91 render_frame_host_->frame_tree_node()->navigation_request(); | |
92 DCHECK(request); | |
93 handle_ = request->navigation_handle(); | |
94 } else { | |
95 render_frame_host_->OnMessageReceived( | |
96 FrameHostMsg_DidStartLoading(render_frame_host_->GetRoutingID(), true)); | |
97 render_frame_host_->OnMessageReceived(FrameHostMsg_DidStartProvisionalLoad( | |
98 render_frame_host_->GetRoutingID(), navigation_url_, | |
99 std::vector<GURL>(), base::TimeTicks::Now())); | |
100 handle_ = render_frame_host_->navigation_handle(); | |
101 handle_->WillStartRequest( | |
102 "GET", scoped_refptr<content::ResourceRequestBodyImpl>(), referrer_, | |
103 true /* user_gesture */, transition_, false /* is_external_protocol */, | |
104 REQUEST_CONTEXT_TYPE_LOCATION, | |
105 blink::WebMixedContentContextType::NotMixedContent, | |
106 base::Callback<void(NavigationThrottle::ThrottleCheckResult)>()); | |
107 } | |
108 | |
109 CHECK(handle_); | |
110 | |
111 // Make sure all NavigationThrottles have run. | |
112 // TODO(clamy): provide a non auto-advance mode if needed. | |
113 while (handle_->state_for_testing() == NavigationHandleImpl::DEFERRING_START) | |
114 handle_->Resume(); | |
115 | |
116 CHECK_EQ(1, num_did_start_navigation_called_); | |
117 CHECK_EQ(1, num_will_start_request_called_); | |
118 } | |
119 | |
120 void NavigationSimulatorImpl::Redirect(const GURL& new_url) { | |
121 CHECK(state_ == STARTED) << "NavigationSimulatorImpl::Redirect should be " | |
122 "called after Start but before Fail or Commit"; | |
123 CHECK_EQ(0, num_did_finish_navigation_called_) | |
124 << "NavigationSimulatorImpl::Redirect cannot be called after the " | |
125 "navigation has finished"; | |
126 | |
127 navigation_url_ = new_url; | |
128 | |
129 int previous_num_will_redirect_request_called = | |
130 num_will_redirect_request_called_; | |
131 int previous_did_redirect_navigation_called = | |
132 num_did_redirect_navigation_called_; | |
133 | |
134 if (IsBrowserSideNavigationEnabled()) { | |
135 NavigationRequest* request = | |
136 render_frame_host_->frame_tree_node()->navigation_request(); | |
137 TestNavigationURLLoader* url_loader = | |
138 static_cast<TestNavigationURLLoader*>(request->loader_for_testing()); | |
139 CHECK(url_loader); | |
140 | |
141 net::RedirectInfo redirect_info; | |
142 redirect_info.status_code = 302; | |
143 redirect_info.new_method = "GET"; | |
144 redirect_info.new_url = new_url; | |
145 redirect_info.new_first_party_for_cookies = new_url; | |
146 redirect_info.new_referrer = referrer_.url.spec(); | |
147 redirect_info.new_referrer_policy = | |
148 Referrer::ReferrerPolicyForUrlRequest(referrer_); | |
149 | |
150 url_loader->CallOnRequestRedirected( | |
151 redirect_info, scoped_refptr<ResourceResponse>(new ResourceResponse)); | |
152 } else { | |
153 handle_->WillRedirectRequest( | |
154 new_url, "GET", referrer_.url, false /* is_external_protocol */, | |
155 scoped_refptr<net::HttpResponseHeaders>(), | |
156 net::HttpResponseInfo::ConnectionInfo(), | |
157 base::Callback<void(NavigationThrottle::ThrottleCheckResult)>()); | |
158 } | |
159 | |
160 // Make sure all NavigationThrottles have run. | |
161 // TODO(clamy): provide a non auto-advance mode if needed. | |
162 while (handle_->state_for_testing() == | |
163 NavigationHandleImpl::DEFERRING_REDIRECT) { | |
164 handle_->Resume(); | |
165 } | |
166 | |
167 CHECK_EQ(previous_num_will_redirect_request_called + 1, | |
168 num_will_redirect_request_called_); | |
169 CHECK_EQ(previous_did_redirect_navigation_called + 1, | |
170 num_did_redirect_navigation_called_); | |
171 } | |
172 | |
173 void NavigationSimulatorImpl::Commit() { | |
174 CHECK_EQ(STARTED, state_) << "NavigationSimulatorImpl::Commit can only be " | |
175 "called once, and should be called after Start " | |
176 "has been called"; | |
177 CHECK_EQ(0, num_did_finish_navigation_called_) | |
178 << "NavigationSimulatorImpl::Commit cannot be called after the " | |
179 "navigation has finished"; | |
180 | |
181 if (IsBrowserSideNavigationEnabled() && | |
182 render_frame_host_->frame_tree_node()->navigation_request()) { | |
183 render_frame_host_->PrepareForCommit(); | |
184 } | |
185 | |
186 // Call NavigationHandle::WillProcessResponse if needed. | |
187 if (handle_->state_for_testing() < | |
188 NavigationHandleImpl::WILL_PROCESS_RESPONSE) { | |
189 handle_->WillProcessResponse( | |
190 render_frame_host_, scoped_refptr<net::HttpResponseHeaders>(), | |
191 net::HttpResponseInfo::ConnectionInfo(), SSLStatus(), GlobalRequestID(), | |
192 false /* should_replace_current_entry */, false /* is_download */, | |
193 false /* is_stream */, base::Closure(), | |
194 base::Callback<void(NavigationThrottle::ThrottleCheckResult)>()); | |
195 } | |
196 | |
197 // Make sure all NavigationThrottles have run. | |
198 // TODO(clamy): provide a non auto-advance mode if needed. | |
199 while (handle_->state_for_testing() == | |
200 NavigationHandleImpl::DEFERRING_RESPONSE) { | |
201 handle_->Resume(); | |
202 } | |
203 | |
204 CHECK_EQ(1, num_will_process_response_called_); | |
205 CHECK_EQ(1, num_ready_to_commit_called_); | |
206 | |
207 // Update the RenderFrameHost now that we know which RenderFrameHost will | |
208 // commit the navigation. | |
209 TestRenderFrameHost* new_render_frame_host = | |
210 static_cast<TestRenderFrameHost*>(handle_->GetRenderFrameHost()); | |
211 if (!IsBrowserSideNavigationEnabled() && | |
212 new_render_frame_host != render_frame_host_) { | |
213 CHECK(handle_->is_transferring()); | |
214 // Simulate the renderer transfer. | |
215 new_render_frame_host->OnMessageReceived(FrameHostMsg_DidStartLoading( | |
216 new_render_frame_host->GetRoutingID(), true)); | |
217 new_render_frame_host->OnMessageReceived( | |
218 FrameHostMsg_DidStartProvisionalLoad( | |
219 new_render_frame_host->GetRoutingID(), navigation_url_, | |
220 std::vector<GURL>(), base::TimeTicks::Now())); | |
221 CHECK(!handle_->is_transferring()); | |
222 } | |
223 render_frame_host_ = | |
224 static_cast<TestRenderFrameHost*>(handle_->GetRenderFrameHost()); | |
nasko
2017/02/16 18:47:59
Why do we need to call this again? Wouldn't assign
clamy
2017/02/17 17:34:52
Done.
| |
225 | |
226 FrameHostMsg_DidCommitProvisionalLoad_Params params; | |
227 params.nav_entry_id = 0; | |
228 params.url = navigation_url_; | |
229 params.origin = url::Origin(navigation_url_); | |
230 params.transition = transition_; | |
231 params.should_update_history = true; | |
232 params.did_create_new_entry = | |
233 render_frame_host_->GetParent() || | |
234 render_frame_host_->frame_tree_node()->has_committed_real_load(); | |
235 params.gesture = NavigationGestureUser; | |
236 params.contents_mime_type = "text/html"; | |
237 params.method = "GET"; | |
238 params.http_status_code = 200; | |
239 params.socket_address.set_host("2001:db8::1"); | |
240 params.socket_address.set_port(80); | |
241 params.history_list_was_cleared = false; | |
242 params.original_request_url = navigation_url_; | |
243 params.was_within_same_page = false; | |
244 params.page_state = | |
245 PageState::CreateForTesting(navigation_url_, false, nullptr, nullptr); | |
246 | |
247 render_frame_host_->SendNavigateWithParams(¶ms); | |
248 | |
249 state_ = FINISHED; | |
250 | |
251 CHECK_EQ(1, num_did_finish_navigation_called_); | |
252 } | |
253 | |
254 void NavigationSimulatorImpl::Fail(int error_code) { | |
255 CHECK_EQ(STARTED, state_) << "NavigationSimulatorImpl::Fail can only be " | |
256 "called once, and should be called after Start " | |
257 "has been called"; | |
258 CHECK_EQ(0, num_did_finish_navigation_called_) | |
259 << "NavigationSimulatorImpl::Fail cannot be called after the " | |
260 "navigation has finished"; | |
261 | |
262 state_ = FAILED; | |
263 | |
264 bool should_result_in_error_page = error_code != net::ERR_ABORTED; | |
265 if (IsBrowserSideNavigationEnabled()) { | |
266 NavigationRequest* request = | |
267 render_frame_host_->frame_tree_node()->navigation_request(); | |
268 CHECK(request); | |
269 TestNavigationURLLoader* url_loader = | |
270 static_cast<TestNavigationURLLoader*>(request->loader_for_testing()); | |
271 CHECK(url_loader); | |
272 url_loader->SimulateError(error_code); | |
273 } else { | |
274 FrameHostMsg_DidFailProvisionalLoadWithError_Params error_params; | |
275 error_params.error_code = error_code; | |
276 error_params.url = navigation_url_; | |
277 render_frame_host_->OnMessageReceived( | |
278 FrameHostMsg_DidFailProvisionalLoadWithError( | |
279 render_frame_host_->GetRoutingID(), error_params)); | |
280 if (!should_result_in_error_page) { | |
281 render_frame_host_->OnMessageReceived( | |
282 FrameHostMsg_DidStopLoading(render_frame_host_->GetRoutingID())); | |
283 } | |
284 } | |
285 | |
286 if (IsBrowserSideNavigationEnabled()) { | |
287 CHECK_EQ(1, num_ready_to_commit_called_); | |
288 if (should_result_in_error_page) { | |
289 // Update the RenderFrameHost now that we know which RenderFrameHost will | |
290 // commit the error page. | |
291 render_frame_host_ = | |
292 static_cast<TestRenderFrameHost*>(handle_->GetRenderFrameHost()); | |
293 } | |
294 } | |
295 | |
296 if (should_result_in_error_page) | |
297 CHECK_EQ(0, num_did_finish_navigation_called_); | |
298 else | |
299 CHECK_EQ(1, num_did_finish_navigation_called_); | |
300 } | |
301 | |
302 void NavigationSimulatorImpl::CommitErrorPage() { | |
303 CHECK_EQ(FAILED, state_) | |
304 << "NavigationSimulatorImpl::CommitErrorPage can only be " | |
305 "called once, and should be called after Fail " | |
306 "has been called"; | |
307 CHECK_EQ(0, num_did_finish_navigation_called_) | |
308 << "NavigationSimulatorImpl::CommitErrorPage cannot be called after the " | |
309 "navigation has finished"; | |
310 | |
311 GURL error_url = GURL(kUnreachableWebDataURL); | |
312 render_frame_host_->OnMessageReceived(FrameHostMsg_DidStartProvisionalLoad( | |
313 render_frame_host_->GetRoutingID(), error_url, std::vector<GURL>(), | |
314 base::TimeTicks::Now())); | |
315 FrameHostMsg_DidCommitProvisionalLoad_Params params; | |
316 params.nav_entry_id = 0; | |
317 params.did_create_new_entry = true; | |
318 params.url = navigation_url_; | |
319 params.transition = transition_; | |
320 params.was_within_same_page = false; | |
321 params.url_is_unreachable = true; | |
322 params.page_state = | |
323 PageState::CreateForTesting(navigation_url_, false, nullptr, nullptr); | |
324 render_frame_host_->SendNavigateWithParams(¶ms); | |
325 | |
326 state_ = FINISHED; | |
327 | |
328 CHECK_EQ(1, num_did_finish_navigation_called_); | |
329 } | |
330 | |
331 void NavigationSimulatorImpl::CommitSamePage() { | |
332 CHECK_EQ(INITIALIZATION, state_) | |
333 << "NavigationSimulatorImpl::CommitErrorPage should be the only " | |
334 "navigation event function called on the NavigationSimulator"; | |
335 | |
336 render_frame_host_->OnMessageReceived( | |
337 FrameHostMsg_DidStartLoading(render_frame_host_->GetRoutingID(), false)); | |
338 | |
339 FrameHostMsg_DidCommitProvisionalLoad_Params params; | |
340 params.nav_entry_id = 0; | |
341 params.url = navigation_url_; | |
342 params.origin = url::Origin(navigation_url_); | |
343 params.transition = transition_; | |
344 params.should_update_history = true; | |
nasko
2017/02/16 18:47:59
Is this set to true for same page?
clamy
2017/02/17 17:34:52
I think so. See https://cs.chromium.org/chromium/s
| |
345 params.did_create_new_entry = | |
nasko
2017/02/16 18:47:59
Why would we create a new entry for same page navi
clamy
2017/02/17 17:34:52
Done.
| |
346 render_frame_host_->GetParent() || | |
347 render_frame_host_->frame_tree_node()->has_committed_real_load(); | |
348 params.gesture = NavigationGestureUser; | |
349 params.contents_mime_type = "text/html"; | |
350 params.method = "GET"; | |
351 params.http_status_code = 200; | |
352 params.socket_address.set_host("2001:db8::1"); | |
353 params.socket_address.set_port(80); | |
354 params.history_list_was_cleared = false; | |
355 params.original_request_url = navigation_url_; | |
356 params.was_within_same_page = true; | |
357 params.page_state = | |
358 PageState::CreateForTesting(navigation_url_, false, nullptr, nullptr); | |
359 | |
360 render_frame_host_->SendNavigateWithParams(¶ms); | |
361 | |
362 render_frame_host_->OnMessageReceived( | |
363 FrameHostMsg_DidStopLoading(render_frame_host_->GetRoutingID())); | |
364 | |
365 state_ = FINISHED; | |
366 | |
367 CHECK_EQ(1, num_did_start_navigation_called_); | |
368 CHECK_EQ(0, num_will_start_request_called_); | |
369 CHECK_EQ(0, num_will_process_response_called_); | |
370 CHECK_EQ(0, num_ready_to_commit_called_); | |
371 CHECK_EQ(1, num_did_finish_navigation_called_); | |
372 } | |
373 | |
374 void NavigationSimulatorImpl::SetTransition(ui::PageTransition transition) { | |
375 CHECK_EQ(INITIALIZATION, state_) | |
376 << "The transition cannot be set after the navigation has started"; | |
377 transition_ = transition; | |
378 } | |
379 | |
380 void NavigationSimulatorImpl::SetReferrer(const Referrer& referrer) { | |
381 CHECK_LE(state_, STARTED) << "The referrer cannot be set after the " | |
382 "navigation has committed or has failed"; | |
383 referrer_ = referrer; | |
384 } | |
385 | |
386 void NavigationSimulatorImpl::DidStartNavigation( | |
387 NavigationHandle* navigation_handle) { | |
388 // Check if this navigation is the one we're simulating. | |
389 if (state_ != STARTED) | |
390 return; | |
391 | |
392 if (navigation_handle->GetURL() != navigation_url_) | |
393 return; | |
394 | |
395 NavigationHandleImpl* handle = | |
396 static_cast<NavigationHandleImpl*>(navigation_handle); | |
397 | |
398 if (handle->frame_tree_node() != render_frame_host_->frame_tree_node()) | |
399 return; | |
400 | |
401 num_did_start_navigation_called_++; | |
402 | |
403 // Add a throttle to count NavigationThrottle calls count. | |
404 handle->RegisterThrottleForTesting( | |
405 base::MakeUnique<NavigationThrottleCallCounter>( | |
406 handle, base::Bind(&NavigationSimulatorImpl::OnWillStartRequest, | |
407 weak_factory_.GetWeakPtr()), | |
408 base::Bind(&NavigationSimulatorImpl::OnWillRedirectRequest, | |
409 weak_factory_.GetWeakPtr()), | |
410 base::Bind(&NavigationSimulatorImpl::OnWillProcessResponse, | |
411 weak_factory_.GetWeakPtr()))); | |
412 } | |
413 | |
414 void NavigationSimulatorImpl::DidRedirectNavigation( | |
415 NavigationHandle* navigation_handle) { | |
416 if (navigation_handle == handle_) | |
417 num_did_redirect_navigation_called_++; | |
418 } | |
419 | |
420 void NavigationSimulatorImpl::ReadyToCommitNavigation( | |
421 NavigationHandle* navigation_handle) { | |
422 if (navigation_handle == handle_) | |
423 num_ready_to_commit_called_++; | |
424 } | |
425 | |
426 void NavigationSimulatorImpl::DidFinishNavigation( | |
427 NavigationHandle* navigation_handle) { | |
428 if (navigation_handle == handle_) | |
429 num_did_finish_navigation_called_++; | |
430 } | |
431 | |
432 void NavigationSimulatorImpl::OnWillStartRequest() { | |
433 num_will_start_request_called_++; | |
434 } | |
435 | |
436 void NavigationSimulatorImpl::OnWillRedirectRequest() { | |
437 num_will_redirect_request_called_++; | |
438 } | |
439 | |
440 void NavigationSimulatorImpl::OnWillProcessResponse() { | |
441 num_will_process_response_called_++; | |
442 } | |
443 | |
444 } // namespace content | |
OLD | NEW |