summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorclamy <clamy@chromium.org>2015-09-21 19:18:53 -0700
committerCommit bot <commit-bot@chromium.org>2015-09-22 02:19:35 +0000
commit394057986ff5d00a841a976f3bd8d599603acaa1 (patch)
tree3cf339bca77629de8a2d9a5d00e1cc793c9020f2
parentd3090238be5465186fb991d306b4911c407bc6b8 (diff)
downloadchromium_src-394057986ff5d00a841a976f3bd8d599603acaa1.zip
chromium_src-394057986ff5d00a841a976f3bd8d599603acaa1.tar.gz
chromium_src-394057986ff5d00a841a976f3bd8d599603acaa1.tar.bz2
Add a NavigationThrottle to the public content/ interface
This CL adds a NavigationThrottle class to the public content/ interface. A NavigationThrottle is used to control the flow of navigations. It lives entirely on the UI thread. Eventually, all components that want the functionality of a ResourceThrottle for navigations should transition to a NavigationThrottle: the new architecture for navigations (browser-side navigation) will not support ResourceThrottles for main resources load. See https://docs.google.com/document/d/1ICLLQoC9EsZ-bWH4ZKRhPCIoZKn6pOj02SlGl6SKH6Y/edit?pli=1#heading=h.fmxjmgvbgg7x for the design doc. This Cl also transition the InterceptNavigationresourceThrottle to the Navigationthrottle model. BUG=504347 Review URL: https://codereview.chromium.org/1269813002 Cr-Commit-Position: refs/heads/master@{#350092}
-rw-r--r--android_webview/browser/aw_content_browser_client.cc19
-rw-r--r--android_webview/browser/aw_content_browser_client.h2
-rw-r--r--android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc8
-rw-r--r--chrome/browser/apps/app_url_redirector.cc69
-rw-r--r--chrome/browser/apps/app_url_redirector.h22
-rw-r--r--chrome/browser/chrome_content_browser_client.cc32
-rw-r--r--chrome/browser/chrome_content_browser_client.h2
-rw-r--r--chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc21
-rw-r--r--components/components_tests.gyp2
-rw-r--r--components/navigation_interception.gypi4
-rw-r--r--components/navigation_interception/BUILD.gn6
-rw-r--r--components/navigation_interception/intercept_navigation_delegate.cc13
-rw-r--r--components/navigation_interception/intercept_navigation_delegate.h16
-rw-r--r--components/navigation_interception/intercept_navigation_resource_throttle.cc146
-rw-r--r--components/navigation_interception/intercept_navigation_resource_throttle.h63
-rw-r--r--components/navigation_interception/intercept_navigation_resource_throttle_unittest.cc481
-rw-r--r--components/navigation_interception/intercept_navigation_throttle.cc49
-rw-r--r--components/navigation_interception/intercept_navigation_throttle.h51
-rw-r--r--components/navigation_interception/intercept_navigation_throttle_unittest.cc165
-rw-r--r--content/browser/frame_host/navigation_handle_impl.cc141
-rw-r--r--content/browser/frame_host/navigation_handle_impl.h67
-rw-r--r--content/browser/frame_host/navigation_request.cc35
-rw-r--r--content/browser/frame_host/navigation_request.h4
-rw-r--r--content/browser/frame_host/navigator_impl.cc2
-rw-r--r--content/browser/frame_host/render_frame_host_impl.cc4
-rw-r--r--content/browser/loader/navigation_resource_throttle.cc154
-rw-r--r--content/browser/loader/navigation_resource_throttle.h44
-rw-r--r--content/browser/loader/resource_dispatcher_host_impl.cc11
-rw-r--r--content/content_browser.gypi5
-rw-r--r--content/public/browser/content_browser_client.cc6
-rw-r--r--content/public/browser/content_browser_client.h10
-rw-r--r--content/public/browser/navigation_handle.cc30
-rw-r--r--content/public/browser/navigation_handle.h91
-rw-r--r--content/public/browser/navigation_throttle.cc23
-rw-r--r--content/public/browser/navigation_throttle.h43
-rw-r--r--content/test/web_contents_observer_sanity_checker.cc4
36 files changed, 1025 insertions, 820 deletions
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index 759c844..ab14d49 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -25,10 +25,13 @@
#include "base/command_line.h"
#include "base/path_service.h"
#include "components/cdm/browser/cdm_message_filter_android.h"
+#include "components/navigation_interception/intercept_navigation_delegate.h"
#include "content/public/browser/access_token_store.h"
#include "content/public/browser/browser_message_filter.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/client_certificate_delegate.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/navigation_throttle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
@@ -487,6 +490,22 @@ void AwContentBrowserClient::OverrideWebkitPrefs(
content::WebContents::FromRenderViewHost(rvh), web_prefs);
}
+ScopedVector<content::NavigationThrottle>
+AwContentBrowserClient::CreateThrottlesForNavigation(
+ content::NavigationHandle* navigation_handle) {
+ ScopedVector<content::NavigationThrottle> throttles;
+ if (navigation_handle->IsInMainFrame() ||
+ (!navigation_handle->GetURL().SchemeIs(url::kHttpScheme) &&
+ !navigation_handle->GetURL().SchemeIs(url::kHttpsScheme) &&
+ !navigation_handle->GetURL().SchemeIs(url::kAboutScheme))) {
+ throttles.push_back(
+ navigation_interception::InterceptNavigationDelegate::CreateThrottleFor(
+ navigation_handle)
+ .Pass());
+ }
+ return throttles.Pass();
+}
+
#if defined(VIDEO_HOLE)
content::ExternalVideoSurfaceContainer*
AwContentBrowserClient::OverrideCreateExternalVideoSurfaceContainer(
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index d811cf2..a3a814e 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -142,6 +142,8 @@ class AwContentBrowserClient : public content::ContentBrowserClient {
std::map<int, base::MemoryMappedFile::Region>* regions) override;
void OverrideWebkitPrefs(content::RenderViewHost* rvh,
content::WebPreferences* web_prefs) override;
+ ScopedVector<content::NavigationThrottle> CreateThrottlesForNavigation(
+ content::NavigationHandle* navigation_handle) override;
#if defined(VIDEO_HOLE)
content::ExternalVideoSurfaceContainer*
OverrideCreateExternalVideoSurfaceContainer(
diff --git a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
index 1d9e585..ed7c52b 100644
--- a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
+++ b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
@@ -221,14 +221,6 @@ void AwResourceDispatcherHostDelegate::RequestBeginning(
throttles->push_back(new IoThreadClientThrottle(
request_info->GetChildID(), request_info->GetRenderFrameID(), request));
- if (resource_type == content::RESOURCE_TYPE_MAIN_FRAME ||
- (resource_type == content::RESOURCE_TYPE_SUB_FRAME &&
- !request->url().SchemeIs(url::kHttpScheme) &&
- !request->url().SchemeIs(url::kHttpsScheme) &&
- !request->url().SchemeIs(url::kAboutScheme))) {
- throttles->push_back(InterceptNavigationDelegate::CreateThrottleFor(
- request));
- }
if (resource_type != content::RESOURCE_TYPE_MAIN_FRAME)
InterceptNavigationDelegate::UpdateUserGestureCarryoverInfo(request);
}
diff --git a/chrome/browser/apps/app_url_redirector.cc b/chrome/browser/apps/app_url_redirector.cc
index cf15169..6396293 100644
--- a/chrome/browser/apps/app_url_redirector.cc
+++ b/chrome/browser/apps/app_url_redirector.cc
@@ -9,22 +9,18 @@
#include "base/logging.h"
#include "chrome/browser/prerender/prerender_contents.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_io_data.h"
#include "chrome/common/extensions/api/url_handlers/url_handlers_parser.h"
-#include "components/navigation_interception/intercept_navigation_resource_throttle.h"
+#include "components/navigation_interception/intercept_navigation_throttle.h"
#include "components/navigation_interception/navigation_params.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/resource_request_info.h"
-#include "content/public/browser/resource_throttle.h"
+#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h"
-#include "extensions/browser/info_map.h"
+#include "extensions/browser/extension_registry.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_set.h"
#include "net/url_request/url_request.h"
using content::BrowserThread;
-using content::ResourceRequestInfo;
using content::WebContents;
using extensions::Extension;
using extensions::UrlHandlers;
@@ -55,8 +51,8 @@ bool LaunchAppWithUrl(
}
// These are guaranteed by CreateThrottleFor below.
- DCHECK(!params.is_post());
DCHECK(UrlHandlers::CanExtensionHandleUrl(app.get(), params.url()));
+ DCHECK(!params.is_post());
Profile* profile =
Profile::FromBrowserContext(source->GetBrowserContext());
@@ -73,57 +69,54 @@ bool LaunchAppWithUrl(
} // namespace
// static
-content::ResourceThrottle*
-AppUrlRedirector::MaybeCreateThrottleFor(net::URLRequest* request,
- ProfileIOData* profile_io_data) {
- DVLOG(1) << "Considering URL for redirection: "
- << request->method() << " " << request->url().spec();
+scoped_ptr<content::NavigationThrottle>
+AppUrlRedirector::MaybeCreateThrottleFor(content::NavigationHandle* handle) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DVLOG(1) << "Considering URL for redirection: " << handle->GetURL().spec();
+
+ content::BrowserContext* browser_context =
+ handle->GetWebContents()->GetBrowserContext();
+ DCHECK(browser_context);
// Support only GET for now.
- if (request->method() != "GET") {
+ if (handle->IsPost()) {
DVLOG(1) << "Skip redirection: method is not GET";
- return NULL;
+ return nullptr;
}
- if (!request->url().SchemeIsHTTPOrHTTPS()) {
+ if (!handle->GetURL().SchemeIsHTTPOrHTTPS()) {
DVLOG(1) << "Skip redirection: scheme is not HTTP or HTTPS";
- return NULL;
- }
-
- // The user has indicated that a URL should be force downloaded. Turn off
- // URL redirection in this case.
- if (ResourceRequestInfo::ForRequest(request)->IsDownload()) {
- DVLOG(1) << "Skip redirection: request is a forced download";
- return NULL;
+ return nullptr;
}
// Never redirect URLs to apps in incognito. Technically, apps are not
// supported in incognito, but that may change in future.
// See crbug.com/240879, which tracks incognito support for v2 apps.
- if (profile_io_data->IsOffTheRecord()) {
+ Profile* profile = Profile::FromBrowserContext(browser_context);
+ if (profile->GetProfileType() == Profile::INCOGNITO_PROFILE) {
DVLOG(1) << "Skip redirection: unsupported in incognito";
- return NULL;
+ return nullptr;
}
- const extensions::ExtensionSet& extensions =
- profile_io_data->GetExtensionInfoMap()->extensions();
- for (extensions::ExtensionSet::const_iterator iter = extensions.begin();
- iter != extensions.end();
- ++iter) {
+ const extensions::ExtensionSet& enabled_extensions =
+ extensions::ExtensionRegistry::Get(browser_context)->enabled_extensions();
+ for (extensions::ExtensionSet::const_iterator iter =
+ enabled_extensions.begin();
+ iter != enabled_extensions.end(); ++iter) {
const UrlHandlerInfo* handler =
- UrlHandlers::FindMatchingUrlHandler(iter->get(), request->url());
+ UrlHandlers::FindMatchingUrlHandler(iter->get(), handle->GetURL());
if (handler) {
DVLOG(1) << "Found matching app handler for redirection: "
<< (*iter)->name() << "(" << (*iter)->id() << "):"
<< handler->id;
- return new navigation_interception::InterceptNavigationResourceThrottle(
- request,
- base::Bind(&LaunchAppWithUrl,
- scoped_refptr<const Extension>(*iter),
- handler->id));
+ return scoped_ptr<content::NavigationThrottle>(
+ new navigation_interception::InterceptNavigationThrottle(
+ handle,
+ base::Bind(&LaunchAppWithUrl,
+ scoped_refptr<const Extension>(*iter), handler->id)));
}
}
DVLOG(1) << "Skipping redirection: no matching app handler found";
- return NULL;
+ return nullptr;
}
diff --git a/chrome/browser/apps/app_url_redirector.h b/chrome/browser/apps/app_url_redirector.h
index 331d7b4..629af37 100644
--- a/chrome/browser/apps/app_url_redirector.h
+++ b/chrome/browser/apps/app_url_redirector.h
@@ -6,24 +6,22 @@
#define CHROME_BROWSER_APPS_APP_URL_REDIRECTOR_H_
#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/navigation_throttle.h"
namespace content {
-class ResourceThrottle;
+class NavigationHandle;
+class NavigationThrottle;
+class WebContents;
}
-namespace net {
-class URLRequest;
-}
-
-class ProfileIOData;
-
-// This class creates resource throttles that redirect URLs to apps that
-// have a matching URL handler in the 'url_handlers' manifest key.
+// This class creates navigation throttles that redirect URLs to apps that have
+// a matching URL handler in the 'url_handlers' manifest key. Note that this is
+// a UI thread class.
class AppUrlRedirector {
public:
- static content::ResourceThrottle* MaybeCreateThrottleFor(
- net::URLRequest* request,
- ProfileIOData* profile_io_data);
+ static scoped_ptr<content::NavigationThrottle> MaybeCreateThrottleFor(
+ content::NavigationHandle* handle);
private:
DISALLOW_COPY_AND_ASSIGN(AppUrlRedirector);
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 25f4aa4..bbe1c07 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -24,6 +24,7 @@
#include "base/thread_task_runner_handle.h"
#include "base/threading/sequenced_worker_pool.h"
#include "chrome/browser/after_startup_task_utils.h"
+#include "chrome/browser/apps/app_url_redirector.h"
#include "chrome/browser/browser_about_handler.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_shutdown.h"
@@ -120,6 +121,8 @@
#include "content/public/browser/child_process_data.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/client_certificate_delegate.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/navigation_throttle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
@@ -173,6 +176,7 @@
#include "chrome/browser/chrome_browser_main_android.h"
#include "chrome/common/descriptors_android.h"
#include "components/crash/content/browser/crash_dump_manager_android.h"
+#include "components/navigation_interception/intercept_navigation_delegate.h"
#include "components/service_tab_launcher/browser/android/service_tab_launcher.h"
#include "ui/base/resource/resource_bundle_android.h"
#elif defined(OS_POSIX)
@@ -2598,6 +2602,34 @@ void ChromeContentBrowserClient::RecordURLMetric(const std::string& metric,
}
}
+ScopedVector<content::NavigationThrottle>
+ChromeContentBrowserClient::CreateThrottlesForNavigation(
+ content::NavigationHandle* handle) {
+ ScopedVector<content::NavigationThrottle> throttles;
+#if defined(OS_ANDROID)
+ // TODO(davidben): This is insufficient to integrate with prerender properly.
+ // https://crbug.com/370595
+ prerender::PrerenderContents* prerender_contents =
+ prerender::PrerenderContents::FromWebContents(handle->GetWebContents());
+ if (!prerender_contents && handle->IsInMainFrame()) {
+ throttles.push_back(
+ navigation_interception::InterceptNavigationDelegate::CreateThrottleFor(
+ handle)
+ .Pass());
+ }
+#else
+ if (handle->IsInMainFrame()) {
+ // Redirect some navigations to apps that have registered matching URL
+ // handlers ('url_handlers' in the manifest).
+ scoped_ptr<content::NavigationThrottle> url_to_app_throttle =
+ AppUrlRedirector::MaybeCreateThrottleFor(handle);
+ if (url_to_app_throttle)
+ throttles.push_back(url_to_app_throttle.Pass());
+ }
+#endif
+ return throttles.Pass();
+}
+
content::DevToolsManagerDelegate*
ChromeContentBrowserClient::GetDevToolsManagerDelegate() {
return new ChromeDevToolsManagerDelegate();
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index a8b6270..1e2e97f 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -285,6 +285,8 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
content::WebContents* web_contents) override;
void RecordURLMetric(const std::string& metric, const GURL& url) override;
+ ScopedVector<content::NavigationThrottle> CreateThrottlesForNavigation(
+ content::NavigationHandle* handle) override;
private:
friend class DisableWebRtcEncryptionFlagTest;
diff --git a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
index aa4705e..b28332e 100644
--- a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
+++ b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
@@ -339,25 +339,8 @@ void ChromeResourceDispatcherHostDelegate::RequestBeginning(
resource_context);
#if defined(OS_ANDROID)
- // TODO(davidben): This is insufficient to integrate with prerender properly.
- // https://crbug.com/370595
- if (!is_prerendering) {
- if (resource_type == content::RESOURCE_TYPE_MAIN_FRAME) {
- throttles->push_back(
- InterceptNavigationDelegate::CreateThrottleFor(request));
- } else {
- InterceptNavigationDelegate::UpdateUserGestureCarryoverInfo(request);
- }
- }
-#else
- if (resource_type == content::RESOURCE_TYPE_MAIN_FRAME) {
- // Redirect some navigations to apps that have registered matching URL
- // handlers ('url_handlers' in the manifest).
- content::ResourceThrottle* url_to_app_throttle =
- AppUrlRedirector::MaybeCreateThrottleFor(request, io_data);
- if (url_to_app_throttle)
- throttles->push_back(url_to_app_throttle);
- }
+ if (resource_type != content::RESOURCE_TYPE_MAIN_FRAME)
+ InterceptNavigationDelegate::UpdateUserGestureCarryoverInfo(request);
#endif
#if defined(OS_CHROMEOS)
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index 8e3d46c..78a981d 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -353,7 +353,7 @@
'nacl/zygote/nacl_fork_delegate_linux_unittest.cc',
],
'navigation_interception_unittest_sources': [
- 'navigation_interception/intercept_navigation_resource_throttle_unittest.cc',
+ 'navigation_interception/intercept_navigation_throttle_unittest.cc',
],
'network_hints_unittest_sources': [
'network_hints/renderer/dns_prefetch_queue_unittest.cc',
diff --git a/components/navigation_interception.gypi b/components/navigation_interception.gypi
index 3511201..7ccc4cd 100644
--- a/components/navigation_interception.gypi
+++ b/components/navigation_interception.gypi
@@ -23,8 +23,8 @@
],
'sources': [
# Note: sources list duplicated in GN build.
- 'navigation_interception/intercept_navigation_resource_throttle.cc',
- 'navigation_interception/intercept_navigation_resource_throttle.h',
+ 'navigation_interception/intercept_navigation_throttle.cc',
+ 'navigation_interception/intercept_navigation_throttle.h',
'navigation_interception/navigation_params.cc',
'navigation_interception/navigation_params.h',
],
diff --git a/components/navigation_interception/BUILD.gn b/components/navigation_interception/BUILD.gn
index 12456ff..f268510 100644
--- a/components/navigation_interception/BUILD.gn
+++ b/components/navigation_interception/BUILD.gn
@@ -8,8 +8,8 @@ if (is_android) {
source_set("navigation_interception") {
sources = [
- "intercept_navigation_resource_throttle.cc",
- "intercept_navigation_resource_throttle.h",
+ "intercept_navigation_throttle.cc",
+ "intercept_navigation_throttle.h",
"navigation_params.cc",
"navigation_params.h",
]
@@ -49,7 +49,7 @@ if (is_android) {
source_set("unit_tests") {
testonly = true
sources = [
- "intercept_navigation_resource_throttle_unittest.cc",
+ "intercept_navigation_throttle_unittest.cc",
]
deps = [
":navigation_interception",
diff --git a/components/navigation_interception/intercept_navigation_delegate.cc b/components/navigation_interception/intercept_navigation_delegate.cc
index ba9053d..11017f3b 100644
--- a/components/navigation_interception/intercept_navigation_delegate.cc
+++ b/components/navigation_interception/intercept_navigation_delegate.cc
@@ -7,9 +7,10 @@
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/callback.h"
-#include "components/navigation_interception/intercept_navigation_resource_throttle.h"
+#include "components/navigation_interception/intercept_navigation_throttle.h"
#include "components/navigation_interception/navigation_params_android.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_throttle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/resource_request_info.h"
@@ -83,10 +84,12 @@ InterceptNavigationDelegate* InterceptNavigationDelegate::Get(
}
// static
-content::ResourceThrottle* InterceptNavigationDelegate::CreateThrottleFor(
- net::URLRequest* request) {
- return new InterceptNavigationResourceThrottle(
- request, base::Bind(&CheckIfShouldIgnoreNavigationOnUIThread));
+scoped_ptr<content::NavigationThrottle>
+InterceptNavigationDelegate::CreateThrottleFor(
+ content::NavigationHandle* handle) {
+ return scoped_ptr<content::NavigationThrottle>(
+ new InterceptNavigationThrottle(
+ handle, base::Bind(&CheckIfShouldIgnoreNavigationOnUIThread)));
}
// static
diff --git a/components/navigation_interception/intercept_navigation_delegate.h b/components/navigation_interception/intercept_navigation_delegate.h
index d84969f..57858fd 100644
--- a/components/navigation_interception/intercept_navigation_delegate.h
+++ b/components/navigation_interception/intercept_navigation_delegate.h
@@ -12,7 +12,8 @@
class GURL;
namespace content {
-class ResourceThrottle;
+class NavigationHandle;
+class NavigationThrottle;
class WebContents;
}
@@ -32,9 +33,8 @@ class NavigationParams;
// 1) the Java-side interface implementation must be associated (via the
// Associate method) with a WebContents for which URLRequests are to be
// intercepted,
-// 2) the ResourceThrottle obtained via CreateThrottleFor must be associated
-// with the URLRequests in the ResourceDispatcherHostDelegate
-// implementation.
+// 2) the NavigationThrottle obtained via CreateThrottleFor must be associated
+// with the NavigationHandle in the ContentBrowserClient implementation.
class InterceptNavigationDelegate : public base::SupportsUserData::Data {
public:
InterceptNavigationDelegate(JNIEnv* env, jobject jdelegate);
@@ -50,10 +50,10 @@ class InterceptNavigationDelegate : public base::SupportsUserData::Data {
// can be null.
static InterceptNavigationDelegate* Get(content::WebContents* web_contents);
- // Creates a InterceptNavigationResourceThrottle that will direct all
- // callbacks to the InterceptNavigationDelegate.
- static content::ResourceThrottle* CreateThrottleFor(
- net::URLRequest* request);
+ // Creates a InterceptNavigationThrottle that will direct all callbacks to
+ // the InterceptNavigationDelegate.
+ static scoped_ptr<content::NavigationThrottle> CreateThrottleFor(
+ content::NavigationHandle* handle);
// Updates information to determine whether to have user gesture carryover or
// not.
diff --git a/components/navigation_interception/intercept_navigation_resource_throttle.cc b/components/navigation_interception/intercept_navigation_resource_throttle.cc
deleted file mode 100644
index 1b0b89f..0000000
--- a/components/navigation_interception/intercept_navigation_resource_throttle.cc
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright (c) 2012 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 "components/navigation_interception/intercept_navigation_resource_throttle.h"
-
-#include "components/navigation_interception/navigation_params.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/child_process_security_policy.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/resource_context.h"
-#include "content/public/browser/resource_controller.h"
-#include "content/public/browser/resource_request_info.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/referrer.h"
-#include "net/http/http_response_headers.h"
-#include "net/url_request/redirect_info.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_job_factory.h"
-#include "net/url_request/url_request.h"
-#include "ui/base/page_transition_types.h"
-
-using content::BrowserThread;
-using content::ChildProcessSecurityPolicy;
-using ui::PageTransition;
-using content::Referrer;
-using content::RenderProcessHost;
-using content::ResourceRequestInfo;
-
-namespace navigation_interception {
-
-namespace {
-
-void CheckIfShouldIgnoreNavigationOnUIThread(
- int render_process_id,
- int render_frame_id,
- const NavigationParams& navigation_params,
- InterceptNavigationResourceThrottle::CheckOnUIThreadCallback
- should_ignore_callback,
- base::Callback<void(bool)> callback) {
- bool should_ignore_navigation = false;
- RenderProcessHost* rph = RenderProcessHost::FromID(render_process_id);
- if (rph) {
- NavigationParams validated_params(navigation_params);
- rph->FilterURL(false, &validated_params.url());
-
- content::RenderFrameHost* render_frame_host =
- content::RenderFrameHost::FromID(render_process_id, render_frame_id);
- content::WebContents* web_contents =
- content::WebContents::FromRenderFrameHost(render_frame_host);
-
- if (web_contents) {
- should_ignore_navigation = should_ignore_callback.Run(web_contents,
- validated_params);
- }
- }
-
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(callback, should_ignore_navigation));
-}
-
-} // namespace
-
-InterceptNavigationResourceThrottle::InterceptNavigationResourceThrottle(
- net::URLRequest* request,
- CheckOnUIThreadCallback should_ignore_callback)
- : request_(request),
- should_ignore_callback_(should_ignore_callback),
- weak_ptr_factory_(this) {
-}
-
-InterceptNavigationResourceThrottle::~InterceptNavigationResourceThrottle() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-}
-
-void InterceptNavigationResourceThrottle::WillStartRequest(bool* defer) {
- *defer =
- CheckIfShouldIgnoreNavigation(request_->url(), request_->method(), false);
-}
-
-void InterceptNavigationResourceThrottle::WillRedirectRequest(
- const net::RedirectInfo& redirect_info,
- bool* defer) {
- *defer = CheckIfShouldIgnoreNavigation(redirect_info.new_url,
- redirect_info.new_method, true);
-}
-
-const char* InterceptNavigationResourceThrottle::GetNameForLogging() const {
- return "InterceptNavigationResourceThrottle";
-}
-
-bool InterceptNavigationResourceThrottle::CheckIfShouldIgnoreNavigation(
- const GURL& url,
- const std::string& method,
- bool is_redirect) {
- const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_);
- if (!info)
- return false;
-
- int render_process_id, render_frame_id;
- if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_id))
- return false;
-
- bool is_external_protocol =
- !info->GetContext()->GetRequestContext()->job_factory()->IsHandledURL(
- url);
- NavigationParams navigation_params(
- url,
- Referrer::SanitizeForRequest(
- url, Referrer(GURL(request_->referrer()), info->GetReferrerPolicy())),
- info->HasUserGesture(), method == "POST", info->GetPageTransition(),
- is_redirect, is_external_protocol, true);
-
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(
- &CheckIfShouldIgnoreNavigationOnUIThread,
- render_process_id,
- render_frame_id,
- navigation_params,
- should_ignore_callback_,
- base::Bind(
- &InterceptNavigationResourceThrottle::OnResultObtained,
- weak_ptr_factory_.GetWeakPtr())));
-
- // Defer request while we wait for the UI thread to check if the navigation
- // should be ignored.
- return true;
-}
-
-void InterceptNavigationResourceThrottle::OnResultObtained(
- bool should_ignore_navigation) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- if (should_ignore_navigation) {
- controller()->CancelAndIgnore();
- } else {
- controller()->Resume();
- }
-}
-
-} // namespace navigation_interception
diff --git a/components/navigation_interception/intercept_navigation_resource_throttle.h b/components/navigation_interception/intercept_navigation_resource_throttle.h
deleted file mode 100644
index db3a714..0000000
--- a/components/navigation_interception/intercept_navigation_resource_throttle.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) 2012 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 COMPONENTS_NAVIGATION_INTERCEPTION_INTERCEPT_NAVIGATION_RESOURCE_THROTTLE_H_
-#define COMPONENTS_NAVIGATION_INTERCEPTION_INTERCEPT_NAVIGATION_RESOURCE_THROTTLE_H_
-
-#include <string>
-
-#include "base/callback.h"
-#include "base/memory/weak_ptr.h"
-#include "content/public/browser/resource_throttle.h"
-
-class GURL;
-
-namespace content {
-class WebContents;
-}
-
-namespace net {
-class URLRequest;
-}
-
-namespace navigation_interception {
-
-class NavigationParams;
-
-// This class allows the provider of the Callback to selectively ignore top
-// level navigations.
-class InterceptNavigationResourceThrottle : public content::ResourceThrottle {
- public:
- typedef base::Callback<bool(
- content::WebContents* /* source */,
- const NavigationParams& /* navigation_params */)>
- CheckOnUIThreadCallback;
-
- InterceptNavigationResourceThrottle(
- net::URLRequest* request,
- CheckOnUIThreadCallback should_ignore_callback);
- ~InterceptNavigationResourceThrottle() override;
-
- // content::ResourceThrottle implementation:
- void WillStartRequest(bool* defer) override;
- void WillRedirectRequest(const net::RedirectInfo& redirect_info,
- bool* defer) override;
- const char* GetNameForLogging() const override;
-
- private:
- bool CheckIfShouldIgnoreNavigation(const GURL& url,
- const std::string& method,
- bool is_redirect);
- void OnResultObtained(bool should_ignore_navigation);
-
- net::URLRequest* request_;
- CheckOnUIThreadCallback should_ignore_callback_;
- base::WeakPtrFactory<InterceptNavigationResourceThrottle> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(InterceptNavigationResourceThrottle);
-};
-
-} // namespace navigation_interception
-
-#endif // COMPONENTS_NAVIGATION_INTERCEPTION_INTERCEPT_NAVIGATION_RESOURCE_THROTTLE_H_
diff --git a/components/navigation_interception/intercept_navigation_resource_throttle_unittest.cc b/components/navigation_interception/intercept_navigation_resource_throttle_unittest.cc
deleted file mode 100644
index 8855f42..0000000
--- a/components/navigation_interception/intercept_navigation_resource_throttle_unittest.cc
+++ /dev/null
@@ -1,481 +0,0 @@
-// Copyright (c) 2012 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 "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/run_loop.h"
-#include "base/synchronization/waitable_event.h"
-#include "components/navigation_interception/intercept_navigation_resource_throttle.h"
-#include "components/navigation_interception/navigation_params.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/resource_context.h"
-#include "content/public/browser/resource_controller.h"
-#include "content/public/browser/resource_dispatcher_host.h"
-#include "content/public/browser/resource_dispatcher_host_delegate.h"
-#include "content/public/browser/resource_request_info.h"
-#include "content/public/browser/resource_throttle.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_delegate.h"
-#include "content/public/test/mock_resource_context.h"
-#include "content/public/test/test_renderer_host.h"
-#include "net/base/request_priority.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_response_info.h"
-#include "net/url_request/redirect_info.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_test_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using content::ResourceType;
-using testing::_;
-using testing::Eq;
-using testing::Ne;
-using testing::Property;
-using testing::Return;
-
-namespace navigation_interception {
-
-namespace {
-
-const char kTestUrl[] = "http://www.test.com/";
-const char kUnsafeTestUrl[] = "about:crash";
-
-// The MS C++ compiler complains about not being able to resolve which url()
-// method (const or non-const) to use if we use the Property matcher to check
-// the return value of the NavigationParams::url() method.
-// It is possible to suppress the error by specifying the types directly but
-// that results in very ugly syntax, which is why these custom matchers are
-// used instead.
-MATCHER(NavigationParamsUrlIsTest, "") {
- return arg.url() == GURL(kTestUrl);
-}
-
-MATCHER(NavigationParamsUrlIsSafe, "") {
- return arg.url() != GURL(kUnsafeTestUrl);
-}
-
-} // namespace
-
-
-// MockInterceptCallbackReceiver ----------------------------------------------
-
-class MockInterceptCallbackReceiver {
- public:
- MOCK_METHOD2(ShouldIgnoreNavigation,
- bool(content::WebContents* source,
- const NavigationParams& navigation_params));
-};
-
-// MockResourceController -----------------------------------------------------
-class MockResourceController : public content::ResourceController {
- public:
- enum Status {
- UNKNOWN,
- RESUMED,
- CANCELLED
- };
-
- MockResourceController()
- : status_(UNKNOWN) {
- }
-
- Status status() const { return status_; }
-
- // ResourceController:
- void Cancel() override { NOTREACHED(); }
- void CancelAndIgnore() override { status_ = CANCELLED; }
- void CancelWithError(int error_code) override { NOTREACHED(); }
- void Resume() override {
- DCHECK(status_ == UNKNOWN);
- status_ = RESUMED;
- }
-
- private:
- Status status_;
-};
-
-// TestIOThreadState ----------------------------------------------------------
-
-enum RedirectMode {
- REDIRECT_MODE_NO_REDIRECT,
- REDIRECT_MODE_302,
-};
-
-class TestIOThreadState {
- public:
- TestIOThreadState(const GURL& url,
- int render_process_id,
- int render_frame_id,
- const std::string& request_method,
- RedirectMode redirect_mode,
- MockInterceptCallbackReceiver* callback_receiver)
- : resource_context_(&test_url_request_context_),
- request_(resource_context_.GetRequestContext()->CreateRequest(
- url,
- net::DEFAULT_PRIORITY,
- NULL /* delegate */)) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- if (render_process_id != MSG_ROUTING_NONE &&
- render_frame_id != MSG_ROUTING_NONE) {
- content::ResourceRequestInfo::AllocateForTesting(
- request_.get(),
- content::RESOURCE_TYPE_MAIN_FRAME,
- &resource_context_,
- render_process_id,
- MSG_ROUTING_NONE,
- render_frame_id,
- true, // is_main_frame
- false, // parent_is_main_frame
- true, // allow_download
- false); // is_async
- }
- throttle_.reset(new InterceptNavigationResourceThrottle(
- request_.get(),
- base::Bind(&MockInterceptCallbackReceiver::ShouldIgnoreNavigation,
- base::Unretained(callback_receiver))));
- throttle_->set_controller_for_testing(&throttle_controller_);
- request_->set_method(request_method);
-
- if (redirect_mode == REDIRECT_MODE_302) {
- net::HttpResponseInfo& response_info =
- const_cast<net::HttpResponseInfo&>(request_->response_info());
- response_info.headers = new net::HttpResponseHeaders(
- "Status: 302 Found\0\0");
- }
- }
-
- void ThrottleWillStartRequest(bool* defer) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- throttle_->WillStartRequest(defer);
- }
-
- void ThrottleWillRedirectRequest(const net::RedirectInfo& redirect_info,
- bool* defer) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- throttle_->WillRedirectRequest(redirect_info, defer);
- }
-
- bool request_resumed() const {
- return throttle_controller_.status() ==
- MockResourceController::RESUMED;
- }
-
- bool request_cancelled() const {
- return throttle_controller_.status() ==
- MockResourceController::CANCELLED;
- }
-
- private:
- net::TestURLRequestContext test_url_request_context_;
- content::MockResourceContext resource_context_;
- scoped_ptr<net::URLRequest> request_;
- scoped_ptr<InterceptNavigationResourceThrottle> throttle_;
- MockResourceController throttle_controller_;
-};
-
-// InterceptNavigationResourceThrottleTest ------------------------------------
-
-class InterceptNavigationResourceThrottleTest
- : public content::RenderViewHostTestHarness {
- public:
- InterceptNavigationResourceThrottleTest()
- : mock_callback_receiver_(new MockInterceptCallbackReceiver()),
- io_thread_state_(NULL) {
- }
-
- void SetUp() override { RenderViewHostTestHarness::SetUp(); }
-
- void TearDown() override {
- if (web_contents())
- web_contents()->SetDelegate(NULL);
-
- content::BrowserThread::DeleteSoon(
- content::BrowserThread::IO, FROM_HERE, io_thread_state_);
-
- RenderViewHostTestHarness::TearDown();
- }
-
- void SetIOThreadState(TestIOThreadState* io_thread_state) {
- io_thread_state_ = io_thread_state;
- }
-
- void RunThrottleWillStartRequestOnIOThread(
- const GURL& url,
- const std::string& request_method,
- RedirectMode redirect_mode,
- int render_process_id,
- int render_frame_id,
- bool* defer) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- TestIOThreadState* io_thread_state =
- new TestIOThreadState(url, render_process_id, render_frame_id,
- request_method, redirect_mode,
- mock_callback_receiver_.get());
-
- SetIOThreadState(io_thread_state);
-
- if (redirect_mode == REDIRECT_MODE_NO_REDIRECT) {
- io_thread_state->ThrottleWillStartRequest(defer);
- } else {
- // 302 redirects convert POSTs to gets.
- net::RedirectInfo redirect_info;
- redirect_info.new_url = url;
- redirect_info.new_method = "GET";
- io_thread_state->ThrottleWillRedirectRequest(redirect_info, defer);
- }
- }
-
- protected:
- enum ShouldIgnoreNavigationCallbackAction {
- IgnoreNavigation,
- DontIgnoreNavigation
- };
-
- void SetUpWebContentsDelegateAndDrainRunLoop(
- ShouldIgnoreNavigationCallbackAction callback_action,
- bool* defer) {
- ON_CALL(*mock_callback_receiver_, ShouldIgnoreNavigation(_, _))
- .WillByDefault(Return(callback_action == IgnoreNavigation));
- EXPECT_CALL(*mock_callback_receiver_,
- ShouldIgnoreNavigation(web_contents(),
- NavigationParamsUrlIsTest()))
- .Times(1);
-
- content::BrowserThread::PostTask(
- content::BrowserThread::IO,
- FROM_HERE,
- base::Bind(
- &InterceptNavigationResourceThrottleTest::
- RunThrottleWillStartRequestOnIOThread,
- base::Unretained(this),
- GURL(kTestUrl),
- "GET",
- REDIRECT_MODE_NO_REDIRECT,
- web_contents()->GetRenderViewHost()->GetProcess()->GetID(),
- web_contents()->GetMainFrame()->GetRoutingID(),
- base::Unretained(defer)));
-
- // Wait for the request to finish processing.
- base::RunLoop().RunUntilIdle();
- }
-
- void WaitForPreviouslyScheduledIoThreadWork() {
- base::WaitableEvent io_thread_work_done(true, false);
- content::BrowserThread::PostTask(
- content::BrowserThread::IO,
- FROM_HERE,
- base::Bind(
- &base::WaitableEvent::Signal,
- base::Unretained(&io_thread_work_done)));
- io_thread_work_done.Wait();
- }
-
- scoped_ptr<MockInterceptCallbackReceiver> mock_callback_receiver_;
- TestIOThreadState* io_thread_state_;
-};
-
-TEST_F(InterceptNavigationResourceThrottleTest,
- RequestDeferredAndResumedIfNavigationNotIgnored) {
- bool defer = false;
- SetUpWebContentsDelegateAndDrainRunLoop(DontIgnoreNavigation, &defer);
-
- EXPECT_TRUE(defer);
- ASSERT_TRUE(io_thread_state_);
- EXPECT_TRUE(io_thread_state_->request_resumed());
-}
-
-TEST_F(InterceptNavigationResourceThrottleTest,
- RequestDeferredAndCancelledIfNavigationIgnored) {
- bool defer = false;
- SetUpWebContentsDelegateAndDrainRunLoop(IgnoreNavigation, &defer);
-
- EXPECT_TRUE(defer);
- ASSERT_TRUE(io_thread_state_);
- EXPECT_TRUE(io_thread_state_->request_cancelled());
-}
-
-TEST_F(InterceptNavigationResourceThrottleTest,
- NoCallbackMadeIfContentsDeletedWhileThrottleRunning) {
- bool defer = false;
-
- // The tested scenario is when the WebContents is deleted after the
- // ResourceThrottle has finished processing on the IO thread but before the
- // UI thread callback has been processed. Since both threads in this test
- // are serviced by one message loop, the post order is the execution order.
- EXPECT_CALL(*mock_callback_receiver_,
- ShouldIgnoreNavigation(_, _))
- .Times(0);
-
- content::BrowserThread::PostTask(
- content::BrowserThread::IO,
- FROM_HERE,
- base::Bind(
- &InterceptNavigationResourceThrottleTest::
- RunThrottleWillStartRequestOnIOThread,
- base::Unretained(this),
- GURL(kTestUrl),
- "GET",
- REDIRECT_MODE_NO_REDIRECT,
- web_contents()->GetRenderViewHost()->GetProcess()->GetID(),
- web_contents()->GetMainFrame()->GetRoutingID(),
- base::Unretained(&defer)));
-
- content::BrowserThread::PostTask(
- content::BrowserThread::UI,
- FROM_HERE,
- base::Bind(
- &RenderViewHostTestHarness::DeleteContents,
- base::Unretained(this)));
-
- // The WebContents will now be deleted and only after that will the UI-thread
- // callback posted by the ResourceThrottle be executed.
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(defer);
- ASSERT_TRUE(io_thread_state_);
- EXPECT_TRUE(io_thread_state_->request_resumed());
-}
-
-TEST_F(InterceptNavigationResourceThrottleTest,
- RequestNotDeferredForRequestNotAssociatedWithARenderView) {
- bool defer = false;
-
- content::BrowserThread::PostTask(
- content::BrowserThread::IO,
- FROM_HERE,
- base::Bind(
- &InterceptNavigationResourceThrottleTest::
- RunThrottleWillStartRequestOnIOThread,
- base::Unretained(this),
- GURL(kTestUrl),
- "GET",
- REDIRECT_MODE_NO_REDIRECT,
- MSG_ROUTING_NONE,
- MSG_ROUTING_NONE,
- base::Unretained(&defer)));
-
- // Wait for the request to finish processing.
- base::RunLoop().RunUntilIdle();
-
- EXPECT_FALSE(defer);
-}
-
-TEST_F(InterceptNavigationResourceThrottleTest,
- CallbackCalledWithFilteredUrl) {
- bool defer = false;
-
- ON_CALL(*mock_callback_receiver_,
- ShouldIgnoreNavigation(_, NavigationParamsUrlIsSafe()))
- .WillByDefault(Return(false));
- EXPECT_CALL(*mock_callback_receiver_,
- ShouldIgnoreNavigation(_, NavigationParamsUrlIsSafe()))
- .Times(1);
-
- content::BrowserThread::PostTask(
- content::BrowserThread::IO,
- FROM_HERE,
- base::Bind(
- &InterceptNavigationResourceThrottleTest::
- RunThrottleWillStartRequestOnIOThread,
- base::Unretained(this),
- GURL(kUnsafeTestUrl),
- "GET",
- REDIRECT_MODE_NO_REDIRECT,
- web_contents()->GetRenderViewHost()->GetProcess()->GetID(),
- web_contents()->GetMainFrame()->GetRoutingID(),
- base::Unretained(&defer)));
-
- // Wait for the request to finish processing.
- base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(InterceptNavigationResourceThrottleTest,
- CallbackIsPostFalseForGet) {
- bool defer = false;
-
- EXPECT_CALL(*mock_callback_receiver_,
- ShouldIgnoreNavigation(_, AllOf(
- NavigationParamsUrlIsSafe(),
- Property(&NavigationParams::is_post, Eq(false)))))
- .WillOnce(Return(false));
-
- content::BrowserThread::PostTask(
- content::BrowserThread::IO,
- FROM_HERE,
- base::Bind(
- &InterceptNavigationResourceThrottleTest::
- RunThrottleWillStartRequestOnIOThread,
- base::Unretained(this),
- GURL(kTestUrl),
- "GET",
- REDIRECT_MODE_NO_REDIRECT,
- web_contents()->GetRenderViewHost()->GetProcess()->GetID(),
- web_contents()->GetMainFrame()->GetRoutingID(),
- base::Unretained(&defer)));
-
- // Wait for the request to finish processing.
- base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(InterceptNavigationResourceThrottleTest,
- CallbackIsPostTrueForPost) {
- bool defer = false;
-
- EXPECT_CALL(*mock_callback_receiver_,
- ShouldIgnoreNavigation(_, AllOf(
- NavigationParamsUrlIsSafe(),
- Property(&NavigationParams::is_post, Eq(true)))))
- .WillOnce(Return(false));
-
- content::BrowserThread::PostTask(
- content::BrowserThread::IO,
- FROM_HERE,
- base::Bind(
- &InterceptNavigationResourceThrottleTest::
- RunThrottleWillStartRequestOnIOThread,
- base::Unretained(this),
- GURL(kTestUrl),
- "POST",
- REDIRECT_MODE_NO_REDIRECT,
- web_contents()->GetRenderViewHost()->GetProcess()->GetID(),
- web_contents()->GetMainFrame()->GetRoutingID(),
- base::Unretained(&defer)));
-
- // Wait for the request to finish processing.
- base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(InterceptNavigationResourceThrottleTest,
- CallbackIsPostFalseForPostConvertedToGetBy302) {
- bool defer = false;
-
- EXPECT_CALL(*mock_callback_receiver_,
- ShouldIgnoreNavigation(_, AllOf(
- NavigationParamsUrlIsSafe(),
- Property(&NavigationParams::is_post, Eq(false)))))
- .WillOnce(Return(false));
-
- content::BrowserThread::PostTask(
- content::BrowserThread::IO,
- FROM_HERE,
- base::Bind(
- &InterceptNavigationResourceThrottleTest::
- RunThrottleWillStartRequestOnIOThread,
- base::Unretained(this),
- GURL(kTestUrl),
- "POST",
- REDIRECT_MODE_302,
- web_contents()->GetRenderViewHost()->GetProcess()->GetID(),
- web_contents()->GetMainFrame()->GetRoutingID(),
- base::Unretained(&defer)));
-
- // Wait for the request to finish processing.
- base::RunLoop().RunUntilIdle();
-}
-
-} // namespace navigation_interception
diff --git a/components/navigation_interception/intercept_navigation_throttle.cc b/components/navigation_interception/intercept_navigation_throttle.cc
new file mode 100644
index 0000000..cc256a1
--- /dev/null
+++ b/components/navigation_interception/intercept_navigation_throttle.cc
@@ -0,0 +1,49 @@
+// Copyright 2015 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 "components/navigation_interception/intercept_navigation_throttle.h"
+
+#include "components/navigation_interception/navigation_params.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_handle.h"
+
+namespace navigation_interception {
+
+InterceptNavigationThrottle::InterceptNavigationThrottle(
+ content::NavigationHandle* navigation_handle,
+ CheckCallback should_ignore_callback)
+ : content::NavigationThrottle(navigation_handle),
+ should_ignore_callback_(should_ignore_callback) {}
+
+InterceptNavigationThrottle::~InterceptNavigationThrottle() {}
+
+content::NavigationThrottle::ThrottleCheckResult
+InterceptNavigationThrottle::WillStartRequest() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ return CheckIfShouldIgnoreNavigation(false);
+}
+
+content::NavigationThrottle::ThrottleCheckResult
+InterceptNavigationThrottle::WillRedirectRequest() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ return CheckIfShouldIgnoreNavigation(true);
+}
+
+content::NavigationThrottle::ThrottleCheckResult
+InterceptNavigationThrottle::CheckIfShouldIgnoreNavigation(bool is_redirect) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ NavigationParams navigation_params(
+ navigation_handle()->GetURL(), navigation_handle()->GetReferrer(),
+ navigation_handle()->HasUserGesture(), navigation_handle()->IsPost(),
+ navigation_handle()->GetPageTransition(), is_redirect,
+ navigation_handle()->IsExternalProtocol(), true);
+
+ bool should_ignore_navigation = should_ignore_callback_.Run(
+ navigation_handle()->GetWebContents(), navigation_params);
+ return should_ignore_navigation
+ ? content::NavigationThrottle::CANCEL_AND_IGNORE
+ : content::NavigationThrottle::PROCEED;
+}
+
+} // namespace navigation_interception
diff --git a/components/navigation_interception/intercept_navigation_throttle.h b/components/navigation_interception/intercept_navigation_throttle.h
new file mode 100644
index 0000000..0b7f746
--- /dev/null
+++ b/components/navigation_interception/intercept_navigation_throttle.h
@@ -0,0 +1,51 @@
+// Copyright 2015 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 COMPONENTS_NAVIGATION_INTERCEPTION_INTERCEPT_NAVIGATION_THROTTLE_H_
+#define COMPONENTS_NAVIGATION_INTERCEPTION_INTERCEPT_NAVIGATION_THROTTLE_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "content/public/browser/navigation_throttle.h"
+
+class GURL;
+
+namespace content {
+class NavigationHandle;
+class WebContents;
+}
+
+namespace navigation_interception {
+
+class NavigationParams;
+
+// This class allows the provider of the Callback to selectively ignore top
+// level navigations. This is a UI thread class.
+class InterceptNavigationThrottle : public content::NavigationThrottle {
+ public:
+ typedef base::Callback<bool(content::WebContents* /* source */,
+ const NavigationParams& /* navigation_params */)>
+ CheckCallback;
+
+ InterceptNavigationThrottle(content::NavigationHandle* navigation_handle,
+ CheckCallback should_ignore_callback);
+ ~InterceptNavigationThrottle() override;
+
+ // content::NavigationThrottle implementation:
+ ThrottleCheckResult WillStartRequest() override;
+ ThrottleCheckResult WillRedirectRequest() override;
+
+ private:
+ ThrottleCheckResult CheckIfShouldIgnoreNavigation(bool is_redirect);
+
+ CheckCallback should_ignore_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(InterceptNavigationThrottle);
+};
+
+} // namespace navigation_interception
+
+#endif // COMPONENTS_NAVIGATION_INTERCEPTION_INTERCEPT_NAVIGATION_THROTTLE_H_
diff --git a/components/navigation_interception/intercept_navigation_throttle_unittest.cc b/components/navigation_interception/intercept_navigation_throttle_unittest.cc
new file mode 100644
index 0000000..15e05ef
--- /dev/null
+++ b/components/navigation_interception/intercept_navigation_throttle_unittest.cc
@@ -0,0 +1,165 @@
+// Copyright 2015 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 "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/scoped_ptr.h"
+#include "components/navigation_interception/intercept_navigation_throttle.h"
+#include "components/navigation_interception/navigation_params.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/navigation_throttle.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/test_renderer_host.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using content::NavigationThrottle;
+using testing::_;
+using testing::Eq;
+using testing::Ne;
+using testing::Property;
+using testing::Return;
+
+namespace navigation_interception {
+
+namespace {
+
+const char kTestUrl[] = "http://www.test.com/";
+
+// The MS C++ compiler complains about not being able to resolve which url()
+// method (const or non-const) to use if we use the Property matcher to check
+// the return value of the NavigationParams::url() method.
+// It is possible to suppress the error by specifying the types directly but
+// that results in very ugly syntax, which is why these custom matchers are
+// used instead.
+MATCHER(NavigationParamsUrlIsTest, "") {
+ return arg.url() == GURL(kTestUrl);
+}
+
+} // namespace
+
+// MockInterceptCallbackReceiver ----------------------------------------------
+
+class MockInterceptCallbackReceiver {
+ public:
+ MOCK_METHOD2(ShouldIgnoreNavigation,
+ bool(content::WebContents* source,
+ const NavigationParams& navigation_params));
+};
+
+// InterceptNavigationThrottleTest ------------------------------------
+
+class InterceptNavigationThrottleTest
+ : public content::RenderViewHostTestHarness {
+ public:
+ InterceptNavigationThrottleTest()
+ : mock_callback_receiver_(new MockInterceptCallbackReceiver()) {}
+
+ NavigationThrottle::ThrottleCheckResult
+ SimulateWillStart(const GURL& url, const GURL& sanitized_url, bool is_post) {
+ scoped_ptr<content::NavigationHandle> test_handle =
+ content::NavigationHandle::CreateNavigationHandleForTesting(
+ url, true, web_contents());
+ test_handle->RegisterThrottleForTesting(
+ scoped_ptr<NavigationThrottle>(
+ new InterceptNavigationThrottle(
+ test_handle.get(),
+ base::Bind(
+ &MockInterceptCallbackReceiver::ShouldIgnoreNavigation,
+ base::Unretained(mock_callback_receiver_.get()))))
+ .Pass());
+ return test_handle->CallWillStartRequestForTesting(
+ is_post, content::Referrer(), false, ui::PAGE_TRANSITION_LINK, false);
+ }
+
+ NavigationThrottle::ThrottleCheckResult Simulate302() {
+ scoped_ptr<content::NavigationHandle> test_handle =
+ content::NavigationHandle::CreateNavigationHandleForTesting(
+ GURL(kTestUrl), true, web_contents());
+ test_handle->RegisterThrottleForTesting(
+ scoped_ptr<NavigationThrottle>(
+ new InterceptNavigationThrottle(
+ test_handle.get(),
+ base::Bind(
+ &MockInterceptCallbackReceiver::ShouldIgnoreNavigation,
+ base::Unretained(mock_callback_receiver_.get()))))
+ .Pass());
+ test_handle->CallWillStartRequestForTesting(
+ true, content::Referrer(), false, ui::PAGE_TRANSITION_LINK, false);
+ return test_handle->CallWillRedirectRequestForTesting(GURL(kTestUrl), false,
+ GURL(), false);
+ }
+
+ scoped_ptr<MockInterceptCallbackReceiver> mock_callback_receiver_;
+};
+
+TEST_F(InterceptNavigationThrottleTest,
+ RequestDeferredAndResumedIfNavigationNotIgnored) {
+ ON_CALL(*mock_callback_receiver_, ShouldIgnoreNavigation(_, _))
+ .WillByDefault(Return(false));
+ EXPECT_CALL(
+ *mock_callback_receiver_,
+ ShouldIgnoreNavigation(web_contents(), NavigationParamsUrlIsTest()));
+ NavigationThrottle::ThrottleCheckResult result =
+ SimulateWillStart(GURL(kTestUrl), GURL(kTestUrl), false);
+
+ EXPECT_EQ(NavigationThrottle::PROCEED, result);
+}
+
+TEST_F(InterceptNavigationThrottleTest,
+ RequestDeferredAndCancelledIfNavigationIgnored) {
+ ON_CALL(*mock_callback_receiver_, ShouldIgnoreNavigation(_, _))
+ .WillByDefault(Return(true));
+ EXPECT_CALL(
+ *mock_callback_receiver_,
+ ShouldIgnoreNavigation(web_contents(), NavigationParamsUrlIsTest()));
+ NavigationThrottle::ThrottleCheckResult result =
+ SimulateWillStart(GURL(kTestUrl), GURL(kTestUrl), false);
+
+ EXPECT_EQ(NavigationThrottle::CANCEL_AND_IGNORE, result);
+}
+
+TEST_F(InterceptNavigationThrottleTest, CallbackIsPostFalseForGet) {
+ EXPECT_CALL(*mock_callback_receiver_,
+ ShouldIgnoreNavigation(
+ _, AllOf(NavigationParamsUrlIsTest(),
+ Property(&NavigationParams::is_post, Eq(false)))))
+ .WillOnce(Return(false));
+
+ NavigationThrottle::ThrottleCheckResult result =
+ SimulateWillStart(GURL(kTestUrl), GURL(kTestUrl), false);
+
+ EXPECT_EQ(NavigationThrottle::PROCEED, result);
+}
+
+TEST_F(InterceptNavigationThrottleTest, CallbackIsPostTrueForPost) {
+ EXPECT_CALL(*mock_callback_receiver_,
+ ShouldIgnoreNavigation(
+ _, AllOf(NavigationParamsUrlIsTest(),
+ Property(&NavigationParams::is_post, Eq(true)))))
+ .WillOnce(Return(false));
+ NavigationThrottle::ThrottleCheckResult result =
+ SimulateWillStart(GURL(kTestUrl), GURL(kTestUrl), true);
+
+ EXPECT_EQ(NavigationThrottle::PROCEED, result);
+}
+
+TEST_F(InterceptNavigationThrottleTest,
+ CallbackIsPostFalseForPostConvertedToGetBy302) {
+ EXPECT_CALL(*mock_callback_receiver_,
+ ShouldIgnoreNavigation(
+ _, AllOf(NavigationParamsUrlIsTest(),
+ Property(&NavigationParams::is_post, Eq(true)))))
+ .WillOnce(Return(false));
+ EXPECT_CALL(*mock_callback_receiver_,
+ ShouldIgnoreNavigation(
+ _, AllOf(NavigationParamsUrlIsTest(),
+ Property(&NavigationParams::is_post, Eq(false)))))
+ .WillOnce(Return(false));
+ NavigationThrottle::ThrottleCheckResult result = Simulate302();
+
+ EXPECT_EQ(NavigationThrottle::PROCEED, result);
+}
+
+} // namespace navigation_interception
diff --git a/content/browser/frame_host/navigation_handle_impl.cc b/content/browser/frame_host/navigation_handle_impl.cc
index 2c5e773..994a2fc 100644
--- a/content/browser/frame_host/navigation_handle_impl.cc
+++ b/content/browser/frame_host/navigation_handle_impl.cc
@@ -5,6 +5,8 @@
#include "content/browser/frame_host/navigation_handle_impl.h"
#include "content/browser/frame_host/navigator_delegate.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/common/content_client.h"
#include "net/url_request/redirect_info.h"
namespace content {
@@ -12,7 +14,7 @@ namespace content {
// static
scoped_ptr<NavigationHandleImpl> NavigationHandleImpl::Create(
const GURL& url,
- const bool is_main_frame,
+ bool is_main_frame,
NavigatorDelegate* delegate) {
return scoped_ptr<NavigationHandleImpl>(
new NavigationHandleImpl(url, is_main_frame, delegate));
@@ -22,10 +24,14 @@ NavigationHandleImpl::NavigationHandleImpl(const GURL& url,
const bool is_main_frame,
NavigatorDelegate* delegate)
: url_(url),
- net_error_code_(net::OK),
- state_(DID_START),
is_main_frame_(is_main_frame),
+ is_post_(false),
+ has_user_gesture_(false),
+ transition_(ui::PAGE_TRANSITION_LINK),
+ is_external_protocol_(false),
+ net_error_code_(net::OK),
is_same_page_(false),
+ state_(INITIAL),
is_transferring_(false),
delegate_(delegate) {
delegate_->DidStartNavigation(this);
@@ -35,16 +41,46 @@ NavigationHandleImpl::~NavigationHandleImpl() {
delegate_->DidFinishNavigation(this);
}
-const GURL& NavigationHandleImpl::GetURL() const {
+const GURL& NavigationHandleImpl::GetURL() {
return url_;
}
-net::Error NavigationHandleImpl::GetNetErrorCode() const {
- return net_error_code_;
+bool NavigationHandleImpl::IsInMainFrame() {
+ return is_main_frame_;
}
-bool NavigationHandleImpl::IsInMainFrame() const {
- return is_main_frame_;
+bool NavigationHandleImpl::IsPost() {
+ CHECK_NE(INITIAL, state_)
+ << "This accessor should not be called before the request is started.";
+ return is_post_;
+}
+
+const Referrer& NavigationHandleImpl::GetReferrer() {
+ CHECK_NE(INITIAL, state_)
+ << "This accessor should not be called before the request is started.";
+ return sanitized_referrer_;
+}
+
+bool NavigationHandleImpl::HasUserGesture() {
+ CHECK_NE(INITIAL, state_)
+ << "This accessor should not be called before the request is started.";
+ return has_user_gesture_;
+}
+
+ui::PageTransition NavigationHandleImpl::GetPageTransition() {
+ CHECK_NE(INITIAL, state_)
+ << "This accessor should not be called before the request is started.";
+ return transition_;
+}
+
+bool NavigationHandleImpl::IsExternalProtocol() {
+ CHECK_NE(INITIAL, state_)
+ << "This accessor should not be called before the request is started.";
+ return is_external_protocol_;
+}
+
+net::Error NavigationHandleImpl::GetNetErrorCode() {
+ return net_error_code_;
}
bool NavigationHandleImpl::IsSamePage() {
@@ -54,14 +90,99 @@ bool NavigationHandleImpl::IsSamePage() {
return is_same_page_;
}
-bool NavigationHandleImpl::HasCommittedDocument() const {
+bool NavigationHandleImpl::HasCommittedDocument() {
return state_ == DID_COMMIT;
}
-bool NavigationHandleImpl::HasCommittedErrorPage() const {
+bool NavigationHandleImpl::HasCommittedErrorPage() {
return state_ == DID_COMMIT_ERROR_PAGE;
}
+void NavigationHandleImpl::RegisterThrottleForTesting(
+ scoped_ptr<NavigationThrottle> navigation_throttle) {
+ throttles_.push_back(navigation_throttle.Pass());
+}
+
+NavigationThrottle::ThrottleCheckResult
+NavigationHandleImpl::CallWillStartRequestForTesting(
+ bool is_post,
+ const Referrer& sanitized_referrer,
+ bool has_user_gesture,
+ ui::PageTransition transition,
+ bool is_external_protocol) {
+ return WillStartRequest(is_post, sanitized_referrer, has_user_gesture,
+ transition, is_external_protocol);
+}
+
+NavigationThrottle::ThrottleCheckResult
+NavigationHandleImpl::CallWillRedirectRequestForTesting(
+ const GURL& new_url,
+ bool new_method_is_post,
+ const GURL& new_referrer_url,
+ bool new_is_external_protocol) {
+ return WillRedirectRequest(new_url, new_method_is_post, new_referrer_url,
+ new_is_external_protocol);
+}
+
+NavigationThrottle::ThrottleCheckResult NavigationHandleImpl::WillStartRequest(
+ bool is_post,
+ const Referrer& sanitized_referrer,
+ bool has_user_gesture,
+ ui::PageTransition transition,
+ bool is_external_protocol) {
+ // Update the navigation parameters.
+ is_post_ = is_post;
+ sanitized_referrer_ = sanitized_referrer;
+ has_user_gesture_ = has_user_gesture;
+ transition_ = transition;
+ is_external_protocol_ = is_external_protocol;
+
+ state_ = WILL_SEND_REQUEST;
+
+ // Register the navigation throttles. The ScopedVector returned by
+ // GetNavigationThrottles is not assigned to throttles_ directly because it
+ // would overwrite any throttle previously added with
+ // RegisterThrottleForTesting.
+ ScopedVector<NavigationThrottle> throttles_to_register =
+ GetContentClient()->browser()->CreateThrottlesForNavigation(this);
+ if (throttles_to_register.size() > 0) {
+ throttles_.insert(throttles_.end(), throttles_to_register.begin(),
+ throttles_to_register.end());
+ throttles_to_register.weak_clear();
+ }
+
+ // Notify each throttle of the request.
+ for (NavigationThrottle* throttle : throttles_) {
+ NavigationThrottle::ThrottleCheckResult result =
+ throttle->WillStartRequest();
+ if (result == NavigationThrottle::CANCEL_AND_IGNORE)
+ return NavigationThrottle::CANCEL_AND_IGNORE;
+ }
+ return NavigationThrottle::PROCEED;
+}
+
+NavigationThrottle::ThrottleCheckResult
+NavigationHandleImpl::WillRedirectRequest(const GURL& new_url,
+ bool new_method_is_post,
+ const GURL& new_referrer_url,
+ bool new_is_external_protocol) {
+ // Update the navigation parameters.
+ url_ = new_url;
+ is_post_ = new_method_is_post;
+ sanitized_referrer_.url = new_referrer_url;
+ sanitized_referrer_ = Referrer::SanitizeForRequest(url_, sanitized_referrer_);
+ is_external_protocol_ = new_is_external_protocol;
+
+ // Have each throttle be notified of the request.
+ for (NavigationThrottle* throttle : throttles_) {
+ NavigationThrottle::ThrottleCheckResult result =
+ throttle->WillRedirectRequest();
+ if (result == NavigationThrottle::CANCEL_AND_IGNORE)
+ return NavigationThrottle::CANCEL_AND_IGNORE;
+ }
+ return NavigationThrottle::PROCEED;
+}
+
void NavigationHandleImpl::DidRedirectNavigation(const GURL& new_url) {
url_ = new_url;
delegate_->DidRedirectNavigation(this);
diff --git a/content/browser/frame_host/navigation_handle_impl.h b/content/browser/frame_host/navigation_handle_impl.h
index 861adb0..aebb929 100644
--- a/content/browser/frame_host/navigation_handle_impl.h
+++ b/content/browser/frame_host/navigation_handle_impl.h
@@ -9,7 +9,9 @@
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
#include "content/common/content_export.h"
+#include "content/public/browser/navigation_throttle.h"
#include "url/gurl.h"
namespace content {
@@ -53,18 +55,37 @@ struct NavigationRequestInfo;
class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
public:
static scoped_ptr<NavigationHandleImpl> Create(const GURL& url,
- const bool is_main_frame,
+ bool is_main_frame,
NavigatorDelegate* delegate);
-
~NavigationHandleImpl() override;
// NavigationHandle implementation:
- const GURL& GetURL() const override;
- net::Error GetNetErrorCode() const override;
- bool IsInMainFrame() const override;
+ const GURL& GetURL() override;
+ bool IsInMainFrame() override;
+ bool IsPost() override;
+ const Referrer& GetReferrer() override;
+ bool HasUserGesture() override;
+ ui::PageTransition GetPageTransition() override;
+ bool IsExternalProtocol() override;
+ net::Error GetNetErrorCode() override;
bool IsSamePage() override;
- bool HasCommittedDocument() const override;
- bool HasCommittedErrorPage() const override;
+ bool HasCommittedDocument() override;
+ bool HasCommittedErrorPage() override;
+ void RegisterThrottleForTesting(
+ scoped_ptr<NavigationThrottle> navigation_throttle) override;
+ NavigationThrottle::ThrottleCheckResult CallWillStartRequestForTesting(
+ bool is_post,
+ const Referrer& sanitized_referrer,
+ bool has_user_gesture,
+ ui::PageTransition transition,
+ bool is_external_protocol) override;
+ NavigationThrottle::ThrottleCheckResult CallWillRedirectRequestForTesting(
+ const GURL& new_url,
+ bool new_method_is_post,
+ const GURL& new_referrer_url,
+ bool new_is_external_protocol) override;
+
+ NavigatorDelegate* delegate() const { return delegate_; }
void set_net_error_code(net::Error net_error_code) {
net_error_code_ = net_error_code;
@@ -79,6 +100,21 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
is_transferring_ = is_transferring;
}
+ // Called when the URLRequest will start in the network stack.
+ NavigationThrottle::ThrottleCheckResult WillStartRequest(
+ bool is_post,
+ const Referrer& sanitized_referrer,
+ bool has_user_gesture,
+ ui::PageTransition transition,
+ bool is_external_protocol);
+
+ // Called when the URLRequest will be redirected in the network stack.
+ NavigationThrottle::ThrottleCheckResult WillRedirectRequest(
+ const GURL& new_url,
+ bool new_method_is_post,
+ const GURL& new_referrer_url,
+ bool new_is_external_protocol);
+
// Called when the navigation was redirected. This will update the |url_| and
// inform the delegate.
void DidRedirectNavigation(const GURL& new_url);
@@ -90,7 +126,8 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
private:
// Used to track the state the navigation is currently in.
enum State {
- DID_START = 0,
+ INITIAL = 0,
+ WILL_SEND_REQUEST,
DID_COMMIT,
DID_COMMIT_ERROR_PAGE,
};
@@ -101,11 +138,18 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
// See NavigationHandle for a description of those member variables.
GURL url_;
- net::Error net_error_code_;
- State state_;
const bool is_main_frame_;
+ bool is_post_;
+ Referrer sanitized_referrer_;
+ bool has_user_gesture_;
+ ui::PageTransition transition_;
+ bool is_external_protocol_;
+ net::Error net_error_code_;
bool is_same_page_;
+ // The state the navigation is in.
+ State state_;
+
// Whether the navigation is in the middle of a transfer. Set to false when
// the DidStartProvisionalLoad is received from the new renderer.
bool is_transferring_;
@@ -114,6 +158,9 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
// navigation.
NavigatorDelegate* delegate_;
+ // A list of Throttles registered for this navigation.
+ ScopedVector<NavigationThrottle> throttles_;
+
DISALLOW_COPY_AND_ASSIGN(NavigationHandleImpl);
};
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index a99074f..8247f35 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -14,6 +14,7 @@
#include "content/browser/site_instance_impl.h"
#include "content/common/resource_request_body.h"
#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/navigation_throttle.h"
#include "content/public/browser/stream_handle.h"
#include "content/public/common/content_client.h"
#include "net/base/load_flags.h"
@@ -179,6 +180,20 @@ bool NavigationRequest::BeginNavigation() {
state_ = STARTED;
if (ShouldMakeNetworkRequestForURL(common_params_.url)) {
+ // TODO(clamy): pass the real value for |is_external_protocol| if needed.
+ NavigationThrottle::ThrottleCheckResult result =
+ navigation_handle_->WillStartRequest(
+ begin_params_.method == "POST",
+ Referrer::SanitizeForRequest(common_params_.url,
+ common_params_.referrer),
+ begin_params_.has_user_gesture, common_params_.transition, false);
+
+ // Abort the request if needed. This will destroy the NavigationRequest.
+ if (result == NavigationThrottle::CANCEL_AND_IGNORE) {
+ frame_tree_node_->ResetNavigationRequest(false);
+ return false;
+ }
+
loader_ = NavigationURLLoader::Create(
frame_tree_node_->navigator()->GetController()->GetBrowserContext(),
frame_tree_node_->frame_tree_node_id(), info_.Pass(), this);
@@ -209,12 +224,24 @@ void NavigationRequest::TransferNavigationHandleOwnership(
void NavigationRequest::OnRequestRedirected(
const net::RedirectInfo& redirect_info,
const scoped_refptr<ResourceResponse>& response) {
- // TODO(davidben): Track other changes from redirects. These are important
- // for, e.g., reloads.
common_params_.url = redirect_info.new_url;
+ begin_params_.method = redirect_info.new_method;
+ common_params_.referrer.url = GURL(redirect_info.new_referrer);
+
+ // TODO(clamy): Have CSP + security upgrade checks here.
+ // TODO(clamy): Kill the renderer if FilterURL fails?
+ // TODO(clamy): pass the real value for |is_external_protocol| if needed.
+ NavigationThrottle::ThrottleCheckResult result =
+ navigation_handle_->WillRedirectRequest(
+ common_params_.url, begin_params_.method == "POST",
+ common_params_.referrer.url, false);
+
+ // Abort the request if needed. This will destroy the NavigationRequest.
+ if (result == NavigationThrottle::CANCEL_AND_IGNORE) {
+ frame_tree_node_->ResetNavigationRequest(false);
+ return;
+ }
- // TODO(davidben): This where prerender and navigation_interceptor should be
- // integrated. For now, just always follow all redirects.
loader_->FollowRedirect();
navigation_handle_->DidRedirectNavigation(redirect_info.new_url);
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h
index a1530b4..b711278 100644
--- a/content/browser/frame_host/navigation_request.h
+++ b/content/browser/frame_host/navigation_request.h
@@ -164,8 +164,10 @@ class CONTENT_EXPORT NavigationRequest : public NavigationURLLoaderDelegate {
// Note: When the navigation is ready to commit, the url in |common_params|
// will be set to the final navigation url, obtained after following all
// redirects.
+ // Note: |common_params_| and |begin_params_| are not const as they can be
+ // modified during redirects.
CommonNavigationParams common_params_;
- const BeginNavigationParams begin_params_;
+ BeginNavigationParams begin_params_;
const RequestNavigationParams request_params_;
const bool browser_initiated_;
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index b03e232..fa0c049 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -159,7 +159,7 @@ void NavigatorImpl::DidStartProvisionalLoad(
}
render_frame_host->SetNavigationHandle(
- NavigationHandleImpl::Create(url, is_main_frame, delegate_));
+ NavigationHandleImpl::Create(validated_url, is_main_frame, delegate_));
}
void NavigatorImpl::DidFailProvisionalLoadWithError(
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 8f6c99c..aed2daa 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1359,8 +1359,10 @@ void RenderFrameHostImpl::OnBeginNavigation(
scoped_refptr<ResourceRequestBody> body) {
CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableBrowserSideNavigation));
+ CommonNavigationParams validated_params = common_params;
+ GetProcess()->FilterURL(false, &validated_params.url);
frame_tree_node()->navigator()->OnBeginNavigation(
- frame_tree_node(), common_params, begin_params, body);
+ frame_tree_node(), validated_params, begin_params, body);
}
void RenderFrameHostImpl::OnDispatchLoad() {
diff --git a/content/browser/loader/navigation_resource_throttle.cc b/content/browser/loader/navigation_resource_throttle.cc
new file mode 100644
index 0000000..8dd143c
--- /dev/null
+++ b/content/browser/loader/navigation_resource_throttle.cc
@@ -0,0 +1,154 @@
+// Copyright 2015 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/loader/navigation_resource_throttle.h"
+
+#include "base/callback.h"
+#include "content/browser/frame_host/navigation_handle_impl.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/public/browser/resource_context.h"
+#include "content/public/browser/resource_controller.h"
+#include "content/public/browser/resource_request_info.h"
+#include "content/public/common/referrer.h"
+#include "net/url_request/redirect_info.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_job_factory.h"
+#include "ui/base/page_transition_types.h"
+
+namespace content {
+
+namespace {
+typedef base::Callback<void(NavigationThrottle::ThrottleCheckResult)>
+ UIChecksPerformedCallback;
+
+void CheckWillStartRequestOnUIThread(UIChecksPerformedCallback callback,
+ int render_process_id,
+ int render_frame_host_id,
+ bool is_post,
+ const Referrer& sanitized_referrer,
+ bool has_user_gesture,
+ ui::PageTransition transition,
+ bool is_external_protocol) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ NavigationThrottle::ThrottleCheckResult result = NavigationThrottle::PROCEED;
+ RenderFrameHostImpl* render_frame_host =
+ RenderFrameHostImpl::FromID(render_process_id, render_frame_host_id);
+ if (render_frame_host) {
+ NavigationHandleImpl* navigation_handle =
+ render_frame_host->navigation_handle();
+ if (navigation_handle) {
+ result = navigation_handle->WillStartRequest(is_post, sanitized_referrer,
+ has_user_gesture, transition,
+ is_external_protocol);
+ }
+ }
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(callback, result));
+}
+
+void CheckWillRedirectRequestOnUIThread(UIChecksPerformedCallback callback,
+ int render_process_id,
+ int render_frame_host_id,
+ const GURL& new_url,
+ bool new_method_is_post,
+ const GURL& new_referrer_url,
+ bool new_is_external_protocol) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ NavigationThrottle::ThrottleCheckResult result = NavigationThrottle::PROCEED;
+ RenderFrameHostImpl* render_frame_host =
+ RenderFrameHostImpl::FromID(render_process_id, render_frame_host_id);
+ if (render_frame_host) {
+ NavigationHandleImpl* navigation_handle =
+ render_frame_host->navigation_handle();
+ if (navigation_handle) {
+ RenderProcessHost* rph = RenderProcessHost::FromID(render_process_id);
+ GURL new_validated_url = new_url;
+ rph->FilterURL(false, &new_validated_url);
+ result = navigation_handle->WillRedirectRequest(
+ new_validated_url, new_method_is_post, new_referrer_url,
+ new_is_external_protocol);
+ }
+ }
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(callback, result));
+}
+} // namespace
+
+NavigationResourceThrottle::NavigationResourceThrottle(net::URLRequest* request)
+ : request_(request), weak_ptr_factory_(this) {}
+
+NavigationResourceThrottle::~NavigationResourceThrottle() {}
+
+void NavigationResourceThrottle::WillStartRequest(bool* defer) {
+ const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_);
+ if (!info)
+ return;
+
+ int render_process_id, render_frame_id;
+ if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_id))
+ return;
+
+ bool is_external_protocol =
+ !info->GetContext()->GetRequestContext()->job_factory()->IsHandledURL(
+ request_->url());
+ UIChecksPerformedCallback callback =
+ base::Bind(&NavigationResourceThrottle::OnUIChecksPerformed,
+ weak_ptr_factory_.GetWeakPtr());
+ DCHECK(request_->method() == "POST" || request_->method() == "GET");
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&CheckWillStartRequestOnUIThread, callback, render_process_id,
+ render_frame_id, request_->method() == "POST",
+ Referrer::SanitizeForRequest(
+ request_->url(), Referrer(GURL(request_->referrer()),
+ info->GetReferrerPolicy())),
+ info->HasUserGesture(), info->GetPageTransition(),
+ is_external_protocol));
+ *defer = true;
+}
+
+void NavigationResourceThrottle::WillRedirectRequest(
+ const net::RedirectInfo& redirect_info,
+ bool* defer) {
+ const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_);
+ if (!info)
+ return;
+
+ int render_process_id, render_frame_id;
+ if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_id))
+ return;
+
+ bool new_is_external_protocol =
+ !info->GetContext()->GetRequestContext()->job_factory()->IsHandledURL(
+ request_->url());
+ DCHECK(redirect_info.new_method == "POST" ||
+ redirect_info.new_method == "GET");
+ UIChecksPerformedCallback callback =
+ base::Bind(&NavigationResourceThrottle::OnUIChecksPerformed,
+ weak_ptr_factory_.GetWeakPtr());
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&CheckWillRedirectRequestOnUIThread, callback,
+ render_process_id, render_frame_id, redirect_info.new_url,
+ redirect_info.new_method == "POST",
+ GURL(redirect_info.new_referrer), new_is_external_protocol));
+ *defer = true;
+}
+
+const char* NavigationResourceThrottle::GetNameForLogging() const {
+ return "NavigationResourceThrottle";
+}
+
+void NavigationResourceThrottle::OnUIChecksPerformed(
+ NavigationThrottle::ThrottleCheckResult result) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (result == NavigationThrottle::CANCEL_AND_IGNORE) {
+ controller()->CancelAndIgnore();
+ } else {
+ controller()->Resume();
+ }
+}
+
+} // namespace content
diff --git a/content/browser/loader/navigation_resource_throttle.h b/content/browser/loader/navigation_resource_throttle.h
new file mode 100644
index 0000000..e46b59d
--- /dev/null
+++ b/content/browser/loader/navigation_resource_throttle.h
@@ -0,0 +1,44 @@
+// Copyright 2015 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_LOADER_NAVIGATION_RESOURCE_THROTTLE_H_
+#define CONTENT_BROWSER_LOADER_NAVIGATION_RESOURCE_THROTTLE_H_
+
+#include "base/basictypes.h"
+#include "base/memory/weak_ptr.h"
+#include "content/public/browser/navigation_throttle.h"
+#include "content/public/browser/resource_throttle.h"
+
+namespace net {
+class URLRequest;
+}
+
+namespace content {
+
+// This ResourceThrottle is used to convey throttling information to the UI
+// thread during navigations. The UI thread can then use its NavigationThrottle
+// mechanism to interact with the navigation.
+class NavigationResourceThrottle : public ResourceThrottle {
+ public:
+ NavigationResourceThrottle(net::URLRequest* request);
+ ~NavigationResourceThrottle() override;
+
+ // ResourceThrottle overrides:
+ void WillStartRequest(bool* defer) override;
+ void WillRedirectRequest(const net::RedirectInfo& redirect_info,
+ bool* defer) override;
+ const char* GetNameForLogging() const override;
+
+ private:
+ void OnUIChecksPerformed(NavigationThrottle::ThrottleCheckResult result);
+
+ net::URLRequest* request_;
+ base::WeakPtrFactory<NavigationResourceThrottle> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(NavigationResourceThrottle);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_LOADER_NAVIGATION_RESOURCE_THROTTLE_H_
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index c5c6796..81cbf8a 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -41,6 +41,7 @@
#include "content/browser/loader/detachable_resource_handler.h"
#include "content/browser/loader/mime_type_resource_handler.h"
#include "content/browser/loader/navigation_resource_handler.h"
+#include "content/browser/loader/navigation_resource_throttle.h"
#include "content/browser/loader/navigation_url_loader_impl_core.h"
#include "content/browser/loader/power_save_block_resource_throttle.h"
#include "content/browser/loader/redirect_to_file_resource_handler.h"
@@ -1481,6 +1482,16 @@ scoped_ptr<ResourceHandler> ResourceDispatcherHostImpl::AddStandardHandlers(
plugin_service, request));
ScopedVector<ResourceThrottle> throttles;
+
+ // Add a NavigationResourceThrottle for navigations.
+ // PlzNavigate: the throttle is unnecessary as communication with the UI
+ // thread is handled by the NavigationURLloader.
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation) &&
+ IsResourceTypeFrame(resource_type)) {
+ throttles.push_back(new NavigationResourceThrottle(request));
+ }
+
if (delegate_) {
delegate_->RequestBeginning(request,
resource_context,
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 182628e..f562da9 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -182,7 +182,10 @@
'public/browser/navigation_details.cc',
'public/browser/navigation_details.h',
'public/browser/navigation_entry.h',
+ 'public/browser/navigation_handle.cc',
'public/browser/navigation_handle.h',
+ 'public/browser/navigation_throttle.cc',
+ 'public/browser/navigation_throttle.h',
'public/browser/navigation_type.h',
'public/browser/navigator_connect_context.h',
'public/browser/navigator_connect_service_factory.h',
@@ -972,6 +975,8 @@
'browser/loader/mime_type_resource_handler.h',
'browser/loader/navigation_resource_handler.cc',
'browser/loader/navigation_resource_handler.h',
+ 'browser/loader/navigation_resource_throttle.cc',
+ 'browser/loader/navigation_resource_throttle.h',
'browser/loader/navigation_url_loader.cc',
'browser/loader/navigation_url_loader.h',
'browser/loader/navigation_url_loader_delegate.h',
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 01b58bd..f25c84a 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -359,6 +359,12 @@ void ContentBrowserClient::OpenURL(
callback.Run(nullptr);
}
+ScopedVector<NavigationThrottle>
+ContentBrowserClient::CreateThrottlesForNavigation(
+ NavigationHandle* navigation_handle) {
+ return ScopedVector<NavigationThrottle>();
+}
+
#if defined(OS_WIN)
const wchar_t* ContentBrowserClient::GetResourceDllName() {
return nullptr;
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 2c6734c..55569fb 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -16,6 +16,7 @@
#include "base/memory/scoped_vector.h"
#include "base/values.h"
#include "content/public/browser/certificate_request_result_type.h"
+#include "content/public/browser/navigation_throttle.h"
#include "content/public/common/content_client.h"
#include "content/public/common/media_stream_request.h"
#include "content/public/common/resource_type.h"
@@ -96,6 +97,7 @@ class DevToolsManagerDelegate;
class ExternalVideoSurfaceContainer;
class LocationProvider;
class MediaObserver;
+class NavigationHandle;
class NavigatorConnectContext;
class NavigatorConnectServiceFactory;
class PlatformNotificationService;
@@ -669,6 +671,14 @@ class CONTENT_EXPORT ContentBrowserClient {
// Allows the embedder to record |metric| for a specific |url|.
virtual void RecordURLMetric(const std::string& metric, const GURL& url) {}
+ // Allows the embedder to register one or more NavigationThrottles for the
+ // navigation indicated by |navigation_handle|. A NavigationThrottle is used
+ // to control the flow of a navigation on the UI thread. The embedder is
+ // guaranteed that the throttles will be executed in the order they were
+ // provided.
+ virtual ScopedVector<NavigationThrottle> CreateThrottlesForNavigation(
+ NavigationHandle* navigation_handle);
+
// Populates |mappings| with all files that need to be mapped before launching
// a child process.
#if defined(OS_ANDROID)
diff --git a/content/public/browser/navigation_handle.cc b/content/public/browser/navigation_handle.cc
new file mode 100644
index 0000000..f5eaa11
--- /dev/null
+++ b/content/public/browser/navigation_handle.cc
@@ -0,0 +1,30 @@
+// Copyright 2015 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/public/browser/navigation_handle.h"
+
+#include "content/browser/frame_host/navigation_handle_impl.h"
+#include "content/browser/frame_host/navigator.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+
+namespace content {
+
+WebContents* NavigationHandle::GetWebContents() {
+ // The NavigationHandleImpl cannot access the WebContentsImpl as it would be
+ // a layering violation, hence the cast here.
+ return static_cast<WebContentsImpl*>(
+ static_cast<NavigationHandleImpl*>(this)->delegate());
+}
+
+// static
+scoped_ptr<NavigationHandle> NavigationHandle::CreateNavigationHandleForTesting(
+ const GURL& url,
+ bool is_main_frame,
+ WebContents* web_contents) {
+ scoped_ptr<NavigationHandleImpl> handle_impl = NavigationHandleImpl::Create(
+ url, is_main_frame, static_cast<WebContentsImpl*>(web_contents));
+ return scoped_ptr<NavigationHandle>(handle_impl.Pass());
+}
+
+} // namespace content
diff --git a/content/public/browser/navigation_handle.h b/content/public/browser/navigation_handle.h
index c60baba..033aca2 100644
--- a/content/public/browser/navigation_handle.h
+++ b/content/public/browser/navigation_handle.h
@@ -6,27 +6,70 @@
#define CONTENT_PUBLIC_BROWSER_NAVIGATION_HANDLE_H_
#include "content/common/content_export.h"
+#include "content/public/browser/navigation_throttle.h"
+#include "content/public/common/referrer.h"
#include "net/base/net_errors.h"
+#include "ui/base/page_transition_types.h"
class GURL;
namespace content {
+class NavigationThrottle;
+class WebContents;
// A NavigationHandle tracks information related to a single navigation.
class CONTENT_EXPORT NavigationHandle {
public:
virtual ~NavigationHandle() {}
+ // Parameters available at navigation start time -----------------------------
+ //
+ // These parameters are always available during the navigation. Note that
+ // some may change during navigation (e.g. due to server redirects).
+
// The URL the frame is navigating to. This may change during the navigation
// when encountering a server redirect.
- virtual const GURL& GetURL() const = 0;
+ virtual const GURL& GetURL() = 0;
+
+ // Whether the navigation is taking place in the main frame or in a subframe.
+ // This remains constant over the navigation lifetime.
+ virtual bool IsInMainFrame() = 0;
+
+ // The WebContents the navigation is taking place in.
+ WebContents* GetWebContents();
+
+ // Parameters available at network request start time ------------------------
+ //
+ // The following parameters are only available when the network request is
+ // made for the navigation (or at commit time if no network request is made).
+ // This corresponds to NavigationThrottle::WillSendRequest. They should not
+ // be queried before that.
+
+ // Whether the navigation is a POST or a GET. This may change during the
+ // navigation when encountering a server redirect.
+ virtual bool IsPost() = 0;
+
+ // Returns a sanitized version of the referrer for this request.
+ virtual const Referrer& GetReferrer() = 0;
+
+ // Whether the navigation was initiated by a user gesture. Note that this
+ // will return false for browser-initiated navigations.
+ // TODO(clamy): when PlzNavigate launches, this should return true for
+ // browser-initiated navigations.
+ virtual bool HasUserGesture() = 0;
+
+ // Returns the page transition type.
+ virtual ui::PageTransition GetPageTransition() = 0;
+
+ // Whether the target URL cannot be handled by the browser's internal protocol
+ // handlers.
+ virtual bool IsExternalProtocol() = 0;
+
+ // Navigation control flow --------------------------------------------------
// The net error code if an error happened prior to commit. Otherwise it will
// be net::OK.
- virtual net::Error GetNetErrorCode() const = 0;
-
- // Whether the navigation is taking place in the main frame or in a subframe.
- virtual bool IsInMainFrame() const = 0;
+ virtual net::Error GetNetErrorCode() = 0;
// Whether the navigation happened in the same page. This is only known
// after the navigation has committed. It is an error to call this method
@@ -34,10 +77,44 @@ class CONTENT_EXPORT NavigationHandle {
virtual bool IsSamePage() = 0;
// Whether the navigation has successfully committed a document.
- virtual bool HasCommittedDocument() const = 0;
+ virtual bool HasCommittedDocument() = 0;
// Whether an error page has committed for the navigation.
- virtual bool HasCommittedErrorPage() const = 0;
+ virtual bool HasCommittedErrorPage() = 0;
+
+ // Testing methods ----------------------------------------------------------
+ //
+ // The following methods should be used exclusively for writing unit tests.
+
+ static scoped_ptr<NavigationHandle> CreateNavigationHandleForTesting(
+ const GURL& url,
+ bool is_main_frame,
+ WebContents* web_contents);
+
+ // Registers a NavigationThrottle for tests. The throttle can
+ // modify the request, pause the request or cancel the request. This will
+ // take ownership of the NavigationThrottle.
+ // Note: in non-test cases, NavigationThrottles should not be added directly
+ // but returned by the implementation of
+ // ContentBrowserClient::CreateThrottlesForNavigation. This ensures proper
+ // ordering of the throttles.
+ virtual void RegisterThrottleForTesting(
+ scoped_ptr<NavigationThrottle> navigation_throttle) = 0;
+
+ // Simulates the network request starting.
+ virtual NavigationThrottle::ThrottleCheckResult
+ CallWillStartRequestForTesting(bool is_post,
+ const Referrer& sanitized_referrer,
+ bool has_user_gesture,
+ ui::PageTransition transition,
+ bool is_external_protocol) = 0;
+
+ // Simulates the network request being redirected.
+ virtual NavigationThrottle::ThrottleCheckResult
+ CallWillRedirectRequestForTesting(const GURL& new_url,
+ bool new_method_is_post,
+ const GURL& new_referrer_url,
+ bool new_is_external_protocol) = 0;
};
} // namespace content
diff --git a/content/public/browser/navigation_throttle.cc b/content/public/browser/navigation_throttle.cc
new file mode 100644
index 0000000..ac3b3aa
--- /dev/null
+++ b/content/public/browser/navigation_throttle.cc
@@ -0,0 +1,23 @@
+// Copyright 2015 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/public/browser/navigation_throttle.h"
+
+namespace content {
+
+NavigationThrottle::NavigationThrottle(NavigationHandle* navigation_handle)
+ : navigation_handle_(navigation_handle) {}
+
+NavigationThrottle::~NavigationThrottle() {}
+
+NavigationThrottle::ThrottleCheckResult NavigationThrottle::WillStartRequest() {
+ return NavigationThrottle::PROCEED;
+}
+
+NavigationThrottle::ThrottleCheckResult
+NavigationThrottle::WillRedirectRequest() {
+ return NavigationThrottle::PROCEED;
+}
+
+} // namespace content
diff --git a/content/public/browser/navigation_throttle.h b/content/public/browser/navigation_throttle.h
new file mode 100644
index 0000000..ae5883b
--- /dev/null
+++ b/content/public/browser/navigation_throttle.h
@@ -0,0 +1,43 @@
+// Copyright 2015 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_PUBLIC_BROWSER_NAVIGATION_THROTTLE_H_
+#define CONTENT_PUBLIC_BROWSER_NAVIGATION_THROTTLE_H_
+
+#include "content/common/content_export.h"
+
+namespace content {
+class NavigationHandle;
+
+// A NavigationThrottle tracks and allows interaction with a navigation on the
+// UI thread.
+class CONTENT_EXPORT NavigationThrottle {
+ public:
+ // This is returned to the NavigationHandle to allow the navigation to
+ // proceed, or to cancel it.
+ enum ThrottleCheckResult {
+ PROCEED,
+ CANCEL_AND_IGNORE,
+ };
+
+ NavigationThrottle(NavigationHandle* navigation_handle);
+ virtual ~NavigationThrottle();
+
+ // Called when a network request is about to be made for this navigation.
+ virtual ThrottleCheckResult WillStartRequest();
+
+ // Called when a server redirect is received by the navigation.
+ virtual ThrottleCheckResult WillRedirectRequest();
+
+ // The NavigationHandle that is tracking the information related to this
+ // navigation.
+ NavigationHandle* navigation_handle() const { return navigation_handle_; }
+
+ private:
+ NavigationHandle* navigation_handle_;
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_NAVIGATION_THROTTLE_H_
diff --git a/content/test/web_contents_observer_sanity_checker.cc b/content/test/web_contents_observer_sanity_checker.cc
index 82bcb60..18d38ae 100644
--- a/content/test/web_contents_observer_sanity_checker.cc
+++ b/content/test/web_contents_observer_sanity_checker.cc
@@ -129,6 +129,7 @@ void WebContentsObserverSanityChecker::DidStartNavigation(
CHECK(navigation_handle->GetNetErrorCode() == net::OK);
CHECK(!navigation_handle->HasCommittedDocument());
CHECK(!navigation_handle->HasCommittedErrorPage());
+ CHECK_EQ(navigation_handle->GetWebContents(), web_contents());
ongoing_navigations_.insert(navigation_handle);
}
@@ -141,6 +142,7 @@ void WebContentsObserverSanityChecker::DidRedirectNavigation(
CHECK(navigation_handle->GetNetErrorCode() == net::OK);
CHECK(!navigation_handle->HasCommittedDocument());
CHECK(!navigation_handle->HasCommittedErrorPage());
+ CHECK_EQ(navigation_handle->GetWebContents(), web_contents());
}
void WebContentsObserverSanityChecker::ReadyToCommitNavigation(
@@ -163,6 +165,7 @@ void WebContentsObserverSanityChecker::DidCommitNavigation(
navigation_handle->GetNetErrorCode() == net::OK);
CHECK_IMPLIES(navigation_handle->HasCommittedErrorPage(),
navigation_handle->GetNetErrorCode() != net::OK);
+ CHECK_EQ(navigation_handle->GetWebContents(), web_contents());
ongoing_committed_navigations_.insert(navigation_handle);
}
@@ -178,6 +181,7 @@ void WebContentsObserverSanityChecker::DidFinishNavigation(
navigation_handle->GetNetErrorCode() == net::OK);
CHECK_IMPLIES(navigation_handle->HasCommittedErrorPage(),
navigation_handle->GetNetErrorCode() != net::OK);
+ CHECK_EQ(navigation_handle->GetWebContents(), web_contents());
if (NavigationIsOngoingAndCommitted(navigation_handle))
ongoing_committed_navigations_.erase(navigation_handle);