[DevTools] Merge navigations control into requests interception

Bug: 546953, 702384
Change-Id: I73460b641d4083d615dfffb284aee8fd9cd1cdd7
Reviewed-on: https://chromium-review.googlesource.com/590348
Reviewed-by: Pavel Feldman <pfeldman@chromium.org>
Reviewed-by: Alex Clarke <alexclarke@chromium.org>
Commit-Queue: Dmitry Gozman <dgozman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#490912}
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 82c330ec..e3b7f64 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -536,8 +536,6 @@
     "devtools/devtools_url_request_interceptor.h",
     "devtools/forwarding_agent_host.cc",
     "devtools/forwarding_agent_host.h",
-    "devtools/page_navigation_throttle.cc",
-    "devtools/page_navigation_throttle.h",
     "devtools/protocol/devtools_domain_handler.cc",
     "devtools/protocol/devtools_domain_handler.h",
     "devtools/protocol/dom_handler.cc",
diff --git a/content/browser/devtools/devtools_url_interceptor_request_job.cc b/content/browser/devtools/devtools_url_interceptor_request_job.cc
index 9a8ddc7..39336af 100644
--- a/content/browser/devtools/devtools_url_interceptor_request_job.cc
+++ b/content/browser/devtools/devtools_url_interceptor_request_job.cc
@@ -65,31 +65,51 @@
   }
 }
 
-void SendRequestInterceptedEventOnUiThread(
+void UnregisterNavigationRequestOnUI(
     base::WeakPtr<protocol::NetworkHandler> network_handler,
-    std::string interception_id,
-    std::unique_ptr<protocol::Network::Request> network_request,
-    std::string resource_type) {
+    std::string interception_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!network_handler)
     return;
+  network_handler->InterceptedNavigationRequestFinished(interception_id);
+}
+
+void SendRequestInterceptedEventOnUiThread(
+    base::WeakPtr<protocol::NetworkHandler> network_handler,
+    std::string interception_id,
+    GlobalRequestID global_request_id,
+    std::unique_ptr<protocol::Network::Request> network_request,
+    ResourceType resource_type) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (!network_handler)
+    return;
+  bool is_navigation_request = resource_type == RESOURCE_TYPE_MAIN_FRAME ||
+                               resource_type == RESOURCE_TYPE_SUB_FRAME;
+  if (is_navigation_request) {
+    network_handler->InterceptedNavigationRequest(global_request_id,
+                                                  interception_id);
+  }
   network_handler->frontend()->RequestIntercepted(
-      interception_id, std::move(network_request), resource_type);
+      interception_id, std::move(network_request),
+      ResourceTypeToString(resource_type), is_navigation_request);
 }
 
 void SendRedirectInterceptedEventOnUiThread(
     base::WeakPtr<protocol::NetworkHandler> network_handler,
     std::string interception_id,
     std::unique_ptr<protocol::Network::Request> network_request,
-    std::string resource_type,
+    ResourceType resource_type,
     std::unique_ptr<protocol::Object> headers_object,
     int http_status_code,
     std::string redirect_url) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!network_handler)
     return;
-  return network_handler->frontend()->RequestIntercepted(
-      interception_id, std::move(network_request), resource_type,
+  bool is_navigation_request = resource_type == RESOURCE_TYPE_MAIN_FRAME ||
+                               resource_type == RESOURCE_TYPE_SUB_FRAME;
+  network_handler->frontend()->RequestIntercepted(
+      interception_id, std::move(network_request),
+      ResourceTypeToString(resource_type), is_navigation_request,
       std::move(headers_object), http_status_code, redirect_url);
 }
 
@@ -97,13 +117,16 @@
     base::WeakPtr<protocol::NetworkHandler> network_handler,
     std::string interception_id,
     std::unique_ptr<protocol::Network::Request> network_request,
-    std::string resource_type,
+    ResourceType resource_type,
     std::unique_ptr<protocol::Network::AuthChallenge> auth_challenge) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!network_handler)
     return;
+  bool is_navigation_request = resource_type == RESOURCE_TYPE_MAIN_FRAME ||
+                               resource_type == RESOURCE_TYPE_SUB_FRAME;
   network_handler->frontend()->RequestIntercepted(
-      interception_id, std::move(network_request), resource_type,
+      interception_id, std::move(network_request),
+      ResourceTypeToString(resource_type), is_navigation_request,
       protocol::Maybe<protocol::Network::Headers>(), protocol::Maybe<int>(),
       protocol::Maybe<protocol::String>(), std::move(auth_challenge));
 }
@@ -190,10 +213,21 @@
       resource_type_(resource_type),
       weak_ptr_factory_(this) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  if (const ResourceRequestInfo* info =
+          ResourceRequestInfo::ForRequest(original_request)) {
+    global_request_id_ = info->GetGlobalRequestID();
+  }
 }
 
 DevToolsURLInterceptorRequestJob::~DevToolsURLInterceptorRequestJob() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  bool is_navigation_request = resource_type_ == RESOURCE_TYPE_MAIN_FRAME ||
+                               resource_type_ == RESOURCE_TYPE_SUB_FRAME;
+  if (is_navigation_request) {
+    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                            base::Bind(UnregisterNavigationRequestOnUI,
+                                       network_handler_, interception_id_));
+  }
   devtools_url_request_interceptor_state_->JobFinished(interception_id_);
 }
 
@@ -220,8 +254,8 @@
     BrowserThread::PostTask(
         BrowserThread::UI, FROM_HERE,
         base::Bind(SendRequestInterceptedEventOnUiThread, network_handler_,
-                   interception_id_, base::Passed(&network_request),
-                   ResourceTypeToString(resource_type_)));
+                   interception_id_, global_request_id_,
+                   base::Passed(&network_request), resource_type_));
   }
 }
 
@@ -359,8 +393,7 @@
       BrowserThread::UI, FROM_HERE,
       base::Bind(SendAuthRequiredEventOnUiThread, network_handler_,
                  interception_id_, base::Passed(&network_request),
-                 ResourceTypeToString(resource_type_),
-                 base::Passed(&auth_challenge)));
+                 resource_type_, base::Passed(&auth_challenge)));
 }
 
 void DevToolsURLInterceptorRequestJob::OnCertificateRequested(
@@ -452,9 +485,8 @@
       BrowserThread::UI, FROM_HERE,
       base::Bind(SendRedirectInterceptedEventOnUiThread, network_handler_,
                  interception_id_, base::Passed(&network_request),
-                 ResourceTypeToString(resource_type_),
-                 base::Passed(&headers_object), redirectinfo.status_code,
-                 redirectinfo.new_url.spec()));
+                 resource_type_, base::Passed(&headers_object),
+                 redirectinfo.status_code, redirectinfo.new_url.spec()));
 }
 
 void DevToolsURLInterceptorRequestJob::StopIntercepting() {
diff --git a/content/browser/devtools/devtools_url_interceptor_request_job.h b/content/browser/devtools/devtools_url_interceptor_request_job.h
index 8ec210c..33d1a442 100644
--- a/content/browser/devtools/devtools_url_interceptor_request_job.h
+++ b/content/browser/devtools/devtools_url_interceptor_request_job.h
@@ -10,6 +10,7 @@
 #include "content/browser/devtools/devtools_url_request_interceptor.h"
 #include "content/browser/devtools/protocol/network.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/global_request_id.h"
 #include "content/public/common/resource_type.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_job.h"
@@ -199,6 +200,7 @@
   const base::WeakPtr<protocol::NetworkHandler> network_handler_;
   const bool is_redirect_;
   const ResourceType resource_type_;
+  GlobalRequestID global_request_id_;
   base::WeakPtrFactory<DevToolsURLInterceptorRequestJob> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(DevToolsURLInterceptorRequestJob);
diff --git a/content/browser/devtools/devtools_url_request_interceptor.cc b/content/browser/devtools/devtools_url_request_interceptor.cc
index de4f70f..ad7578a 100644
--- a/content/browser/devtools/devtools_url_request_interceptor.cc
+++ b/content/browser/devtools/devtools_url_request_interceptor.cc
@@ -185,19 +185,21 @@
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
   }
 
-  void RenderFrameCreated(RenderFrameHost* render_frame_host) override {
+  void RenderFrameHostChanged(RenderFrameHost* old_host,
+                              RenderFrameHost* new_host) override {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    if (old_host)
+      FrameDeleted(old_host);
     BrowserThread::PostTask(
         BrowserThread::IO, FROM_HERE,
-        base::BindOnce(&DevToolsURLRequestInterceptor::State::
-                           StartInterceptingRequestsInternal,
-                       state_, render_frame_host->GetRoutingID(),
-                       render_frame_host->GetFrameTreeNodeId(),
-                       render_frame_host->GetProcess()->GetID(), web_contents(),
-                       network_handler_));
+        base::BindOnce(
+            &DevToolsURLRequestInterceptor::State::
+                StartInterceptingRequestsInternal,
+            state_, new_host->GetRoutingID(), new_host->GetFrameTreeNodeId(),
+            new_host->GetProcess()->GetID(), web_contents(), network_handler_));
   }
 
-  void RenderFrameDeleted(RenderFrameHost* render_frame_host) override {
+  void FrameDeleted(RenderFrameHost* render_frame_host) override {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
     BrowserThread::PostTask(
         BrowserThread::IO, FROM_HERE,
diff --git a/content/browser/devtools/page_navigation_throttle.cc b/content/browser/devtools/page_navigation_throttle.cc
deleted file mode 100644
index bd73a5c63d..0000000
--- a/content/browser/devtools/page_navigation_throttle.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/devtools/page_navigation_throttle.h"
-
-#include "base/strings/stringprintf.h"
-#include "content/browser/devtools/protocol/page_handler.h"
-#include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/web_contents.h"
-
-namespace content {
-
-PageNavigationThrottle::PageNavigationThrottle(
-    base::WeakPtr<protocol::PageHandler> page_handler,
-    int navigation_id,
-    content::NavigationHandle* navigation_handle)
-    : content::NavigationThrottle(navigation_handle),
-      navigation_id_(navigation_id),
-      page_handler_(page_handler),
-      navigation_deferred_(false) {}
-
-PageNavigationThrottle::~PageNavigationThrottle() {
-  if (page_handler_)
-    page_handler_->OnPageNavigationThrottleDisposed(navigation_id_);
-}
-
-NavigationThrottle::ThrottleCheckResult
-PageNavigationThrottle::WillStartRequest() {
-  if (!page_handler_)
-    return ThrottleCheckResult::PROCEED;
-  navigation_deferred_ = true;
-  page_handler_->NavigationRequested(this);
-  return ThrottleCheckResult::DEFER;
-}
-
-NavigationThrottle::ThrottleCheckResult
-PageNavigationThrottle::WillRedirectRequest() {
-  if (!page_handler_)
-    return ThrottleCheckResult::PROCEED;
-  navigation_deferred_ = true;
-  page_handler_->NavigationRequested(this);
-  return ThrottleCheckResult::DEFER;
-}
-
-const char* PageNavigationThrottle::GetNameForLogging() {
-  return "PageNavigationThrottle";
-}
-
-void PageNavigationThrottle::AlwaysProceed() {
-  // Makes WillStartRequest and WillRedirectRequest always return
-  // ThrottleCheckResult::PROCEED.
-  page_handler_.reset();
-  Resume();
-}
-
-// Resumes a deferred navigation request. Does nothing if a response isn't
-// expected.
-void PageNavigationThrottle::Resume() {
-  if (!navigation_deferred_)
-    return;
-  navigation_deferred_ = false;
-  content::NavigationThrottle::Resume();
-
-  // Do not add code after this as the PageNavigationThrottle may be deleted by
-  // the line above.
-}
-
-// Cancels a deferred navigation request. Does nothing if a response isn't
-// expected.
-void PageNavigationThrottle::CancelDeferredNavigation(
-    NavigationThrottle::ThrottleCheckResult result) {
-  if (!navigation_deferred_)
-    return;
-  navigation_deferred_ = false;
-  content::NavigationThrottle::CancelDeferredNavigation(result);
-
-  // Do not add code after this as the PageNavigationThrottle may be deleted by
-  // the line above.
-}
-
-}  // namespace content
diff --git a/content/browser/devtools/page_navigation_throttle.h b/content/browser/devtools/page_navigation_throttle.h
deleted file mode 100644
index 6fd23f0..0000000
--- a/content/browser/devtools/page_navigation_throttle.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_DEVTOOLS_PAGE_NAVIGATION_THROTTLE_H_
-#define CONTENT_BROWSER_DEVTOOLS_PAGE_NAVIGATION_THROTTLE_H_
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "content/public/browser/navigation_throttle.h"
-
-namespace content {
-namespace protocol {
-class PageHandler;
-}  // namespace protocol
-
-// Used to allow the DevTools client to optionally cancel navigations via the
-// Page.setControlNavigations and Page.processNavigation commands.
-class PageNavigationThrottle : public content::NavigationThrottle {
- public:
-  PageNavigationThrottle(base::WeakPtr<protocol::PageHandler> page_handler,
-                         int navigation_id,
-                         content::NavigationHandle* navigation_handle);
-  ~PageNavigationThrottle() override;
-
-  // content::NavigationThrottle implementation:
-  NavigationThrottle::ThrottleCheckResult WillStartRequest() override;
-  NavigationThrottle::ThrottleCheckResult WillRedirectRequest() override;
-  const char* GetNameForLogging() override;
-  void Resume() override;
-  void CancelDeferredNavigation(
-      NavigationThrottle::ThrottleCheckResult result) override;
-
-  int navigation_id() const { return navigation_id_; }
-
-  // Tells the PageNavigationThrottle to not throttle anything!
-  void AlwaysProceed();
-
- private:
-  // An opaque ID assigned by the PageHandler, used to allow the protocol client
-  // to refer to this navigation throttle.
-  const int navigation_id_;
-
-  // The PageHandler that this navigation throttle is associated with.
-  base::WeakPtr<protocol::PageHandler> page_handler_;
-
-  // Whether or not a navigation was deferred. If deferred we expect a
-  // subsequent call to AlwaysProceed, Resume or CancelNavigationIfDeferred.
-  bool navigation_deferred_;
-
-  DISALLOW_COPY_AND_ASSIGN(PageNavigationThrottle);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_DEVTOOLS_PAGE_NAVIGATION_THROTTLE_H_
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index 2345158..0e05c55 100644
--- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -274,9 +274,8 @@
 
   struct ExpectedNavigation {
     std::string url;
-    bool is_in_main_frame;
     bool is_redirect;
-    std::string navigation_response;
+    bool abort;
   };
 
   std::string RemovePort(const GURL& url) {
@@ -286,48 +285,57 @@
   }
 
   // Waits for the expected navigations to occur in any order. If an expected
-  // navigation occurs, Page.processNavigation is called with the specified
-  // navigation_response to either allow it to proceed or to cancel it.
+  // navigation occurs, Network.continueInterceptedRequest is called with the
+  // specified navigation_response to either allow it to proceed or to cancel
+  // it.
   void ProcessNavigationsAnyOrder(
       std::vector<ExpectedNavigation> expected_navigations) {
+    std::unique_ptr<base::DictionaryValue> params;
     while (!expected_navigations.empty()) {
       std::unique_ptr<base::DictionaryValue> params =
-          WaitForNotification("Page.navigationRequested");
+          WaitForNotification("Network.requestIntercepted");
 
+      std::string interception_id;
+      ASSERT_TRUE(params->GetString("interceptionId", &interception_id));
+      bool is_redirect = params->HasKey("redirectUrl");
+      bool is_navigation;
+      ASSERT_TRUE(params->GetBoolean("isNavigationRequest", &is_navigation));
+      std::string resource_type;
+      ASSERT_TRUE(params->GetString("resourceType", &resource_type));
       std::string url;
-      ASSERT_TRUE(params->GetString("url", &url));
-
+      ASSERT_TRUE(params->GetString("request.url", &url));
+      if (is_redirect)
+        ASSERT_TRUE(params->GetString("redirectUrl", &url));
       // The url will typically have a random port which we want to remove.
       url = RemovePort(GURL(url));
 
-      int navigation_id;
-      ASSERT_TRUE(params->GetInteger("navigationId", &navigation_id));
-      bool is_in_main_frame;
-      ASSERT_TRUE(params->GetBoolean( "isInMainFrame", &is_in_main_frame));
-      bool is_redirect;
-      ASSERT_TRUE(params->GetBoolean("isRedirect", &is_redirect));
+      if (!is_navigation) {
+        params.reset(new base::DictionaryValue());
+        params->SetString("interceptionId", interception_id);
+        SendCommand("Network.continueInterceptedRequest", std::move(params),
+                    false);
+        continue;
+      }
 
-      bool navigation_was_expected;
+      bool navigation_was_expected = false;
       for (auto it = expected_navigations.begin();
            it != expected_navigations.end(); it++) {
-        if (url != it->url || is_in_main_frame != it->is_in_main_frame ||
-            is_redirect != it->is_redirect) {
+        if (url != it->url || is_redirect != it->is_redirect)
           continue;
-        }
 
-        std::unique_ptr<base::DictionaryValue> process_params(
-            new base::DictionaryValue());
-        process_params->SetString("response", it->navigation_response);
-        process_params->SetInteger("navigationId", navigation_id);
-        SendCommand("Page.processNavigation", std::move(process_params), false);
+        params.reset(new base::DictionaryValue());
+        params->SetString("interceptionId", interception_id);
+        if (it->abort)
+          params->SetString("errorReason", "Aborted");
+        SendCommand("Network.continueInterceptedRequest", std::move(params),
+                    false);
 
         navigation_was_expected = true;
         expected_navigations.erase(it);
         break;
       }
       EXPECT_TRUE(navigation_was_expected)
-          << "url = " << url << "is_in_main_frame = " << is_in_main_frame
-          << "is_redirect = " << is_redirect;
+          << "url = " << url << "is_redirect = " << is_redirect;
     }
   }
 
@@ -1274,20 +1282,20 @@
   ASSERT_TRUE(embedded_test_server()->Start());
 
   // Navigate to about:blank first so we can make sure there is a target page we
-  // can attach to, and have Page.setControlNavigations complete before we start
-  // the navigations we're interested in.
+  // can attach to, and have Network.setRequestInterceptionEnabled complete
+  // before we start the navigations we're interested in.
   NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1);
   Attach();
 
   std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue());
   params->SetBoolean("enabled", true);
-  SendCommand("Page.setControlNavigations", std::move(params), true);
+  SendCommand("Network.setRequestInterceptionEnabled", std::move(params), true);
 
   LoadFinishedObserver load_finished_observer(shell()->web_contents());
 
   // The page will try to navigate twice, however since
-  // Page.setControlNavigations is true, it'll wait for confirmation before
-  // committing to the navigation.
+  // Network.setRequestInterceptionEnabled is true,
+  // it'll wait for confirmation before committing to the navigation.
   GURL test_url = embedded_test_server()->GetURL(
       "/devtools/control_navigations/meta_tag.html");
   shell()->LoadURL(test_url);
@@ -1303,14 +1311,14 @@
   ASSERT_TRUE(embedded_test_server()->Start());
 
   // Navigate to about:blank first so we can make sure there is a target page we
-  // can attach to, and have Page.setControlNavigations complete before we start
-  // the navigations we're interested in.
+  // can attach to, and have Network.setRequestInterceptionEnabled complete
+  // before we start the navigations we're interested in.
   NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1);
   Attach();
 
   std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue());
   params->SetBoolean("enabled", true);
-  SendCommand("Page.setControlNavigations", std::move(params), true);
+  SendCommand("Network.setRequestInterceptionEnabled", std::move(params), true);
 
   NavigationFinishedObserver navigation_finished_observer(
       shell()->web_contents());
@@ -1321,11 +1329,9 @@
 
   std::vector<ExpectedNavigation> expected_navigations = {
       {"http://127.0.0.1/devtools/control_navigations/meta_tag.html",
-       true /* expected_is_in_main_frame */, false /* expected_is_redirect */,
-       "Proceed"},
+       false /* expected_is_redirect */, false /* abort */},
       {"http://127.0.0.1/devtools/navigation.html",
-       true /* expected_is_in_main_frame */, false /* expected_is_redirect */,
-       "Cancel"}};
+       false /* expected_is_redirect */, true /* abort */}};
 
   ProcessNavigationsAnyOrder(std::move(expected_navigations));
 
@@ -1355,14 +1361,14 @@
   ASSERT_TRUE(embedded_test_server()->Start());
 
   // Navigate to about:blank first so we can make sure there is a target page we
-  // can attach to, and have Page.setControlNavigations complete before we start
-  // the navigations we're interested in.
+  // can attach to, and have Network.setRequestInterceptionEnabled complete
+  // before we start the navigations we're interested in.
   NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1);
   Attach();
 
   std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue());
   params->SetBoolean("enabled", true);
-  SendCommand("Page.setControlNavigations", std::move(params), true);
+  SendCommand("Network.setRequestInterceptionEnabled", std::move(params), true);
 
   NavigationFinishedObserver navigation_finished_observer(
       shell()->web_contents());
@@ -1377,28 +1383,21 @@
   std::vector<ExpectedNavigation> expected_navigations = {
       {"http://127.0.0.1/devtools/control_navigations/"
        "iframe_navigation.html",
-       /* expected_is_in_main_frame */ true,
-       /* expected_is_redirect */ false, "Proceed"},
+       false /* expected_is_redirect */, false /* abort */},
       {"http://127.0.0.1/cross-site/a.com/devtools/control_navigations/"
        "meta_tag.html",
-       /* expected_is_in_main_frame */ false,
-       /* expected_is_redirect */ false, "Proceed"},
+       false /* expected_is_redirect */, false /* abort */},
       {"http://127.0.0.1/cross-site/b.com/devtools/control_navigations/"
        "meta_tag.html",
-       /* expected_is_in_main_frame */ false,
-       /* expected_is_redirect */ false, "Proceed"},
+       false /* expected_is_redirect */, false /* abort */},
       {"http://a.com/devtools/control_navigations/meta_tag.html",
-       /* expected_is_in_main_frame */ false,
-       /* expected_is_redirect */ true, "Proceed"},
+       true /* expected_is_redirect */, false /* abort */},
       {"http://b.com/devtools/control_navigations/meta_tag.html",
-       /* expected_is_in_main_frame */ false,
-       /* expected_is_redirect */ true, "Proceed"},
+       true /* expected_is_redirect */, false /* abort */},
       {"http://a.com/devtools/navigation.html",
-       /* expected_is_in_main_frame */ false,
-       /* expected_is_redirect */ false, "Proceed"},
+       false /* expected_is_redirect */, false /* abort */},
       {"http://b.com/devtools/navigation.html",
-       /* expected_is_in_main_frame */ false,
-       /* expected_is_redirect */ false, "Cancel"}};
+       false /* expected_is_redirect */, true /* abort */}};
 
   ProcessNavigationsAnyOrder(std::move(expected_navigations));
 
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
index bff4f04c..467d7e1 100644
--- a/content/browser/devtools/protocol/network_handler.cc
+++ b/content/browser/devtools/protocol/network_handler.cc
@@ -26,6 +26,8 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/browsing_data_remover.h"
 #include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/global_request_id.h"
+#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/resource_context.h"
 #include "content/public/browser/site_instance.h"
@@ -376,7 +378,8 @@
   return Security::SecurityStateEnum::Secure;
 }
 
-net::Error NetErrorFromString(const std::string& error) {
+net::Error NetErrorFromString(const std::string& error, bool* ok) {
+  *ok = true;
   if (error == Network::ErrorReasonEnum::Failed)
     return net::ERR_FAILED;
   if (error == Network::ErrorReasonEnum::Aborted)
@@ -401,6 +404,7 @@
     return net::ERR_INTERNET_DISCONNECTED;
   if (error == Network::ErrorReasonEnum::AddressUnreachable)
     return net::ERR_ADDRESS_UNREACHABLE;
+  *ok = false;
   return net::ERR_FAILED;
 }
 
@@ -472,6 +476,34 @@
   return protocol;
 }
 
+class NetworkNavigationThrottle : public content::NavigationThrottle {
+ public:
+  NetworkNavigationThrottle(
+      base::WeakPtr<protocol::NetworkHandler> network_handler,
+      content::NavigationHandle* navigation_handle)
+      : content::NavigationThrottle(navigation_handle),
+        network_handler_(network_handler) {}
+
+  ~NetworkNavigationThrottle() override {}
+
+  // content::NavigationThrottle implementation:
+  NavigationThrottle::ThrottleCheckResult WillProcessResponse() override {
+    if (network_handler_ && network_handler_->ShouldCancelNavigation(
+                                navigation_handle()->GetGlobalRequestID())) {
+      return ThrottleCheckResult::CANCEL_AND_IGNORE;
+    }
+    return ThrottleCheckResult::PROCEED;
+  }
+
+  const char* GetNameForLogging() override {
+    return "DevToolsNetworkNavigationThrottle";
+  }
+
+ private:
+  base::WeakPtr<protocol::NetworkHandler> network_handler_;
+  DISALLOW_COPY_AND_ASSIGN(NetworkNavigationThrottle);
+};
+
 }  // namespace
 
 NetworkHandler::NetworkHandler()
@@ -847,6 +879,8 @@
   } else {
     devtools_url_request_interceptor->state()->StopInterceptingRequests(
         web_contents);
+    navigation_requests_.clear();
+    canceled_navigation_requests_.clear();
   }
   interception_enabled_ = enabled;
   return Response::OK();
@@ -895,10 +929,6 @@
     return;
   }
 
-  base::Optional<net::Error> error;
-  if (error_reason.isJust())
-    error = NetErrorFromString(error_reason.fromJust());
-
   base::Optional<std::string> raw_response;
   if (base64_raw_response.isJust()) {
     std::string decoded;
@@ -909,6 +939,27 @@
     raw_response = decoded;
   }
 
+  base::Optional<net::Error> error;
+  if (error_reason.isJust()) {
+    bool ok;
+    error = NetErrorFromString(error_reason.fromJust(), &ok);
+    if (!ok) {
+      callback->sendFailure(Response::InvalidParams("Invalid errorReason."));
+      return;
+    }
+
+    if (error_reason.fromJust() == Network::ErrorReasonEnum::Aborted) {
+      auto it = navigation_requests_.find(interception_id);
+      if (it != navigation_requests_.end()) {
+        canceled_navigation_requests_.insert(it->second);
+        // To successfully cancel navigation the request must succeed. We
+        // provide simple mock response to avoid pointless network fetch.
+        error.reset();
+        raw_response = std::string("HTTP/1.1 200 OK\r\n\r\n");
+      }
+    }
+  }
+
   devtools_url_request_interceptor->state()->ContinueInterceptedRequest(
       interception_id,
       base::MakeUnique<DevToolsURLRequestInterceptor::Modifications>(
@@ -940,5 +991,34 @@
   return request_object;
 }
 
+std::unique_ptr<NavigationThrottle> NetworkHandler::CreateThrottleForNavigation(
+    NavigationHandle* navigation_handle) {
+  if (!interception_enabled_)
+    return nullptr;
+  std::unique_ptr<NavigationThrottle> throttle(new NetworkNavigationThrottle(
+      weak_factory_.GetWeakPtr(), navigation_handle));
+  return throttle;
+}
+
+void NetworkHandler::InterceptedNavigationRequest(
+    const GlobalRequestID& global_request_id,
+    const std::string& interception_id) {
+  navigation_requests_[interception_id] = global_request_id;
+}
+
+void NetworkHandler::InterceptedNavigationRequestFinished(
+    const std::string& interception_id) {
+  navigation_requests_.erase(interception_id);
+}
+
+bool NetworkHandler::ShouldCancelNavigation(
+    const GlobalRequestID& global_request_id) {
+  auto it = canceled_navigation_requests_.find(global_request_id);
+  if (it == canceled_navigation_requests_.end())
+    return false;
+  canceled_navigation_requests_.erase(it);
+  return true;
+}
+
 }  // namespace protocol
 }  // namespace content
diff --git a/content/browser/devtools/protocol/network_handler.h b/content/browser/devtools/protocol/network_handler.h
index f0d64c9..e96b7cb 100644
--- a/content/browser/devtools/protocol/network_handler.h
+++ b/content/browser/devtools/protocol/network_handler.h
@@ -7,6 +7,8 @@
 
 #include <memory>
 
+#include "base/containers/flat_map.h"
+#include "base/containers/flat_set.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "content/browser/devtools/protocol/devtools_domain_handler.h"
@@ -24,6 +26,9 @@
 class RenderFrameHostImpl;
 struct BeginNavigationParams;
 struct CommonNavigationParams;
+struct GlobalRequestID;
+class NavigationHandle;
+class NavigationThrottle;
 struct ResourceRequest;
 struct ResourceRequestCompletionStatus;
 struct ResourceResponseHead;
@@ -104,12 +109,21 @@
   static std::unique_ptr<Network::Request> CreateRequestFromURLRequest(
       const net::URLRequest* request);
 
+  std::unique_ptr<NavigationThrottle> CreateThrottleForNavigation(
+      NavigationHandle* navigation_handle);
+  void InterceptedNavigationRequest(const GlobalRequestID& global_request_id,
+                                    const std::string& interception_id);
+  void InterceptedNavigationRequestFinished(const std::string& interception_id);
+  bool ShouldCancelNavigation(const GlobalRequestID& global_request_id);
+
  private:
   std::unique_ptr<Network::Frontend> frontend_;
   RenderFrameHostImpl* host_;
   bool enabled_;
   bool interception_enabled_;
   std::string user_agent_;
+  base::flat_map<std::string, GlobalRequestID> navigation_requests_;
+  base::flat_set<GlobalRequestID> canceled_navigation_requests_;
   base::WeakPtrFactory<NetworkHandler> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(NetworkHandler);
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc
index 7d2a2ba..7d2b870 100644
--- a/content/browser/devtools/protocol/page_handler.cc
+++ b/content/browser/devtools/protocol/page_handler.cc
@@ -21,7 +21,6 @@
 #include "base/task_scheduler/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/browser/devtools/devtools_session.h"
-#include "content/browser/devtools/page_navigation_throttle.h"
 #include "content/browser/devtools/protocol/emulation_handler.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
@@ -107,8 +106,6 @@
       session_id_(0),
       frame_counter_(0),
       frames_in_flight_(0),
-      navigation_throttle_enabled_(false),
-      next_navigation_id_(0),
       host_(nullptr),
       emulation_handler_(emulation_handler),
       weak_factory_(this) {
@@ -211,7 +208,6 @@
 Response PageHandler::Disable() {
   enabled_ = false;
   screencast_enabled_ = false;
-  SetControlNavigations(false);
   return Response::FallThrough();
 }
 
@@ -542,38 +538,6 @@
   return Response::OK();
 }
 
-Response PageHandler::SetControlNavigations(bool enabled) {
-  navigation_throttle_enabled_ = enabled;
-  // We don't own the page PageNavigationThrottles so we can't delete them, but
-  // we can turn them into NOPs.
-  for (auto& pair : navigation_throttles_) {
-    pair.second->AlwaysProceed();
-  }
-  navigation_throttles_.clear();
-  return Response::OK();
-}
-
-Response PageHandler::ProcessNavigation(const std::string& response,
-                                        int navigation_id) {
-  auto it = navigation_throttles_.find(navigation_id);
-  if (it == navigation_throttles_.end())
-    return Response::InvalidParams("Unknown navigation id");
-
-  if (response == Page::NavigationResponseEnum::Proceed) {
-    it->second->Resume();
-    return Response::OK();
-  } else if (response == Page::NavigationResponseEnum::Cancel) {
-    it->second->CancelDeferredNavigation(content::NavigationThrottle::CANCEL);
-    return Response::OK();
-  } else if (response == Page::NavigationResponseEnum::CancelAndIgnore) {
-    it->second->CancelDeferredNavigation(
-        content::NavigationThrottle::CANCEL_AND_IGNORE);
-    return Response::OK();
-  }
-
-  return Response::InvalidParams("Unrecognized response");
-}
-
 Response PageHandler::BringToFront() {
   WebContentsImpl* wc = GetWebContents();
   if (wc) {
@@ -583,32 +547,6 @@
   return Response::InternalError();
 }
 
-std::unique_ptr<PageNavigationThrottle>
-PageHandler::CreateThrottleForNavigation(NavigationHandle* navigation_handle) {
-  if (!navigation_throttle_enabled_)
-    return nullptr;
-
-  std::unique_ptr<PageNavigationThrottle> throttle(new PageNavigationThrottle(
-      weak_factory_.GetWeakPtr(), next_navigation_id_, navigation_handle));
-  navigation_throttles_[next_navigation_id_++] = throttle.get();
-  return throttle;
-}
-
-void PageHandler::OnPageNavigationThrottleDisposed(int navigation_id) {
-  DCHECK(navigation_throttles_.find(navigation_id) !=
-         navigation_throttles_.end());
-  navigation_throttles_.erase(navigation_id);
-}
-
-void PageHandler::NavigationRequested(const PageNavigationThrottle* throttle) {
-  NavigationHandle* navigation_handle = throttle->navigation_handle();
-  frontend_->NavigationRequested(
-      navigation_handle->IsInMainFrame(),
-      navigation_handle->WasServerRedirect(),
-      throttle->navigation_id(),
-      navigation_handle->GetURL().spec());
-}
-
 WebContentsImpl* PageHandler::GetWebContents() {
   return host_ ?
       static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost(host_)) :
diff --git a/content/browser/devtools/protocol/page_handler.h b/content/browser/devtools/protocol/page_handler.h
index ea995ef..5114d0b 100644
--- a/content/browser/devtools/protocol/page_handler.h
+++ b/content/browser/devtools/protocol/page_handler.h
@@ -35,8 +35,6 @@
 namespace content {
 
 class DevToolsAgentHostImpl;
-class NavigationHandle;
-class PageNavigationThrottle;
 class RenderFrameHostImpl;
 class WebContentsImpl;
 
@@ -111,17 +109,8 @@
 
   Response RequestAppBanner() override;
 
-  Response SetControlNavigations(bool enabled) override;
-  Response ProcessNavigation(const std::string& response,
-                             int navigation_id) override;
   Response BringToFront() override;
 
-  std::unique_ptr<PageNavigationThrottle> CreateThrottleForNavigation(
-      NavigationHandle* navigation_handle);
-
-  void OnPageNavigationThrottleDisposed(int navigation_id);
-  void NavigationRequested(const PageNavigationThrottle* throttle);
-
  private:
   enum EncodingFormat { PNG, JPEG };
 
@@ -164,10 +153,6 @@
   int frame_counter_;
   int frames_in_flight_;
 
-  bool navigation_throttle_enabled_;
-  int next_navigation_id_;
-  std::map<int, PageNavigationThrottle*> navigation_throttles_;
-
   RenderFrameHostImpl* host_;
   EmulationHandler* emulation_handler_;
   std::unique_ptr<Page::Frontend> frontend_;
diff --git a/content/browser/devtools/protocol_config.json b/content/browser/devtools/protocol_config.json
index 1125e1c5f..2eed0a0 100644
--- a/content/browser/devtools/protocol_config.json
+++ b/content/browser/devtools/protocol_config.json
@@ -48,8 +48,8 @@
                 "domain": "Page",
                 "include": ["enable", "disable", "reload", "navigate", "stopLoading", "getNavigationHistory", "navigateToHistoryEntry", "captureScreenshot",
                     "startScreencast", "stopScreencast", "screencastFrameAck", "handleJavaScriptDialog", "setColorPickerEnabled", "requestAppBanner",
-                    "setControlNavigations", "processNavigation", "printToPDF", "bringToFront"],
-                "include_events": ["interstitialShown", "interstitialHidden", "navigationRequested", "screencastVisibilityChanged", "screencastFrame", "colorPicked"],
+                    "printToPDF", "bringToFront"],
+                "include_events": ["interstitialShown", "interstitialHidden", "screencastVisibilityChanged", "screencastFrame", "colorPicked"],
                 "async": ["captureScreenshot", "printToPDF"]
             },
             {
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index 6de1f99bf..8712acd 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -18,7 +18,6 @@
 #include "content/browser/devtools/devtools_frame_trace_recorder.h"
 #include "content/browser/devtools/devtools_manager.h"
 #include "content/browser/devtools/devtools_session.h"
-#include "content/browser/devtools/page_navigation_throttle.h"
 #include "content/browser/devtools/protocol/dom_handler.h"
 #include "content/browser/devtools/protocol/emulation_handler.h"
 #include "content/browser/devtools/protocol/input_handler.h"
@@ -355,14 +354,14 @@
     frame_tree_node = frame_tree_node->parent();
   }
   RenderFrameDevToolsAgentHost* agent_host = FindAgentHost(frame_tree_node);
-  // Note Page.setControlNavigations is intended to control navigations in the
-  // main frame and all child frames and |page_handler_| only exists for the
-  // main frame.
+  // Note Network.setRequestInterceptionEnabled is intended to control
+  // navigations in the main frame and all child frames.
   if (!agent_host)
     return nullptr;
-  for (auto* page_handler : protocol::PageHandler::ForAgentHost(agent_host)) {
+  for (auto* network_handler :
+       protocol::NetworkHandler::ForAgentHost(agent_host)) {
     std::unique_ptr<NavigationThrottle> throttle =
-        page_handler->CreateThrottleForNavigation(navigation_handle);
+        network_handler->CreateThrottleForNavigation(navigation_handle);
     if (throttle)
       return throttle;
   }
diff --git a/headless/app/headless_shell.cc b/headless/app/headless_shell.cc
index b7bb09c..1ecf4cc 100644
--- a/headless/app/headless_shell.cc
+++ b/headless/app/headless_shell.cc
@@ -169,10 +169,12 @@
 
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDeterministicFetch)) {
-    devtools_client_->GetPage()->GetExperimental()->SetControlNavigations(
-        headless::page::SetControlNavigationsParams::Builder()
-            .SetEnabled(true)
-            .Build());
+    devtools_client_->GetNetwork()
+        ->GetExperimental()
+        ->SetRequestInterceptionEnabled(
+            headless::network::SetRequestInterceptionEnabledParams::Builder()
+                .SetEnabled(true)
+                .Build());
   }
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDefaultBackgroundColor)) {
@@ -288,11 +290,19 @@
   OnPageReady();
 }
 
-void HeadlessShell::OnNavigationRequested(
-    const headless::page::NavigationRequestedParams& params) {
-  deterministic_dispatcher_->NavigationRequested(
-      base::MakeUnique<ShellNavigationRequest>(weak_factory_.GetWeakPtr(),
-                                               params));
+// network::Observer implementation:
+void HeadlessShell::OnRequestIntercepted(
+    const headless::network::RequestInterceptedParams& params) {
+  if (params.GetIsNavigationRequest()) {
+    deterministic_dispatcher_->NavigationRequested(
+        base::MakeUnique<ShellNavigationRequest>(weak_factory_.GetWeakPtr(),
+                                                 params));
+    return;
+  }
+  devtools_client_->GetNetwork()->GetExperimental()->ContinueInterceptedRequest(
+      headless::network::ContinueInterceptedRequestParams::Builder()
+          .SetInterceptionId(params.GetInterceptionId())
+          .Build());
 }
 
 void HeadlessShell::OnPageReady() {
diff --git a/headless/app/headless_shell.h b/headless/app/headless_shell.h
index 4aef3fd6..18092fc 100644
--- a/headless/app/headless_shell.h
+++ b/headless/app/headless_shell.h
@@ -28,7 +28,8 @@
 class HeadlessShell : public HeadlessWebContents::Observer,
                       public emulation::ExperimentalObserver,
                       public inspector::ExperimentalObserver,
-                      public page::ExperimentalObserver {
+                      public page::ExperimentalObserver,
+                      public network::ExperimentalObserver {
  public:
   HeadlessShell();
   ~HeadlessShell() override;
@@ -50,8 +51,10 @@
 
   // page::Observer implementation:
   void OnLoadEventFired(const page::LoadEventFiredParams& params) override;
-  void OnNavigationRequested(
-      const headless::page::NavigationRequestedParams& params) override;
+
+  // network::Observer implementation:
+  void OnRequestIntercepted(
+      const headless::network::RequestInterceptedParams& params) override;
 
   virtual void Shutdown();
 
diff --git a/headless/app/shell_navigation_request.cc b/headless/app/shell_navigation_request.cc
index 3c419bce..b63ba4e 100644
--- a/headless/app/shell_navigation_request.cc
+++ b/headless/app/shell_navigation_request.cc
@@ -10,9 +10,9 @@
 
 ShellNavigationRequest::ShellNavigationRequest(
     base::WeakPtr<HeadlessShell> headless_shell,
-    const page::NavigationRequestedParams& params)
+    const network::RequestInterceptedParams& params)
     : headless_shell_(headless_shell),
-      navigation_id_(params.GetNavigationId()) {}
+      interception_id_(params.GetInterceptionId()) {}
 
 ShellNavigationRequest::~ShellNavigationRequest() {}
 
@@ -22,21 +22,20 @@
 
   // Allow the navigation to proceed.
   headless_shell_->devtools_client()
-      ->GetPage()
+      ->GetNetwork()
       ->GetExperimental()
-      ->ProcessNavigation(
-          headless::page::ProcessNavigationParams::Builder()
-              .SetNavigationId(navigation_id_)
-              .SetResponse(headless::page::NavigationResponse::PROCEED)
+      ->ContinueInterceptedRequest(
+          headless::network::ContinueInterceptedRequestParams::Builder()
+              .SetInterceptionId(interception_id_)
               .Build(),
-          base::Bind(&ShellNavigationRequest::ProcessNavigationResult,
+          base::Bind(&ShellNavigationRequest::ContinueInterceptedRequestResult,
                      done_callback));
 }
 
 // static
-void ShellNavigationRequest::ProcessNavigationResult(
+void ShellNavigationRequest::ContinueInterceptedRequestResult(
     base::Closure done_callback,
-    std::unique_ptr<page::ProcessNavigationResult>) {
+    std::unique_ptr<network::ContinueInterceptedRequestResult>) {
   done_callback.Run();
 }
 
diff --git a/headless/app/shell_navigation_request.h b/headless/app/shell_navigation_request.h
index 20ef77f..1199f28 100644
--- a/headless/app/shell_navigation_request.h
+++ b/headless/app/shell_navigation_request.h
@@ -8,7 +8,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "headless/public/devtools/domains/page.h"
+#include "headless/public/devtools/domains/network.h"
 #include "headless/public/util/navigation_request.h"
 
 namespace headless {
@@ -19,7 +19,7 @@
 class ShellNavigationRequest : public NavigationRequest {
  public:
   ShellNavigationRequest(base::WeakPtr<HeadlessShell> headless_shell,
-                         const page::NavigationRequestedParams& params);
+                         const network::RequestInterceptedParams& params);
 
   ~ShellNavigationRequest() override;
 
@@ -28,12 +28,12 @@
  private:
   // Note the navigation likely isn't done when this is called, however we
   // expect it will have been committed and the initial resource load requested.
-  static void ProcessNavigationResult(
+  static void ContinueInterceptedRequestResult(
       base::Closure done_callback,
-      std::unique_ptr<page::ProcessNavigationResult>);
+      std::unique_ptr<network::ContinueInterceptedRequestResult>);
 
   base::WeakPtr<HeadlessShell> headless_shell_;
-  int navigation_id_;
+  std::string interception_id_;
 };
 
 }  // namespace headless
diff --git a/headless/lib/headless_devtools_client_browsertest.cc b/headless/lib/headless_devtools_client_browsertest.cc
index cd8ffc7..67119a0 100644
--- a/headless/lib/headless_devtools_client_browsertest.cc
+++ b/headless/lib/headless_devtools_client_browsertest.cc
@@ -897,33 +897,40 @@
 
 class HeadlessDevToolsNavigationControlTest
     : public HeadlessAsyncDevTooledBrowserTest,
+      network::ExperimentalObserver,
       page::ExperimentalObserver {
  public:
   void RunDevTooledTest() override {
     EXPECT_TRUE(embedded_test_server()->Start());
     base::RunLoop run_loop;
     devtools_client_->GetPage()->GetExperimental()->AddObserver(this);
+    devtools_client_->GetNetwork()->GetExperimental()->AddObserver(this);
     devtools_client_->GetPage()->Enable(run_loop.QuitClosure());
     base::MessageLoop::ScopedNestableTaskAllower nest_loop(
         base::MessageLoop::current());
     run_loop.Run();
-    devtools_client_->GetPage()->GetExperimental()->SetControlNavigations(
-        headless::page::SetControlNavigationsParams::Builder()
-            .SetEnabled(true)
-            .Build());
+    devtools_client_->GetNetwork()->Enable();
+    devtools_client_->GetNetwork()
+        ->GetExperimental()
+        ->SetRequestInterceptionEnabled(
+            headless::network::SetRequestInterceptionEnabledParams::Builder()
+                .SetEnabled(true)
+                .Build());
     devtools_client_->GetPage()->Navigate(
         embedded_test_server()->GetURL("/hello.html").spec());
   }
 
-  void OnNavigationRequested(
-      const headless::page::NavigationRequestedParams& params) override {
-    navigation_requested_ = true;
+  void OnRequestIntercepted(
+      const network::RequestInterceptedParams& params) override {
+    if (params.GetIsNavigationRequest())
+      navigation_requested_ = true;
     // Allow the navigation to proceed.
-    devtools_client_->GetPage()->GetExperimental()->ProcessNavigation(
-        headless::page::ProcessNavigationParams::Builder()
-            .SetNavigationId(params.GetNavigationId())
-            .SetResponse(headless::page::NavigationResponse::PROCEED)
-            .Build());
+    devtools_client_->GetNetwork()
+        ->GetExperimental()
+        ->ContinueInterceptedRequest(
+            headless::network::ContinueInterceptedRequestParams::Builder()
+                .SetInterceptionId(params.GetInterceptionId())
+                .Build());
   }
 
   void OnFrameStoppedLoading(
@@ -1426,7 +1433,7 @@
           ->ContinueInterceptedRequest(
               network::ContinueInterceptedRequestParams::Builder()
                   .SetInterceptionId(params.GetInterceptionId())
-                  .SetErrorReason(network::ErrorReason::ABORTED)
+                  .SetErrorReason(network::ErrorReason::FAILED)
                   .Build());
     } else {
       // Allow everything else to continue.
diff --git a/headless/public/util/navigation_request.h b/headless/public/util/navigation_request.h
index cd28f10d..06e017f5 100644
--- a/headless/public/util/navigation_request.h
+++ b/headless/public/util/navigation_request.h
@@ -10,8 +10,7 @@
 namespace headless {
 
 // While the actual details of the navigation processing are left undefined,
-// it's anticipated implementations will use devtools Page.setControlNavigations
-// and Page.processNavigation commands.
+// it's anticipated implementations will use Network.requestIntercepted event.
 class NavigationRequest {
  public:
   NavigationRequest() {}
diff --git a/third_party/WebKit/Source/core/inspector/browser_protocol-1.2.json b/third_party/WebKit/Source/core/inspector/browser_protocol-1.2.json
index db58625..c0f3788 100644
--- a/third_party/WebKit/Source/core/inspector/browser_protocol-1.2.json
+++ b/third_party/WebKit/Source/core/inspector/browser_protocol-1.2.json
@@ -488,25 +488,6 @@
                 "parameters": [
                     { "name": "threshold", "type": "number", "description": "If set to a positive number, specifies threshold in seconds for input event latency that will cause a console warning about blocked event to be issued. If zero or less, the warning is disabled." }
                 ]
-            },
-            {
-                "name": "setControlNavigations",
-                "parameters": [
-                    { "name": "enabled", "type": "boolean" }
-                ],
-                "description": "Toggles navigation throttling which allows programatic control over navigation and redirect response.",
-                "experimental": true,
-                "handlers": ["browser"]
-            },
-            {
-                "name": "processNavigation",
-                "parameters": [
-                    { "name": "response", "$ref": "NavigationResponse" },
-                    { "name": "navigationId", "type": "integer" }
-                ],
-                "description": "Should be sent in response to a navigationRequested or a redirectRequested event, telling the browser how to handle the navigation.",
-                "experimental": true,
-                "handlers": ["browser"]
             }
         ],
         "events": [
@@ -634,17 +615,6 @@
                 "name": "interstitialHidden",
                 "description": "Fired when interstitial page was hidden",
                 "handlers": ["browser"]
-            },
-            {
-                "name": "navigationRequested",
-                "description": "Fired when a navigation is started if navigation throttles are enabled.  The navigation will be deferred until processNavigation is called.",
-                "parameters": [
-                    { "name": "isInMainFrame", "type": "boolean", "description": "Whether the navigation is taking place in the main frame or in a subframe." },
-                    { "name": "isRedirect", "type": "boolean", "description": "Whether the navigation has encountered a server redirect or not." },
-                    { "name": "navigationId", "type": "integer" },
-                    { "name": "url", "type": "string", "description": "URL of requested navigation." }
-                ],
-                "handlers": ["browser"]
             }
         ]
     },
diff --git a/third_party/WebKit/Source/core/inspector/browser_protocol.json b/third_party/WebKit/Source/core/inspector/browser_protocol.json
index 001842a4..1ecc0612d 100644
--- a/third_party/WebKit/Source/core/inspector/browser_protocol.json
+++ b/third_party/WebKit/Source/core/inspector/browser_protocol.json
@@ -550,23 +550,6 @@
                 "experimental": true
             },
             {
-                "name": "setControlNavigations",
-                "parameters": [
-                    { "name": "enabled", "type": "boolean" }
-                ],
-                "description": "Toggles navigation throttling which allows programatic control over navigation and redirect response.",
-                "experimental": true
-            },
-            {
-                "name": "processNavigation",
-                "parameters": [
-                    { "name": "response", "$ref": "NavigationResponse" },
-                    { "name": "navigationId", "type": "integer" }
-                ],
-                "description": "Should be sent in response to a navigationRequested or a redirectRequested event, telling the browser how to handle the navigation.",
-                "experimental": true
-            },
-            {
                 "name": "getLayoutMetrics",
                 "description": "Returns metrics relating to the layouting of the page, such as viewport bounds/scale.",
                 "experimental": true,
@@ -709,16 +692,6 @@
             {
                 "name": "interstitialHidden",
                 "description": "Fired when interstitial page was hidden"
-            },
-            {
-                "name": "navigationRequested",
-                "description": "Fired when a navigation is started if navigation throttles are enabled.  The navigation will be deferred until processNavigation is called.",
-                "parameters": [
-                    { "name": "isInMainFrame", "type": "boolean", "description": "Whether the navigation is taking place in the main frame or in a subframe." },
-                    { "name": "isRedirect", "type": "boolean", "description": "Whether the navigation has encountered a server redirect or not." },
-                    { "name": "navigationId", "type": "integer" },
-                    { "name": "url", "type": "string", "description": "URL of requested navigation." }
-                ]
             }
         ]
     },
@@ -1609,7 +1582,7 @@
                 "description": "Response to Network.requestIntercepted which either modifies the request to continue with any modifications, or blocks it, or completes it with the provided response bytes. If a network fetch occurs as a result which encounters a redirect an additional Network.requestIntercepted event will be sent with the same InterceptionId.",
                 "parameters": [
                     { "name": "interceptionId", "$ref": "InterceptionId" },
-                    { "name": "errorReason", "$ref": "ErrorReason", "optional": true, "description": "If set this causes the request to fail with the given reason. Must not be set in response to an authChallenge." },
+                    { "name": "errorReason", "$ref": "ErrorReason", "optional": true, "description": "If set this causes the request to fail with the given reason. Passing <code>Aborted</code> for requests marked with <code>isNavigationRequest</code> also cancels the navigation. Must not be set in response to an authChallenge." },
                     { "name": "rawResponse", "type": "string", "optional": true, "description": "If set the requests completes using with the provided base64 encoded raw response, including HTTP status line and headers etc... Must not be set in response to an authChallenge." },
                     { "name": "url", "type": "string", "optional": true, "description": "If set the request url will be modified in a way that's not observable by page. Must not be set in response to an authChallenge." },
                     { "name": "method", "type": "string", "optional": true, "description": "If set this allows the request method to be overridden. Must not be set in response to an authChallenge."},
@@ -1786,6 +1759,7 @@
                     { "name": "interceptionId", "$ref": "InterceptionId", "description": "Each request the page makes will have a unique id, however if any redirects are encountered while processing that fetch, they will be reported with the same id as the original fetch. Likewise if HTTP authentication is needed then the same fetch id will be used." },
                     { "name": "request", "$ref": "Request" },
                     { "name": "resourceType", "$ref": "Page.ResourceType", "description": "How the requested resource will be used." },
+                    { "name": "isNavigationRequest", "type": "boolean", "description": "Whether this is a navigation request, which can abort the navigation completely." },
                     { "name": "redirectHeaders", "$ref": "Headers", "optional": true, "description": "HTTP response headers, only sent if a redirect was intercepted." },
                     { "name": "redirectStatusCode", "type": "integer", "optional": true, "description": "HTTP response code, only sent if a redirect was intercepted." },
                     { "name": "redirectUrl", "optional": true, "type": "string", "description": "Redirect location, only sent if a redirect was intercepted."},
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/NetworkManager.js b/third_party/WebKit/Source/devtools/front_end/sdk/NetworkManager.js
index 25792cd..4277354 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/NetworkManager.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/NetworkManager.js
@@ -655,11 +655,13 @@
    * @param {!Protocol.Network.RequestId} requestId
    * @param {!Protocol.Network.Request} request
    * @param {string} resourceType
+   * @param {boolean} isNavigationRequest
    * @param {!Protocol.Network.Headers=} redirectHeaders
    * @param {number=} redirectStatusCode
    * @param {string=} redirectUrl
    */
-  requestIntercepted(requestId, request, resourceType, redirectHeaders, redirectStatusCode, redirectUrl) {
+  requestIntercepted(
+      requestId, request, resourceType, isNavigationRequest, redirectHeaders, redirectStatusCode, redirectUrl) {
     // Stub implementation.  Event not currently used by the frontend.
   }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/ResourceTreeModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/ResourceTreeModel.js
index 53a5e6c8..a103ba2 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/ResourceTreeModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/ResourceTreeModel.js
@@ -877,11 +877,4 @@
     this._resourceTreeModel._isInterstitialShowing = false;
     this._resourceTreeModel.dispatchEventToListeners(SDK.ResourceTreeModel.Events.InterstitialHidden);
   }
-
-  /**
-   * @override
-   */
-  navigationRequested() {
-    // Frontend is not interested in when navigations are requested.
-  }
 };
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/ScreenCaptureModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/ScreenCaptureModel.js
index f64f9c0..f478e1a 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/ScreenCaptureModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/ScreenCaptureModel.js
@@ -184,12 +184,6 @@
    */
   interstitialHidden() {
   }
-
-  /**
-   * @override
-   */
-  navigationRequested() {
-  }
 };
 
 SDK.SDKModel.register(SDK.ScreenCaptureModel, SDK.Target.Capability.ScreenCapture, false);