Chromium Code Reviews| 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 |