Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1448)

Unified Diff: content/public/test/navigation_simulator.cc

Issue 2698393002: Allow asynchronous deferral in NavigationSimulator (Closed)
Patch Set: Just return the throttle check on Start/Redirect/COmmit Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/public/test/navigation_simulator.cc
diff --git a/content/public/test/navigation_simulator.cc b/content/public/test/navigation_simulator.cc
index 9cc1399bcf7da6050a8b26b6c019fdb51174dec9..309378dbb79bd4fbaabaefd513eef6dda1393000 100644
--- a/content/public/test/navigation_simulator.cc
+++ b/content/public/test/navigation_simulator.cc
@@ -4,7 +4,9 @@
#include "content/public/test/navigation_simulator.h"
-#include "content/browser/frame_host/navigation_handle_impl.h"
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
#include "content/browser/frame_host/navigation_request.h"
#include "content/common/frame_messages.h"
#include "content/public/browser/navigation_throttle.h"
@@ -61,6 +63,7 @@ void NavigationSimulator::NavigateAndCommitFromDocument(
NavigationSimulator simulator(
original_url, static_cast<TestRenderFrameHost*>(render_frame_host));
simulator.Commit();
+ simulator.WaitForThrottleChecksComplete();
}
// static
@@ -101,7 +104,7 @@ NavigationSimulator::NavigationSimulator(const GURL& original_url,
NavigationSimulator::~NavigationSimulator() {}
-void NavigationSimulator::Start() {
+NavigationThrottle::ThrottleCheckResult NavigationSimulator::Start() {
CHECK(state_ == INITIALIZATION)
<< "NavigationSimulator::Start should only be called once.";
state_ = STARTED;
@@ -123,7 +126,9 @@ void NavigationSimulator::Start() {
render_frame_host_->GetRoutingID(), common_params, begin_params));
NavigationRequest* request =
render_frame_host_->frame_tree_node()->navigation_request();
- DCHECK(request);
+ // The request failed synchronously.
+ if (!request)
+ return last_throttle_check_result_.value();
DCHECK_EQ(handle_, request->navigation_handle());
} else {
render_frame_host_->OnMessageReceived(
@@ -131,27 +136,32 @@ void NavigationSimulator::Start() {
render_frame_host_->OnMessageReceived(FrameHostMsg_DidStartProvisionalLoad(
render_frame_host_->GetRoutingID(), navigation_url_,
std::vector<GURL>(), base::TimeTicks::Now()));
+ DCHECK(handle_);
DCHECK_EQ(handle_, render_frame_host_->navigation_handle());
handle_->WillStartRequest(
"GET", scoped_refptr<content::ResourceRequestBodyImpl>(), referrer_,
true /* user_gesture */, transition_, false /* is_external_protocol */,
REQUEST_CONTEXT_TYPE_LOCATION,
blink::WebMixedContentContextType::NotMixedContent,
- base::Callback<void(NavigationThrottle::ThrottleCheckResult)>());
+ GenerateCompleteCallback());
}
-
CHECK(handle_);
+ return RunOrStoreThrottleCompleteCallback(base::Bind(
+ &NavigationSimulator::FinishStart, weak_factory_.GetWeakPtr()));
+}
- // Make sure all NavigationThrottles have run.
- // TODO(clamy): provide a non auto-advance mode if needed.
- while (handle_->state_for_testing() == NavigationHandleImpl::DEFERRING_START)
- handle_->Resume();
-
+void NavigationSimulator::FinishStart(
+ NavigationThrottle::ThrottleCheckResult result) {
CHECK_EQ(1, num_did_start_navigation_called_);
- CHECK_EQ(1, num_will_start_request_called_);
+ if (result == NavigationThrottle::PROCEED) {
+ CHECK_EQ(1, num_will_start_request_called_);
+ } else {
+ state_ = FAILED;
+ }
}
-void NavigationSimulator::Redirect(const GURL& new_url) {
+NavigationThrottle::ThrottleCheckResult NavigationSimulator::Redirect(
+ const GURL& new_url) {
CHECK(state_ <= STARTED) << "NavigationSimulator::Redirect should be "
"called before Fail or Commit";
CHECK_EQ(0, num_did_finish_navigation_called_)
@@ -159,7 +169,7 @@ void NavigationSimulator::Redirect(const GURL& new_url) {
"navigation has finished";
if (state_ == INITIALIZATION)
- Start();
+ StartAndExpectToProceed();
navigation_url_ = new_url;
@@ -168,9 +178,12 @@ void NavigationSimulator::Redirect(const GURL& new_url) {
int previous_did_redirect_navigation_called =
num_did_redirect_navigation_called_;
+ last_throttle_check_result_.reset();
if (IsBrowserSideNavigationEnabled()) {
NavigationRequest* request =
render_frame_host_->frame_tree_node()->navigation_request();
+ request->set_on_checks_complete_callback_for_testing(
+ GenerateCompleteCallback());
TestNavigationURLLoader* url_loader =
static_cast<TestNavigationURLLoader*>(request->loader_for_testing());
CHECK(url_loader);
@@ -190,24 +203,29 @@ void NavigationSimulator::Redirect(const GURL& new_url) {
handle_->WillRedirectRequest(
new_url, "GET", referrer_.url, false /* is_external_protocol */,
scoped_refptr<net::HttpResponseHeaders>(),
- net::HttpResponseInfo::ConnectionInfo(),
- base::Callback<void(NavigationThrottle::ThrottleCheckResult)>());
+ net::HttpResponseInfo::ConnectionInfo(), GenerateCompleteCallback());
}
+ return RunOrStoreThrottleCompleteCallback(base::Bind(
+ &NavigationSimulator::FinishRedirect, weak_factory_.GetWeakPtr(),
+ previous_num_will_redirect_request_called,
+ previous_did_redirect_navigation_called));
+}
- // Make sure all NavigationThrottles have run.
- // TODO(clamy): provide a non auto-advance mode if needed.
- while (handle_->state_for_testing() ==
- NavigationHandleImpl::DEFERRING_REDIRECT) {
- handle_->Resume();
+void NavigationSimulator::FinishRedirect(
+ int previous_num_will_redirect_request_called,
+ int previous_did_redirect_navigation_called,
+ NavigationThrottle::ThrottleCheckResult result) {
+ if (result == NavigationThrottle::PROCEED) {
+ CHECK_EQ(previous_num_will_redirect_request_called + 1,
+ num_will_redirect_request_called_);
+ CHECK_EQ(previous_did_redirect_navigation_called + 1,
+ num_did_redirect_navigation_called_);
+ } else {
+ state_ = FAILED;
}
-
- CHECK_EQ(previous_num_will_redirect_request_called + 1,
- num_will_redirect_request_called_);
- CHECK_EQ(previous_did_redirect_navigation_called + 1,
- num_did_redirect_navigation_called_);
}
-void NavigationSimulator::Commit() {
+NavigationThrottle::ThrottleCheckResult NavigationSimulator::Commit() {
CHECK_LE(state_, STARTED) << "NavigationSimulator::Commit can only be "
"called once, and cannot be called after "
"NavigationSimulator::Fail";
@@ -216,31 +234,39 @@ void NavigationSimulator::Commit() {
"navigation has finished";
if (state_ == INITIALIZATION)
- Start();
+ StartAndExpectToProceed();
- if (IsBrowserSideNavigationEnabled() &&
- render_frame_host_->frame_tree_node()->navigation_request()) {
- render_frame_host_->PrepareForCommit();
+ last_throttle_check_result_.reset();
+ if (IsBrowserSideNavigationEnabled()) {
+ NavigationRequest* request =
+ render_frame_host_->frame_tree_node()->navigation_request();
+ if (request) {
+ request->set_on_checks_complete_callback_for_testing(
+ GenerateCompleteCallback());
+ render_frame_host_->PrepareForCommit();
+ }
}
// Call NavigationHandle::WillProcessResponse if needed.
- if (handle_->state_for_testing() <
- NavigationHandleImpl::WILL_PROCESS_RESPONSE) {
+ // Note that the handle's state can be CANCELING if a throttle cancelled it
+ // synchronously in PrepareForCommit.
+ if (handle_->state_for_testing() < NavigationHandleImpl::CANCELING) {
handle_->WillProcessResponse(
render_frame_host_, scoped_refptr<net::HttpResponseHeaders>(),
net::HttpResponseInfo::ConnectionInfo(), SSLStatus(), GlobalRequestID(),
false /* should_replace_current_entry */, false /* is_download */,
- false /* is_stream */, base::Closure(),
- base::Callback<void(NavigationThrottle::ThrottleCheckResult)>());
+ false /* is_stream */, base::Closure(), GenerateCompleteCallback());
}
+ return RunOrStoreThrottleCompleteCallback(base::Bind(
+ &NavigationSimulator::FinishCommit, weak_factory_.GetWeakPtr()));
+}
- // Make sure all NavigationThrottles have run.
- // TODO(clamy): provide a non auto-advance mode if needed.
- while (handle_->state_for_testing() ==
- NavigationHandleImpl::DEFERRING_RESPONSE) {
- handle_->Resume();
+void NavigationSimulator::FinishCommit(
+ NavigationThrottle::ThrottleCheckResult result) {
+ if (result != NavigationThrottle::PROCEED) {
+ state_ = FAILED;
+ return;
}
-
CHECK_EQ(1, num_will_process_response_called_);
CHECK_EQ(1, num_ready_to_commit_called_);
@@ -310,7 +336,7 @@ void NavigationSimulator::Fail(int error_code) {
"navigation has finished";
if (state_ == INITIALIZATION)
- Start();
+ StartAndExpectToProceed();
state_ = FAILED;
@@ -446,6 +472,17 @@ void NavigationSimulator::SetReferrer(const Referrer& referrer) {
referrer_ = referrer;
}
+NavigationThrottle::ThrottleCheckResult
+NavigationSimulator::WaitForThrottleChecksComplete() {
+ if (!last_throttle_check_result_) {
+ base::RunLoop run_loop;
+ throttle_checks_wait_closure_ = run_loop.QuitClosure();
+ run_loop.Run();
+ throttle_checks_wait_closure_.Reset();
+ }
+ return last_throttle_check_result_.value();
+}
+
void NavigationSimulator::DidStartNavigation(
NavigationHandle* navigation_handle) {
// Check if this navigation is the one we're simulating.
@@ -475,6 +512,15 @@ void NavigationSimulator::DidStartNavigation(
weak_factory_.GetWeakPtr()),
base::Bind(&NavigationSimulator::OnWillProcessResponse,
weak_factory_.GetWeakPtr())));
+
+ if (IsBrowserSideNavigationEnabled()) {
clamy 2017/03/06 15:22:15 What do you think of the previous suggestion to st
Charlie Harrison 2017/03/06 20:18:43 Done.
+ NavigationRequest* request =
+ render_frame_host_->frame_tree_node()->navigation_request();
+ if (request) {
+ request->set_on_checks_complete_callback_for_testing(
+ GenerateCompleteCallback());
+ }
+ }
}
void NavigationSimulator::DidRedirectNavigation(
@@ -507,4 +553,55 @@ void NavigationSimulator::OnWillProcessResponse() {
num_will_process_response_called_++;
}
+// These methods are a little subtle. Overall, the design constraints are:
+// 1. Synchronous throttle checks should not cause subsequent
+// WaitForThrottleChecksComplete to block.
+//
+// 2. |complete_callback_| is called after all synchronous code is executed in
+// response to the throttle checks. This point is important because in some
+// cases (e.g. cancellation), the OnThrottleChecksComplete callback that the
+// NavigationRequest/NavigationHandle holds on to will be called before things
+// like navigation tear down and DidFinishNavigation. This code ensures that
+// |complete_callback_| is called after that occurs, either synchronously in
+// RunOrStoreThrottleCompleteCallback, or asynchronously in
+// OnThrottleChecksComplete.
+NavigationThrottle::ThrottleCheckResult
+NavigationSimulator::RunOrStoreThrottleCompleteCallback(
+ ThrottleChecksFinishedCallback finish_callback) {
+ // If completed the checks synchronously, call Finish* here. Else, save the
+ // callback to call asynchronously when the checks finish.
+ if (last_throttle_check_result_) {
+ finish_callback.Run(last_throttle_check_result_.value());
+ return last_throttle_check_result_.value();
+ }
+ complete_callback_ = std::move(finish_callback);
+ return NavigationThrottle::DEFER;
+}
+
+void NavigationSimulator::OnThrottleChecksComplete(
+ NavigationThrottle::ThrottleCheckResult result) {
+ // For synchronous throttle checks, set this here, and read from it downstream
+ // in RunOrStoreThrottleCompleteCallback.
+ DCHECK(!last_throttle_check_result_);
+ last_throttle_check_result_ = result;
+ if (!complete_callback_)
+ return;
+ BrowserThread::PostTaskAndReply(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(std::move(complete_callback_), result),
+ throttle_checks_wait_closure_);
+}
+
+ThrottleChecksFinishedCallback NavigationSimulator::GenerateCompleteCallback() {
+ return base::Bind(&NavigationSimulator::OnThrottleChecksComplete,
+ weak_factory_.GetWeakPtr());
+}
+
+void NavigationSimulator::StartAndExpectToProceed() {
+ NavigationThrottle::ThrottleCheckResult result = Start();
+ if (result == NavigationThrottle::DEFER)
+ result = WaitForThrottleChecksComplete();
+ CHECK_EQ(NavigationThrottle::PROCEED, result);
+}
+
} // namespace content

Powered by Google App Engine
This is Rietveld 408576698