diff options
author | bengr <bengr@chromium.org> | 2014-11-06 17:36:50 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-11-07 01:37:23 +0000 |
commit | 1bf8e9456a103d086f53400bdc169c437a1590a4 (patch) | |
tree | a0eca7b338d85490758a28cdb5bb10cd5cd407a3 | |
parent | f9567f85788355bf3da8df030cbc232421d00b7d (diff) | |
download | chromium_src-1bf8e9456a103d086f53400bdc169c437a1590a4.zip chromium_src-1bf8e9456a103d086f53400bdc169c437a1590a4.tar.gz chromium_src-1bf8e9456a103d086f53400bdc169c437a1590a4.tar.bz2 |
Adds MaybeInterceptRedirect and MaybeInterceptResponse to the URLRequestInterceptor interface as well as to URLRequestJobFactory.
BUG=429505
Review URL: https://codereview.chromium.org/686343002
Cr-Commit-Position: refs/heads/master@{#303154}
28 files changed, 1079 insertions, 48 deletions
diff --git a/android_webview/browser/net/aw_url_request_job_factory.cc b/android_webview/browser/net/aw_url_request_job_factory.cc index 2872d01..984458c 100644 --- a/android_webview/browser/net/aw_url_request_job_factory.cc +++ b/android_webview/browser/net/aw_url_request_job_factory.cc @@ -57,6 +57,20 @@ URLRequestJob* AwURLRequestJobFactory::MaybeCreateJobWithProtocolHandler( request, network_delegate, net::ERR_UNKNOWN_URL_SCHEME); } +net::URLRequestJob* AwURLRequestJobFactory::MaybeInterceptRedirect( + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const GURL& location) const { + return next_factory_->MaybeInterceptRedirect( + request, network_delegate, location); +} + +net::URLRequestJob* AwURLRequestJobFactory::MaybeInterceptResponse( + net::URLRequest* request, + net::NetworkDelegate* network_delegate) const { + return next_factory_->MaybeInterceptResponse(request, network_delegate); +} + bool AwURLRequestJobFactory::SetProtocolHandler( const std::string& scheme, ProtocolHandler* protocol_handler) { diff --git a/android_webview/browser/net/aw_url_request_job_factory.h b/android_webview/browser/net/aw_url_request_job_factory.h index 6cf507b..db1cfae 100644 --- a/android_webview/browser/net/aw_url_request_job_factory.h +++ b/android_webview/browser/net/aw_url_request_job_factory.h @@ -29,10 +29,20 @@ class AwURLRequestJobFactory : public net::URLRequestJobFactory { ProtocolHandler* protocol_handler); // net::URLRequestJobFactory implementation. - virtual net::URLRequestJob* MaybeCreateJobWithProtocolHandler( + net::URLRequestJob* MaybeCreateJobWithProtocolHandler( const std::string& scheme, net::URLRequest* request, net::NetworkDelegate* network_delegate) const override; + + net::URLRequestJob* MaybeInterceptRedirect( + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const GURL& location) const override; + + net::URLRequestJob* MaybeInterceptResponse( + net::URLRequest* request, + net::NetworkDelegate* network_delegate) const override; + virtual bool IsHandledProtocol(const std::string& scheme) const override; virtual bool IsHandledURL(const GURL& url) const override; virtual bool IsSafeRedirectTarget(const GURL& location) const override; diff --git a/chrome/browser/chromeos/fileapi/external_file_url_request_job_unittest.cc b/chrome/browser/chromeos/fileapi/external_file_url_request_job_unittest.cc index 34cf213..3c4fe88 100644 --- a/chrome/browser/chromeos/fileapi/external_file_url_request_job_unittest.cc +++ b/chrome/browser/chromeos/fileapi/external_file_url_request_job_unittest.cc @@ -63,6 +63,19 @@ class TestURLRequestJobFactory : public net::URLRequestJobFactory { profile_id_, request, network_delegate); } + net::URLRequestJob* MaybeInterceptRedirect( + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const GURL& location) const override { + return nullptr; + } + + net::URLRequestJob* MaybeInterceptResponse( + net::URLRequest* request, + net::NetworkDelegate* network_delegate) const override { + return nullptr; + } + virtual bool IsHandledProtocol(const std::string& scheme) const override { return scheme == chrome::kExternalFileScheme; } diff --git a/chrome/browser/custom_handlers/protocol_handler_registry.cc b/chrome/browser/custom_handlers/protocol_handler_registry.cc index 72f134d6..99bfd7c 100644 --- a/chrome/browser/custom_handlers/protocol_handler_registry.cc +++ b/chrome/browser/custom_handlers/protocol_handler_registry.cc @@ -190,6 +190,22 @@ MaybeCreateJobWithProtocolHandler( scheme, request, network_delegate); } +net::URLRequestJob* +ProtocolHandlerRegistry::JobInterceptorFactory::MaybeInterceptRedirect( + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const GURL& location) const { + return job_factory_->MaybeInterceptRedirect( + request, network_delegate, location); +} + +net::URLRequestJob* +ProtocolHandlerRegistry::JobInterceptorFactory::MaybeInterceptResponse( + net::URLRequest* request, + net::NetworkDelegate* network_delegate) const { + return job_factory_->MaybeInterceptResponse(request, network_delegate); +} + bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledProtocol( const std::string& scheme) const { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); diff --git a/chrome/browser/custom_handlers/protocol_handler_registry.h b/chrome/browser/custom_handlers/protocol_handler_registry.h index 3426ab0..6c25ac1 100644 --- a/chrome/browser/custom_handlers/protocol_handler_registry.h +++ b/chrome/browser/custom_handlers/protocol_handler_registry.h @@ -116,6 +116,16 @@ class ProtocolHandlerRegistry : public KeyedService { const std::string& scheme, net::URLRequest* request, net::NetworkDelegate* network_delegate) const override; + + net::URLRequestJob* MaybeInterceptRedirect( + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const GURL& location) const override; + + net::URLRequestJob* MaybeInterceptResponse( + net::URLRequest* request, + net::NetworkDelegate* network_delegate) const override; + bool IsHandledProtocol(const std::string& scheme) const override; bool IsHandledURL(const GURL& url) const override; bool IsSafeRedirectTarget(const GURL& location) const override; diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc index ab54350..7a1f09e 100644 --- a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc +++ b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc @@ -69,6 +69,20 @@ class FakeURLRequestJobFactory : public net::URLRequestJobFactory { net::NetworkDelegate* network_delegate) const override { return NULL; } + + net::URLRequestJob* MaybeInterceptRedirect( + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const GURL& location) const override { + return nullptr; + } + + net::URLRequestJob* MaybeInterceptResponse( + net::URLRequest* request, + net::NetworkDelegate* network_delegate) const override { + return nullptr; + } + bool IsHandledProtocol(const std::string& scheme) const override { return false; } diff --git a/content/browser/appcache/appcache_request_handler_unittest.cc b/content/browser/appcache/appcache_request_handler_unittest.cc index 5d53a8b..9543f7e 100644 --- a/content/browser/appcache/appcache_request_handler_unittest.cc +++ b/content/browser/appcache/appcache_request_handler_unittest.cc @@ -134,6 +134,19 @@ class AppCacheRequestHandlerTest : public testing::Test { } } + net::URLRequestJob* MaybeInterceptRedirect( + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const GURL& location) const override { + return nullptr; + } + + net::URLRequestJob* MaybeInterceptResponse( + net::URLRequest* request, + net::NetworkDelegate* network_delegate) const override { + return nullptr; + } + bool IsHandledProtocol(const std::string& scheme) const override { return scheme == "http"; }; diff --git a/content/browser/appcache/appcache_url_request_job_unittest.cc b/content/browser/appcache/appcache_url_request_job_unittest.cc index 08b0fc1..8acc71c 100644 --- a/content/browser/appcache/appcache_url_request_job_unittest.cc +++ b/content/browser/appcache/appcache_url_request_job_unittest.cc @@ -72,6 +72,19 @@ class MockURLRequestJobFactory : public net::URLRequestJobFactory { } } + net::URLRequestJob* MaybeInterceptRedirect( + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const GURL& location) const override { + return nullptr; + } + + net::URLRequestJob* MaybeInterceptResponse( + net::URLRequest* request, + net::NetworkDelegate* network_delegate) const override { + return nullptr; + } + bool IsHandledProtocol(const std::string& scheme) const override { return scheme == "http"; }; diff --git a/content/browser/fileapi/file_system_dir_url_request_job_unittest.cc b/content/browser/fileapi/file_system_dir_url_request_job_unittest.cc index 6f7f423..e496954 100644 --- a/content/browser/fileapi/file_system_dir_url_request_job_unittest.cc +++ b/content/browser/fileapi/file_system_dir_url_request_job_unittest.cc @@ -88,6 +88,19 @@ class FileSystemDirURLRequestJobFactory : public net::URLRequestJobFactory { request, network_delegate, storage_domain_, file_system_context_); } + net::URLRequestJob* MaybeInterceptRedirect( + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const GURL& location) const override { + return nullptr; + } + + net::URLRequestJob* MaybeInterceptResponse( + net::URLRequest* request, + net::NetworkDelegate* network_delegate) const override { + return nullptr; + } + bool IsHandledProtocol(const std::string& scheme) const override { return true; } diff --git a/content/browser/fileapi/file_system_url_request_job_unittest.cc b/content/browser/fileapi/file_system_url_request_job_unittest.cc index b6ec510..4dcba3b 100644 --- a/content/browser/fileapi/file_system_url_request_job_unittest.cc +++ b/content/browser/fileapi/file_system_url_request_job_unittest.cc @@ -97,6 +97,19 @@ class FileSystemURLRequestJobFactory : public net::URLRequestJobFactory { request, network_delegate, storage_domain_, file_system_context_); } + net::URLRequestJob* MaybeInterceptRedirect( + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const GURL& location) const override { + return nullptr; + } + + net::URLRequestJob* MaybeInterceptResponse( + net::URLRequest* request, + net::NetworkDelegate* network_delegate) const override { + return nullptr; + } + bool IsHandledProtocol(const std::string& scheme) const override { return true; } diff --git a/content/browser/fileapi/file_writer_delegate_unittest.cc b/content/browser/fileapi/file_writer_delegate_unittest.cc index f69d9d7..d907843 100644 --- a/content/browser/fileapi/file_writer_delegate_unittest.cc +++ b/content/browser/fileapi/file_writer_delegate_unittest.cc @@ -219,6 +219,19 @@ class BlobURLRequestJobFactory : public net::URLRequestJobFactory { request, network_delegate, *content_data_); } + net::URLRequestJob* MaybeInterceptRedirect( + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const GURL& location) const override { + return nullptr; + } + + net::URLRequestJob* MaybeInterceptResponse( + net::URLRequest* request, + net::NetworkDelegate* network_delegate) const override { + return nullptr; + } + bool IsHandledProtocol(const std::string& scheme) const override { return scheme == "blob"; } diff --git a/content/browser/loader/resource_dispatcher_host_unittest.cc b/content/browser/loader/resource_dispatcher_host_unittest.cc index d600a27..d18facd 100644 --- a/content/browser/loader/resource_dispatcher_host_unittest.cc +++ b/content/browser/loader/resource_dispatcher_host_unittest.cc @@ -492,6 +492,15 @@ class TestURLRequestJobFactory : public net::URLRequestJobFactory { net::URLRequest* request, net::NetworkDelegate* network_delegate) const override; + net::URLRequestJob* MaybeInterceptRedirect( + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const GURL& location) const override; + + net::URLRequestJob* MaybeInterceptResponse( + net::URLRequest* request, + net::NetworkDelegate* network_delegate) const override; + bool IsHandledProtocol(const std::string& scheme) const override { return supported_schemes_.count(scheme) > 0; } @@ -3000,4 +3009,17 @@ net::URLRequestJob* TestURLRequestJobFactory::MaybeCreateJobWithProtocolHandler( } } +net::URLRequestJob* TestURLRequestJobFactory::MaybeInterceptRedirect( + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const GURL& location) const { + return nullptr; +} + +net::URLRequestJob* TestURLRequestJobFactory::MaybeInterceptResponse( + net::URLRequest* request, + net::NetworkDelegate* network_delegate) const { + return nullptr; +} + } // namespace content diff --git a/net/data/url_request_unittest/simple.html b/net/data/url_request_unittest/simple.html new file mode 100644 index 0000000..ce01362 --- /dev/null +++ b/net/data/url_request_unittest/simple.html @@ -0,0 +1 @@ +hello diff --git a/net/data/url_request_unittest/simple.html.mock-http-headers b/net/data/url_request_unittest/simple.html.mock-http-headers new file mode 100644 index 0000000..be8f7b5 --- /dev/null +++ b/net/data/url_request_unittest/simple.html.mock-http-headers @@ -0,0 +1,3 @@ +HTTP/1.1 200 OK +Content-Type: text/html +Content-Length: 5 diff --git a/net/data/url_request_unittest/two-content-lengths.html b/net/data/url_request_unittest/two-content-lengths.html new file mode 100644 index 0000000..364322d --- /dev/null +++ b/net/data/url_request_unittest/two-content-lengths.html @@ -0,0 +1 @@ +This file is boring; all the action's in the .mock-http-headers. diff --git a/net/data/url_request_unittest/two-content-lengths.html.mock-http-headers b/net/data/url_request_unittest/two-content-lengths.html.mock-http-headers new file mode 100644 index 0000000..707c0b0 --- /dev/null +++ b/net/data/url_request_unittest/two-content-lengths.html.mock-http-headers @@ -0,0 +1,4 @@ +HTTP/1.1 200 OK +Content-Type: text/html +Content-Length: 42 +Content-Length: 41 diff --git a/net/url_request/url_request_file_job_unittest.cc b/net/url_request/url_request_file_job_unittest.cc index f4d7f7a..23ded74 100644 --- a/net/url_request/url_request_file_job_unittest.cc +++ b/net/url_request/url_request_file_job_unittest.cc @@ -82,6 +82,19 @@ class CallbacksJobFactory : public URLRequestJobFactory { return job; } + net::URLRequestJob* MaybeInterceptRedirect( + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const GURL& location) const override { + return nullptr; + } + + net::URLRequestJob* MaybeInterceptResponse( + net::URLRequest* request, + net::NetworkDelegate* network_delegate) const override { + return nullptr; + } + bool IsHandledProtocol(const std::string& scheme) const override { return scheme == "file"; } diff --git a/net/url_request/url_request_intercepting_job_factory.cc b/net/url_request/url_request_intercepting_job_factory.cc index 43789e1..ea2d1f2 100644 --- a/net/url_request/url_request_intercepting_job_factory.cc +++ b/net/url_request/url_request_intercepting_job_factory.cc @@ -32,6 +32,33 @@ MaybeCreateJobWithProtocolHandler( scheme, request, network_delegate); } +URLRequestJob* URLRequestInterceptingJobFactory::MaybeInterceptRedirect( + URLRequest* request, + NetworkDelegate* network_delegate, + const GURL& location) const { + DCHECK(CalledOnValidThread()); + URLRequestJob* job = interceptor_->MaybeInterceptRedirect(request, + network_delegate, + location); + if (job) + return job; + return job_factory_->MaybeInterceptRedirect(request, + network_delegate, + location); +} + +URLRequestJob* URLRequestInterceptingJobFactory::MaybeInterceptResponse( + URLRequest* request, + NetworkDelegate* network_delegate) const { + DCHECK(CalledOnValidThread()); + URLRequestJob* job = interceptor_->MaybeInterceptResponse(request, + network_delegate); + if (job) + return job; + return job_factory_->MaybeInterceptResponse(request, + network_delegate); +} + bool URLRequestInterceptingJobFactory::IsHandledProtocol( const std::string& scheme) const { return job_factory_->IsHandledProtocol(scheme); diff --git a/net/url_request/url_request_intercepting_job_factory.h b/net/url_request/url_request_intercepting_job_factory.h index 857dbf4..056b385 100644 --- a/net/url_request/url_request_intercepting_job_factory.h +++ b/net/url_request/url_request_intercepting_job_factory.h @@ -42,6 +42,16 @@ class NET_EXPORT URLRequestInterceptingJobFactory const std::string& scheme, URLRequest* request, NetworkDelegate* network_delegate) const override; + + URLRequestJob* MaybeInterceptRedirect( + URLRequest* request, + NetworkDelegate* network_delegate, + const GURL& location) const override; + + URLRequestJob* MaybeInterceptResponse( + URLRequest* request, + NetworkDelegate* network_delegate) const override; + bool IsHandledProtocol(const std::string& scheme) const override; bool IsHandledURL(const GURL& url) const override; bool IsSafeRedirectTarget(const GURL& location) const override; diff --git a/net/url_request/url_request_interceptor.cc b/net/url_request/url_request_interceptor.cc index bcd0fd5..b93611b 100644 --- a/net/url_request/url_request_interceptor.cc +++ b/net/url_request/url_request_interceptor.cc @@ -12,4 +12,16 @@ URLRequestInterceptor::URLRequestInterceptor() { URLRequestInterceptor::~URLRequestInterceptor() { } +URLRequestJob* URLRequestInterceptor::MaybeInterceptRedirect( + URLRequest* request, + NetworkDelegate* network_delegate, + const GURL& location) const { + return nullptr; +} + +URLRequestJob* URLRequestInterceptor::MaybeInterceptResponse( + URLRequest* request, NetworkDelegate* network_delegate) const { + return nullptr; +} + } // namespace net diff --git a/net/url_request/url_request_interceptor.h b/net/url_request/url_request_interceptor.h index 682368d..f7d5275 100644 --- a/net/url_request/url_request_interceptor.h +++ b/net/url_request/url_request_interceptor.h @@ -8,6 +8,8 @@ #include "base/macros.h" #include "net/base/net_export.h" +class GURL; + namespace net { class URLRequest; @@ -28,6 +30,20 @@ class NET_EXPORT URLRequestInterceptor { virtual URLRequestJob* MaybeInterceptRequest( URLRequest* request, NetworkDelegate* network_delegate) const = 0; + // Returns a URLRequestJob to handle |request|, if the interceptor wants to + // take over the handling of the request after a redirect is received, + // instead of using the default ProtocolHandler. Otherwise, returns NULL. + virtual URLRequestJob* MaybeInterceptRedirect( + URLRequest* request, + NetworkDelegate* network_delegate, + const GURL& location) const; + + // Returns a URLRequestJob to handle |request, if the interceptor wants to + // take over the handling of the request after a response has started, + // instead of using the default ProtocolHandler. Otherwise, returns NULL. + virtual URLRequestJob* MaybeInterceptResponse( + URLRequest* request, NetworkDelegate* network_delegate) const; + private: DISALLOW_COPY_AND_ASSIGN(URLRequestInterceptor); }; diff --git a/net/url_request/url_request_job_factory.h b/net/url_request/url_request_job_factory.h index d4cc49e..96f218a 100644 --- a/net/url_request/url_request_job_factory.h +++ b/net/url_request/url_request_job_factory.h @@ -47,6 +47,15 @@ class NET_EXPORT URLRequestJobFactory URLRequest* request, NetworkDelegate* network_delegate) const = 0; + virtual URLRequestJob* MaybeInterceptRedirect( + URLRequest* request, + NetworkDelegate* network_delegate, + const GURL& location) const = 0; + + virtual URLRequestJob* MaybeInterceptResponse( + URLRequest* request, + NetworkDelegate* network_delegate) const = 0; + virtual bool IsHandledProtocol(const std::string& scheme) const = 0; virtual bool IsHandledURL(const GURL& url) const = 0; diff --git a/net/url_request/url_request_job_factory_impl.cc b/net/url_request/url_request_job_factory_impl.cc index 57e775b..264a7a1 100644 --- a/net/url_request/url_request_job_factory_impl.cc +++ b/net/url_request/url_request_job_factory_impl.cc @@ -63,6 +63,19 @@ URLRequestJob* URLRequestJobFactoryImpl::MaybeCreateJobWithProtocolHandler( return it->second->MaybeCreateJob(request, network_delegate); } +URLRequestJob* URLRequestJobFactoryImpl::MaybeInterceptRedirect( + URLRequest* request, + NetworkDelegate* network_delegate, + const GURL& location) const { + return nullptr; +} + +URLRequestJob* URLRequestJobFactoryImpl::MaybeInterceptResponse( + URLRequest* request, + NetworkDelegate* network_delegate) const { + return nullptr; +} + bool URLRequestJobFactoryImpl::IsHandledProtocol( const std::string& scheme) const { DCHECK(CalledOnValidThread()); diff --git a/net/url_request/url_request_job_factory_impl.h b/net/url_request/url_request_job_factory_impl.h index 695661e..8d1d8d9 100644 --- a/net/url_request/url_request_job_factory_impl.h +++ b/net/url_request/url_request_job_factory_impl.h @@ -33,6 +33,16 @@ class NET_EXPORT URLRequestJobFactoryImpl : public URLRequestJobFactory { const std::string& scheme, URLRequest* request, NetworkDelegate* network_delegate) const override; + + URLRequestJob* MaybeInterceptRedirect( + URLRequest* request, + NetworkDelegate* network_delegate, + const GURL& location) const override; + + URLRequestJob* MaybeInterceptResponse( + URLRequest* request, + NetworkDelegate* network_delegate) const override; + bool IsHandledProtocol(const std::string& scheme) const override; bool IsHandledURL(const GURL& url) const override; bool IsSafeRedirectTarget(const GURL& location) const override; diff --git a/net/url_request/url_request_job_manager.cc b/net/url_request/url_request_job_manager.cc index 0fe557b..6fcff22 100644 --- a/net/url_request/url_request_job_manager.cc +++ b/net/url_request/url_request_job_manager.cc @@ -128,6 +128,13 @@ URLRequestJob* URLRequestJobManager::MaybeInterceptRedirect( if (job) return job; } + + URLRequestJob* job = + request->context()->job_factory()->MaybeInterceptRedirect( + request, network_delegate, location); + if (job) + return job; + return NULL; } @@ -154,6 +161,13 @@ URLRequestJob* URLRequestJobManager::MaybeInterceptResponse( if (job) return job; } + + URLRequestJob* job = + request->context()->job_factory()->MaybeInterceptResponse( + request, network_delegate); + if (job) + return job; + return NULL; } diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc index 82d8579..8f70ee7 100644 --- a/net/url_request/url_request_test_util.cc +++ b/net/url_request/url_request_test_util.cc @@ -317,11 +317,14 @@ TestNetworkDelegate::TestNetworkDelegate() blocked_set_cookie_count_(0), set_cookie_count_(0), observed_before_proxy_headers_sent_callbacks_(0), + before_send_headers_count_(0), + headers_received_count_(0), has_load_timing_info_before_redirect_(false), has_load_timing_info_before_auth_(false), can_access_files_(true), can_throttle_requests_(true), - cancel_request_with_policy_violating_referrer_(false) { + cancel_request_with_policy_violating_referrer_(false), + will_be_intercepted_on_next_error_(false) { } TestNetworkDelegate::~TestNetworkDelegate() { @@ -386,7 +389,7 @@ int TestNetworkDelegate::OnBeforeSendHeaders( next_states_[req_id] = kStageSendHeaders | kStageCompletedError; // request canceled by delegate - + before_send_headers_count_++; return OK; } @@ -406,9 +409,11 @@ void TestNetworkDelegate::OnSendHeaders( event_order_[req_id] += "OnSendHeaders\n"; EXPECT_TRUE(next_states_[req_id] & kStageSendHeaders) << event_order_[req_id]; - next_states_[req_id] = - kStageHeadersReceived | - kStageCompletedError; + if (!will_be_intercepted_on_next_error_) + next_states_[req_id] = kStageHeadersReceived | kStageCompletedError; + else + next_states_[req_id] = kStageResponseStarted; + will_be_intercepted_on_next_error_ = false; } int TestNetworkDelegate::OnHeadersReceived( @@ -445,7 +450,7 @@ int TestNetworkDelegate::OnHeadersReceived( if (!allowed_unsafe_redirect_url_.is_empty()) *allowed_unsafe_redirect_url = allowed_unsafe_redirect_url_; } - + headers_received_count_++; return OK; } diff --git a/net/url_request/url_request_test_util.h b/net/url_request/url_request_test_util.h index 5784931..1289db7 100644 --- a/net/url_request/url_request_test_util.h +++ b/net/url_request/url_request_test_util.h @@ -275,12 +275,18 @@ class TestNetworkDelegate : public NetworkDelegate { int observed_before_proxy_headers_sent_callbacks() const { return observed_before_proxy_headers_sent_callbacks_; } + int before_send_headers_count() const { return before_send_headers_count_; } + int headers_received_count() const { return headers_received_count_; } // Last observed proxy in proxy header sent callback. HostPortPair last_observed_proxy() { return last_observed_proxy_; } + void set_can_be_intercepted_on_error(bool can_be_intercepted_on_error) { + will_be_intercepted_on_next_error_ = can_be_intercepted_on_error; + } + protected: // NetworkDelegate: int OnBeforeURLRequest(URLRequest* request, @@ -343,6 +349,8 @@ class TestNetworkDelegate : public NetworkDelegate { int blocked_set_cookie_count_; int set_cookie_count_; int observed_before_proxy_headers_sent_callbacks_; + int before_send_headers_count_; + int headers_received_count_; // Last observed proxy in before proxy header sent callback. HostPortPair last_observed_proxy_; @@ -365,6 +373,7 @@ class TestNetworkDelegate : public NetworkDelegate { bool can_access_files_; // true by default bool can_throttle_requests_; // true by default bool cancel_request_with_policy_violating_referrer_; // false by default + bool will_be_intercepted_on_next_error_; }; // Overrides the host used by the LocalHttpTestServer in diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index 139b6f3..3bb7c15 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc @@ -72,6 +72,8 @@ #include "net/url_request/static_http_user_agent_settings.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_http_job.h" +#include "net/url_request/url_request_intercepting_job_factory.h" +#include "net/url_request/url_request_interceptor.h" #include "net/url_request/url_request_job_factory_impl.h" #include "net/url_request/url_request_redirect_job.h" #include "net/url_request/url_request_test_job.h" @@ -607,31 +609,52 @@ class URLRequestTest : public PlatformTest { URLRequestTest() : default_context_(true) { default_context_.set_network_delegate(&default_network_delegate_); default_context_.set_net_log(&net_log_); - job_factory_.SetProtocolHandler("data", new DataProtocolHandler); -#if !defined(DISABLE_FILE_SUPPORT) - job_factory_.SetProtocolHandler( - "file", new FileProtocolHandler(base::MessageLoopProxy::current())); -#endif - default_context_.set_job_factory(&job_factory_); - default_context_.Init(); + job_factory_impl_ = new URLRequestJobFactoryImpl(); + job_factory_.reset(job_factory_impl_); } + ~URLRequestTest() override { // URLRequestJobs may post clean-up tasks on destruction. base::RunLoop().RunUntilIdle(); } + virtual void SetUp() { + SetUpFactory(); + default_context_.set_job_factory(job_factory_.get()); + default_context_.Init(); + PlatformTest::SetUp(); + } + + virtual void SetUpFactory() { + job_factory_impl_->SetProtocolHandler("data", new DataProtocolHandler); +#if !defined(DISABLE_FILE_SUPPORT) + job_factory_impl_->SetProtocolHandler( + "file", new FileProtocolHandler(base::MessageLoopProxy::current())); +#endif + } + + TestNetworkDelegate* default_network_delegate() { + return &default_network_delegate_; + } + + const TestURLRequestContext& default_context() const { + return default_context_; + } + + // Adds the TestJobInterceptor to the default context. TestJobInterceptor* AddTestInterceptor() { TestJobInterceptor* protocol_handler_ = new TestJobInterceptor(); - job_factory_.SetProtocolHandler("http", NULL); - job_factory_.SetProtocolHandler("http", protocol_handler_); + job_factory_impl_->SetProtocolHandler("http", NULL); + job_factory_impl_->SetProtocolHandler("http", protocol_handler_); return protocol_handler_; } protected: CapturingNetLog net_log_; TestNetworkDelegate default_network_delegate_; // Must outlive URLRequest. - URLRequestJobFactoryImpl job_factory_; + URLRequestJobFactoryImpl* job_factory_impl_; + scoped_ptr<URLRequestJobFactory> job_factory_; TestURLRequestContext default_context_; }; @@ -1574,29 +1597,570 @@ TEST_F(URLRequestTest, InterceptRespectsCancelInRestart) { EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status()); } -LoadTimingInfo RunLoadTimingTest(const LoadTimingInfo& job_load_timing, - URLRequestContext* context) { - TestInterceptor interceptor; - interceptor.intercept_main_request_ = true; - interceptor.main_request_load_timing_info_ = job_load_timing; +// An Interceptor for use with interceptor tests. +class MockURLRequestInterceptor : public URLRequestInterceptor { + public: + // Static getters for canned response header and data strings. + static std::string ok_data() { + return URLRequestTestJob::test_data_1(); + } + + static std::string ok_headers() { + return URLRequestTestJob::test_headers(); + } + + static std::string redirect_data() { + return std::string(); + } + + static std::string redirect_headers() { + return URLRequestTestJob::test_redirect_headers(); + } + + static std::string error_data() { + return std::string("ohhh nooooo mr. bill!"); + } + + static std::string error_headers() { + return URLRequestTestJob::test_error_headers(); + } + + MockURLRequestInterceptor() + : intercept_main_request_(false), restart_main_request_(false), + cancel_main_request_(false), cancel_then_restart_main_request_(false), + simulate_main_network_error_(false), + intercept_redirect_(false), cancel_redirect_request_(false), + intercept_final_response_(false), cancel_final_request_(false), + use_url_request_http_job_(false), + did_intercept_main_(false), did_restart_main_(false), + did_cancel_main_(false), did_cancel_then_restart_main_(false), + did_simulate_error_main_(false), + did_intercept_redirect_(false), did_cancel_redirect_(false), + did_intercept_final_(false), did_cancel_final_(false) { + } + + ~MockURLRequestInterceptor() override { + } + + // URLRequestInterceptor implementation: + URLRequestJob* MaybeInterceptRequest( + URLRequest* request, + NetworkDelegate* network_delegate) const override { + if (restart_main_request_) { + restart_main_request_ = false; + did_restart_main_ = true; + return new RestartTestJob(request, network_delegate); + } + if (cancel_main_request_) { + cancel_main_request_ = false; + did_cancel_main_ = true; + return new CancelTestJob(request, network_delegate); + } + if (cancel_then_restart_main_request_) { + cancel_then_restart_main_request_ = false; + did_cancel_then_restart_main_ = true; + return new CancelThenRestartTestJob(request, network_delegate); + } + if (simulate_main_network_error_) { + simulate_main_network_error_ = false; + did_simulate_error_main_ = true; + if (use_url_request_http_job_) { + return URLRequestHttpJob::Factory(request, network_delegate, "http"); + } + // This job will result in error since the requested URL is not one of the + // URLs supported by these tests. + return new URLRequestTestJob(request, network_delegate, true); + } + if (!intercept_main_request_) + return nullptr; + intercept_main_request_ = false; + did_intercept_main_ = true; + URLRequestTestJob* job = new URLRequestTestJob(request, + network_delegate, + main_headers_, + main_data_, + true); + job->set_load_timing_info(main_request_load_timing_info_); + return job; + } + + URLRequestJob* MaybeInterceptRedirect(URLRequest* request, + NetworkDelegate* network_delegate, + const GURL& location) const override { + if (cancel_redirect_request_) { + cancel_redirect_request_ = false; + did_cancel_redirect_ = true; + return new CancelTestJob(request, network_delegate); + } + if (!intercept_redirect_) + return nullptr; + intercept_redirect_ = false; + did_intercept_redirect_ = true; + if (use_url_request_http_job_) { + return URLRequestHttpJob::Factory(request, network_delegate, "http"); + } + return new URLRequestTestJob(request, + network_delegate, + redirect_headers_, + redirect_data_, + true); + } + + URLRequestJob* MaybeInterceptResponse( + URLRequest* request, + NetworkDelegate* network_delegate) const override { + if (cancel_final_request_) { + cancel_final_request_ = false; + did_cancel_final_ = true; + return new CancelTestJob(request, network_delegate); + } + if (!intercept_final_response_) + return nullptr; + intercept_final_response_ = false; + did_intercept_final_ = true; + if (use_url_request_http_job_) { + return URLRequestHttpJob::Factory(request, network_delegate, "http"); + } + return new URLRequestTestJob(request, + network_delegate, + final_headers_, + final_data_, + true); + } + + void set_intercept_main_request(bool intercept_main_request) { + intercept_main_request_ = intercept_main_request; + } + + void set_main_headers(const std::string& main_headers) { + main_headers_ = main_headers; + } + + void set_main_data(const std::string& main_data) { + main_data_ = main_data; + } + + void set_main_request_load_timing_info( + const LoadTimingInfo& main_request_load_timing_info) { + main_request_load_timing_info_ = main_request_load_timing_info; + } + + void set_restart_main_request(bool restart_main_request) { + restart_main_request_ = restart_main_request; + } + + void set_cancel_main_request(bool cancel_main_request) { + cancel_main_request_ = cancel_main_request; + } + + void set_cancel_then_restart_main_request( + bool cancel_then_restart_main_request) { + cancel_then_restart_main_request_ = cancel_then_restart_main_request; + } + + void set_simulate_main_network_error(bool simulate_main_network_error) { + simulate_main_network_error_ = simulate_main_network_error; + } + + void set_intercept_redirect(bool intercept_redirect) { + intercept_redirect_ = intercept_redirect; + } + + void set_redirect_headers(const std::string& redirect_headers) { + redirect_headers_ = redirect_headers; + } + + void set_redirect_data(const std::string& redirect_data) { + redirect_data_ = redirect_data; + } + + void set_cancel_redirect_request(bool cancel_redirect_request) { + cancel_redirect_request_ = cancel_redirect_request; + } + + void set_intercept_final_response(bool intercept_final_response) { + intercept_final_response_ = intercept_final_response; + } + + void set_final_headers(const std::string& final_headers) { + final_headers_ = final_headers; + } + + void set_final_data(const std::string& final_data) { + final_data_ = final_data; + } + + void set_cancel_final_request(bool cancel_final_request) { + cancel_final_request_ = cancel_final_request; + } + + void set_use_url_request_http_job(bool use_url_request_http_job) { + use_url_request_http_job_ = use_url_request_http_job; + } + + bool did_intercept_main() const { + return did_intercept_main_; + } + + bool did_restart_main() const { + return did_restart_main_; + } + + bool did_cancel_main() const { + return did_cancel_main_; + } + + bool did_cancel_then_restart_main() const { + return did_cancel_then_restart_main_; + } + + bool did_simulate_error_main() const { + return did_simulate_error_main_; + } + + bool did_intercept_redirect() const { + return did_intercept_redirect_; + } + + bool did_cancel_redirect() const { + return did_cancel_redirect_; + } + + bool did_intercept_final() const { + return did_intercept_final_; + } + + bool did_cancel_final() const { + return did_cancel_final_; + } + + private: + // Indicate whether to intercept the main request, and if so specify the + // response to return and the LoadTimingInfo to use. + mutable bool intercept_main_request_; + mutable std::string main_headers_; + mutable std::string main_data_; + mutable LoadTimingInfo main_request_load_timing_info_; + + // These indicate actions that can be taken within MaybeInterceptRequest. + mutable bool restart_main_request_; + mutable bool cancel_main_request_; + mutable bool cancel_then_restart_main_request_; + mutable bool simulate_main_network_error_; + + // Indicate whether to intercept redirects, and if so specify the response to + // return. + mutable bool intercept_redirect_; + mutable std::string redirect_headers_; + mutable std::string redirect_data_; + + // Cancel the request within MaybeInterceptRedirect. + mutable bool cancel_redirect_request_; + + // Indicate whether to intercept the final response, and if so specify the + // response to return. + mutable bool intercept_final_response_; + mutable std::string final_headers_; + mutable std::string final_data_; + + // Cancel the final request within MaybeInterceptResponse. + mutable bool cancel_final_request_; + + // Instruct the interceptor to use a real URLRequestHTTPJob. + mutable bool use_url_request_http_job_; + + // These indicate if the interceptor did something or not. + mutable bool did_intercept_main_; + mutable bool did_restart_main_; + mutable bool did_cancel_main_; + mutable bool did_cancel_then_restart_main_; + mutable bool did_simulate_error_main_; + mutable bool did_intercept_redirect_; + mutable bool did_cancel_redirect_; + mutable bool did_intercept_final_; + mutable bool did_cancel_final_; +}; + +// Inherit PlatformTest since we require the autorelease pool on Mac OS X. +class URLRequestInterceptorTest : public URLRequestTest { + public: + URLRequestInterceptorTest() : URLRequestTest(), interceptor_(NULL) { + } + + ~URLRequestInterceptorTest() override { + // URLRequestJobs may post clean-up tasks on destruction. + base::RunLoop().RunUntilIdle(); + } + + void SetUpFactory() override { + interceptor_ = new MockURLRequestInterceptor(); + job_factory_.reset(new URLRequestInterceptingJobFactory( + job_factory_.Pass(), make_scoped_ptr(interceptor_))); + } + + MockURLRequestInterceptor* interceptor() const { + return interceptor_; + } + + private: + MockURLRequestInterceptor* interceptor_; +}; + +TEST_F(URLRequestInterceptorTest, Intercept) { + // Intercept the main request and respond with a simple response. + interceptor()->set_intercept_main_request(true); + interceptor()->set_main_headers(MockURLRequestInterceptor::ok_headers()); + interceptor()->set_main_data(MockURLRequestInterceptor::ok_data()); TestDelegate d; - scoped_ptr<URLRequest> req(context->CreateRequest( - GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL)); + scoped_ptr<URLRequest> req(default_context().CreateRequest( + GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr)); + base::SupportsUserData::Data* user_data0 = new base::SupportsUserData::Data(); + base::SupportsUserData::Data* user_data1 = new base::SupportsUserData::Data(); + base::SupportsUserData::Data* user_data2 = new base::SupportsUserData::Data(); + req->SetUserData(nullptr, user_data0); + req->SetUserData(&user_data1, user_data1); + req->SetUserData(&user_data2, user_data2); + req->set_method("GET"); req->Start(); base::RunLoop().Run(); - LoadTimingInfo resulting_load_timing; - req->GetLoadTimingInfo(&resulting_load_timing); + // Make sure we can retrieve our specific user data. + EXPECT_EQ(user_data0, req->GetUserData(nullptr)); + EXPECT_EQ(user_data1, req->GetUserData(&user_data1)); + EXPECT_EQ(user_data2, req->GetUserData(&user_data2)); - // None of these should be modified by the URLRequest. - EXPECT_EQ(job_load_timing.socket_reused, resulting_load_timing.socket_reused); - EXPECT_EQ(job_load_timing.socket_log_id, resulting_load_timing.socket_log_id); - EXPECT_EQ(job_load_timing.send_start, resulting_load_timing.send_start); - EXPECT_EQ(job_load_timing.send_end, resulting_load_timing.send_end); - EXPECT_EQ(job_load_timing.receive_headers_end, - resulting_load_timing.receive_headers_end); + // Check that we got one good response. + EXPECT_TRUE(req->status().is_success()); + EXPECT_EQ(200, req->response_headers()->response_code()); + EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received()); + EXPECT_EQ(1, d.response_started_count()); + EXPECT_EQ(0, d.received_redirect_count()); +} - return resulting_load_timing; +TEST_F(URLRequestInterceptorTest, InterceptRedirect) { + // Intercept the main request and respond with a redirect. + interceptor()->set_intercept_main_request(true); + interceptor()->set_main_headers( + MockURLRequestInterceptor::redirect_headers()); + interceptor()->set_main_data(MockURLRequestInterceptor::redirect_data()); + + // Intercept that redirect and respond with a final OK response. + interceptor()->set_intercept_redirect(true); + interceptor()->set_redirect_headers(MockURLRequestInterceptor::ok_headers()); + interceptor()->set_redirect_data(MockURLRequestInterceptor::ok_data()); + + TestDelegate d; + scoped_ptr<URLRequest> req(default_context().CreateRequest( + GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr)); + req->set_method("GET"); + req->Start(); + base::RunLoop().Run(); + + // Check that the interceptor got called as expected. + EXPECT_TRUE(interceptor()->did_intercept_main()); + EXPECT_TRUE(interceptor()->did_intercept_redirect()); + + // Check that we got one good response. + EXPECT_TRUE(req->status().is_success()); + if (req->status().is_success()) + EXPECT_EQ(200, req->response_headers()->response_code()); + + EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received()); + EXPECT_EQ(1, d.response_started_count()); + EXPECT_EQ(0, d.received_redirect_count()); +} + +TEST_F(URLRequestInterceptorTest, InterceptServerError) { + // Intercept the main request to generate a server error response. + interceptor()->set_intercept_main_request(true); + interceptor()->set_main_headers(MockURLRequestInterceptor::error_headers()); + interceptor()->set_main_data(MockURLRequestInterceptor::error_data()); + + // Intercept that error and respond with an OK response. + interceptor()->set_intercept_final_response(true); + interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers()); + interceptor()->set_final_data(MockURLRequestInterceptor::ok_data()); + + TestDelegate d; + scoped_ptr<URLRequest> req(default_context().CreateRequest( + GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr)); + req->set_method("GET"); + req->Start(); + base::RunLoop().Run(); + + // Check that the interceptor got called as expected. + EXPECT_TRUE(interceptor()->did_intercept_main()); + EXPECT_TRUE(interceptor()->did_intercept_final()); + + // Check that we got one good response. + EXPECT_TRUE(req->status().is_success()); + EXPECT_EQ(200, req->response_headers()->response_code()); + EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received()); + EXPECT_EQ(1, d.response_started_count()); + EXPECT_EQ(0, d.received_redirect_count()); +} + +TEST_F(URLRequestInterceptorTest, InterceptNetworkError) { + // Intercept the main request to simulate a network error. + interceptor()->set_simulate_main_network_error(true); + + // Intercept that error and respond with an OK response. + interceptor()->set_intercept_final_response(true); + interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers()); + interceptor()->set_final_data(MockURLRequestInterceptor::ok_data()); + + TestDelegate d; + scoped_ptr<URLRequest> req(default_context().CreateRequest( + GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr)); + req->set_method("GET"); + req->Start(); + base::RunLoop().Run(); + + // Check that the interceptor got called as expected. + EXPECT_TRUE(interceptor()->did_simulate_error_main()); + EXPECT_TRUE(interceptor()->did_intercept_final()); + + // Check that we received one good response. + EXPECT_TRUE(req->status().is_success()); + EXPECT_EQ(200, req->response_headers()->response_code()); + EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received()); + EXPECT_EQ(1, d.response_started_count()); + EXPECT_EQ(0, d.received_redirect_count()); +} + +TEST_F(URLRequestInterceptorTest, InterceptRestartRequired) { + // Restart the main request. + interceptor()->set_restart_main_request(true); + + // then intercept the new main request and respond with an OK response + interceptor()->set_intercept_main_request(true); + interceptor()->set_main_headers(MockURLRequestInterceptor::ok_headers()); + interceptor()->set_main_data(MockURLRequestInterceptor::ok_data()); + + TestDelegate d; + scoped_ptr<URLRequest> req(default_context().CreateRequest( + GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr)); + req->set_method("GET"); + req->Start(); + base::RunLoop().Run(); + + // Check that the interceptor got called as expected. + EXPECT_TRUE(interceptor()->did_restart_main()); + EXPECT_TRUE(interceptor()->did_intercept_main()); + + // Check that we received one good response. + EXPECT_TRUE(req->status().is_success()); + if (req->status().is_success()) + EXPECT_EQ(200, req->response_headers()->response_code()); + + EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received()); + EXPECT_EQ(1, d.response_started_count()); + EXPECT_EQ(0, d.received_redirect_count()); +} + +TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelMain) { + // Intercept the main request and cancel from within the restarted job. + interceptor()->set_cancel_main_request(true); + + // Set up to intercept the final response and override it with an OK response. + interceptor()->set_intercept_final_response(true); + interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers()); + interceptor()->set_final_data(MockURLRequestInterceptor::ok_data()); + + TestDelegate d; + scoped_ptr<URLRequest> req(default_context().CreateRequest( + GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr)); + req->set_method("GET"); + req->Start(); + base::RunLoop().Run(); + + // Check that the interceptor got called as expected. + EXPECT_TRUE(interceptor()->did_cancel_main()); + EXPECT_FALSE(interceptor()->did_intercept_final()); + + // Check that we see a canceled request. + EXPECT_FALSE(req->status().is_success()); + EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status()); +} + +TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelRedirect) { + // Intercept the main request and respond with a redirect. + interceptor()->set_intercept_main_request(true); + interceptor()->set_main_headers( + MockURLRequestInterceptor::redirect_headers()); + interceptor()->set_main_data(MockURLRequestInterceptor::redirect_data()); + + // Intercept the redirect and cancel from within that job. + interceptor()->set_cancel_redirect_request(true); + + // Set up to intercept the final response and override it with an OK response. + interceptor()->set_intercept_final_response(true); + interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers()); + interceptor()->set_final_data(MockURLRequestInterceptor::ok_data()); + + TestDelegate d; + scoped_ptr<URLRequest> req(default_context().CreateRequest( + GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr)); + req->set_method("GET"); + req->Start(); + base::RunLoop().Run(); + + // Check that the interceptor got called as expected. + EXPECT_TRUE(interceptor()->did_intercept_main()); + EXPECT_TRUE(interceptor()->did_cancel_redirect()); + EXPECT_FALSE(interceptor()->did_intercept_final()); + + // Check that we see a canceled request. + EXPECT_FALSE(req->status().is_success()); + EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status()); +} + +TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelFinal) { + // Intercept the main request to simulate a network error. + interceptor()->set_simulate_main_network_error(true); + + // Set up to intercept final the response and cancel from within that job. + interceptor()->set_cancel_final_request(true); + + TestDelegate d; + scoped_ptr<URLRequest> req(default_context().CreateRequest( + GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr)); + req->set_method("GET"); + req->Start(); + base::RunLoop().Run(); + + // Check that the interceptor got called as expected. + EXPECT_TRUE(interceptor()->did_simulate_error_main()); + EXPECT_TRUE(interceptor()->did_cancel_final()); + + // Check that we see a canceled request. + EXPECT_FALSE(req->status().is_success()); + EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status()); +} + +TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelInRestart) { + // Intercept the main request and cancel then restart from within that job. + interceptor()->set_cancel_then_restart_main_request(true); + + // Set up to intercept the final response and override it with an OK response. + interceptor()->set_intercept_final_response(true); + interceptor()->set_final_headers(TestInterceptor::ok_headers()); + interceptor()->set_final_data(TestInterceptor::ok_data()); + + TestDelegate d; + scoped_ptr<URLRequest> req(default_context().CreateRequest( + GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr)); + req->set_method("GET"); + req->Start(); + base::RunLoop().Run(); + + // Check that the interceptor got called as expected. + EXPECT_TRUE(interceptor()->did_cancel_then_restart_main()); + EXPECT_FALSE(interceptor()->did_intercept_final()); + + // Check that we see a canceled request. + EXPECT_FALSE(req->status().is_success()); + EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status()); } // "Normal" LoadTimingInfo as returned by a job. Everything is in order, not @@ -1649,14 +2213,41 @@ LoadTimingInfo NormalLoadTimingInfoReused(base::TimeTicks now, return load_timing; } +LoadTimingInfo RunURLRequestInterceptorLoadTimingTest( + const LoadTimingInfo& job_load_timing, + const URLRequestContext& context, + MockURLRequestInterceptor* interceptor) { + interceptor->set_intercept_main_request(true); + interceptor->set_main_request_load_timing_info(job_load_timing); + TestDelegate d; + scoped_ptr<URLRequest> req(context.CreateRequest( + GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr)); + req->Start(); + base::RunLoop().Run(); + + LoadTimingInfo resulting_load_timing; + req->GetLoadTimingInfo(&resulting_load_timing); + + // None of these should be modified by the URLRequest. + EXPECT_EQ(job_load_timing.socket_reused, resulting_load_timing.socket_reused); + EXPECT_EQ(job_load_timing.socket_log_id, resulting_load_timing.socket_log_id); + EXPECT_EQ(job_load_timing.send_start, resulting_load_timing.send_start); + EXPECT_EQ(job_load_timing.send_end, resulting_load_timing.send_end); + EXPECT_EQ(job_load_timing.receive_headers_end, + resulting_load_timing.receive_headers_end); + + return resulting_load_timing; +} + // Basic test that the intercept + load timing tests work. -TEST_F(URLRequestTest, InterceptLoadTiming) { +TEST_F(URLRequestInterceptorTest, InterceptLoadTiming) { base::TimeTicks now = base::TimeTicks::Now(); LoadTimingInfo job_load_timing = NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_DNS_TIMES, false); LoadTimingInfo load_timing_result = - RunLoadTimingTest(job_load_timing, &default_context_); + RunURLRequestInterceptorLoadTimingTest( + job_load_timing, default_context(), interceptor()); // Nothing should have been changed by the URLRequest. EXPECT_EQ(job_load_timing.proxy_resolve_start, @@ -1681,13 +2272,14 @@ TEST_F(URLRequestTest, InterceptLoadTiming) { } // Another basic test, with proxy and SSL times, but no DNS times. -TEST_F(URLRequestTest, InterceptLoadTimingProxy) { +TEST_F(URLRequestInterceptorTest, InterceptLoadTimingProxy) { base::TimeTicks now = base::TimeTicks::Now(); LoadTimingInfo job_load_timing = NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_SSL_TIMES, true); LoadTimingInfo load_timing_result = - RunLoadTimingTest(job_load_timing, &default_context_); + RunURLRequestInterceptorLoadTimingTest( + job_load_timing, default_context(), interceptor()); // Nothing should have been changed by the URLRequest. EXPECT_EQ(job_load_timing.proxy_resolve_start, @@ -1718,7 +2310,7 @@ TEST_F(URLRequestTest, InterceptLoadTimingProxy) { // reused in this test (May be a preconnect). // // To mix things up from the test above, assumes DNS times but no SSL times. -TEST_F(URLRequestTest, InterceptLoadTimingEarlyProxyResolution) { +TEST_F(URLRequestInterceptorTest, InterceptLoadTimingEarlyProxyResolution) { base::TimeTicks now = base::TimeTicks::Now(); LoadTimingInfo job_load_timing = NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_DNS_TIMES, true); @@ -1732,7 +2324,8 @@ TEST_F(URLRequestTest, InterceptLoadTimingEarlyProxyResolution) { now - base::TimeDelta::FromDays(1); LoadTimingInfo load_timing_result = - RunLoadTimingTest(job_load_timing, &default_context_); + RunURLRequestInterceptorLoadTimingTest( + job_load_timing, default_context(), interceptor()); // Proxy times, connect times, and DNS times should all be replaced with // request_start. @@ -1755,14 +2348,16 @@ TEST_F(URLRequestTest, InterceptLoadTimingEarlyProxyResolution) { } // Same as above, but in the reused case. -TEST_F(URLRequestTest, InterceptLoadTimingEarlyProxyResolutionReused) { +TEST_F(URLRequestInterceptorTest, + InterceptLoadTimingEarlyProxyResolutionReused) { base::TimeTicks now = base::TimeTicks::Now(); LoadTimingInfo job_load_timing = NormalLoadTimingInfoReused(now, true); job_load_timing.proxy_resolve_start = now - base::TimeDelta::FromDays(4); job_load_timing.proxy_resolve_end = now - base::TimeDelta::FromDays(3); LoadTimingInfo load_timing_result = - RunLoadTimingTest(job_load_timing, &default_context_); + RunURLRequestInterceptorLoadTimingTest( + job_load_timing, default_context(), interceptor()); // Proxy times and connect times should all be replaced with request_start. EXPECT_EQ(load_timing_result.request_start, @@ -1779,7 +2374,7 @@ TEST_F(URLRequestTest, InterceptLoadTimingEarlyProxyResolutionReused) { // not considered reused in this test (May be a preconnect). // // To mix things up, the request has SSL times, but no DNS times. -TEST_F(URLRequestTest, InterceptLoadTimingEarlyConnect) { +TEST_F(URLRequestInterceptorTest, InterceptLoadTimingEarlyConnect) { base::TimeTicks now = base::TimeTicks::Now(); LoadTimingInfo job_load_timing = NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_SSL_TIMES, false); @@ -1791,7 +2386,8 @@ TEST_F(URLRequestTest, InterceptLoadTimingEarlyConnect) { now - base::TimeDelta::FromDays(4); LoadTimingInfo load_timing_result = - RunLoadTimingTest(job_load_timing, &default_context_); + RunURLRequestInterceptorLoadTimingTest( + job_load_timing, default_context(), interceptor()); // Connect times, and SSL times should be replaced with request_start. EXPECT_EQ(load_timing_result.request_start, @@ -1813,7 +2409,7 @@ TEST_F(URLRequestTest, InterceptLoadTimingEarlyConnect) { // test (May be a preconnect). // // In this test, there are no SSL or DNS times. -TEST_F(URLRequestTest, InterceptLoadTimingEarlyConnectWithProxy) { +TEST_F(URLRequestInterceptorTest, InterceptLoadTimingEarlyConnectWithProxy) { base::TimeTicks now = base::TimeTicks::Now(); LoadTimingInfo job_load_timing = NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY, true); @@ -1823,7 +2419,8 @@ TEST_F(URLRequestTest, InterceptLoadTimingEarlyConnectWithProxy) { now - base::TimeDelta::FromDays(2); LoadTimingInfo load_timing_result = - RunLoadTimingTest(job_load_timing, &default_context_); + RunURLRequestInterceptorLoadTimingTest( + job_load_timing, default_context(), interceptor()); // Connect times should be replaced with proxy_resolve_end. EXPECT_EQ(load_timing_result.proxy_resolve_end, @@ -2665,6 +3262,11 @@ class URLRequestTestHTTP : public URLRequestTest { return is_success; } + LocalHttpTestServer* test_server() { + return &test_server_; + } + + protected: LocalHttpTestServer test_server_; }; @@ -5166,7 +5768,7 @@ TEST_F(URLRequestTestHTTP, ProtocolHandlerAndFactoryRestrictDataRedirects) { EXPECT_FALSE(data_protocol_handler.IsSafeRedirectTarget(data_url)); // Test URLRequestJobFactoryImpl::IsSafeRedirectTarget(). - EXPECT_FALSE(job_factory_.IsSafeRedirectTarget(data_url)); + EXPECT_FALSE(job_factory_->IsSafeRedirectTarget(data_url)); } #if !defined(DISABLE_FILE_SUPPORT) @@ -5177,7 +5779,7 @@ TEST_F(URLRequestTestHTTP, ProtocolHandlerAndFactoryRestrictFileRedirects) { EXPECT_FALSE(file_protocol_handler.IsSafeRedirectTarget(file_url)); // Test URLRequestJobFactoryImpl::IsSafeRedirectTarget(). - EXPECT_FALSE(job_factory_.IsSafeRedirectTarget(file_url)); + EXPECT_FALSE(job_factory_->IsSafeRedirectTarget(file_url)); } TEST_F(URLRequestTestHTTP, RestrictFileRedirects) { @@ -6446,6 +7048,124 @@ TEST_F(URLRequestTestHTTP, NetworkSuspendTestNoCache) { EXPECT_EQ(ERR_NETWORK_IO_SUSPENDED, req->status().error()); } +class URLRequestInterceptorTestHTTP : public URLRequestTestHTTP { + public: + // TODO(bengr): Merge this with the URLRequestInterceptorHTTPTest fixture, + // ideally remove the dependency on URLRequestTestJob, and maybe move these + // tests into the factory tests. + URLRequestInterceptorTestHTTP() : URLRequestTestHTTP(), interceptor_(NULL) { + } + + void SetUpFactory() override { + interceptor_ = new MockURLRequestInterceptor(); + job_factory_.reset(new URLRequestInterceptingJobFactory( + job_factory_.Pass(), make_scoped_ptr(interceptor_))); + } + + MockURLRequestInterceptor* interceptor() const { + return interceptor_; + } + + private: + MockURLRequestInterceptor* interceptor_; +}; + +TEST_F(URLRequestInterceptorTestHTTP, + NetworkDelegateNotificationOnRedirectIntercept) { + interceptor()->set_intercept_redirect(true); + interceptor()->set_redirect_headers(MockURLRequestInterceptor::ok_headers()); + interceptor()->set_redirect_data(MockURLRequestInterceptor::ok_data()); + + ASSERT_TRUE(test_server()->Start()); + + TestDelegate d; + scoped_ptr<URLRequest> req(default_context().CreateRequest( + test_server()->GetURL("files/redirect-test.html"), DEFAULT_PRIORITY, + &d, nullptr)); + req->Start(); + base::RunLoop().Run(); + + EXPECT_TRUE(interceptor()->did_intercept_redirect()); + // Check we got one good response + EXPECT_TRUE(req->status().is_success()); + if (req->status().is_success()) + EXPECT_EQ(200, req->response_headers()->response_code()); + + EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received()); + EXPECT_EQ(1, d.response_started_count()); + EXPECT_EQ(0, d.received_redirect_count()); + + EXPECT_EQ(1, default_network_delegate()->created_requests()); + EXPECT_EQ(1, default_network_delegate()->before_send_headers_count()); + EXPECT_EQ(1, default_network_delegate()->headers_received_count()); +} + +TEST_F(URLRequestInterceptorTestHTTP, + NetworkDelegateNotificationOnErrorIntercept) { + // Intercept that error and respond with an OK response. + interceptor()->set_intercept_final_response(true); + interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers()); + interceptor()->set_final_data(MockURLRequestInterceptor::ok_data()); + default_network_delegate()->set_can_be_intercepted_on_error(true); + + ASSERT_TRUE(test_server()->Start()); + + TestDelegate d; + scoped_ptr<URLRequest> req(default_context().CreateRequest( + test_server()->GetURL("files/two-content-lengths.html"), DEFAULT_PRIORITY, + &d, nullptr)); + req->set_method("GET"); + req->Start(); + base::RunLoop().Run(); + + EXPECT_TRUE(interceptor()->did_intercept_final()); + + // Check we received one good response. + EXPECT_TRUE(req->status().is_success()); + if (req->status().is_success()) + EXPECT_EQ(200, req->response_headers()->response_code()); + EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received()); + EXPECT_EQ(1, d.response_started_count()); + EXPECT_EQ(0, d.received_redirect_count()); + + EXPECT_EQ(1, default_network_delegate()->created_requests()); + EXPECT_EQ(1, default_network_delegate()->before_send_headers_count()); + EXPECT_EQ(0, default_network_delegate()->headers_received_count()); +} + +TEST_F(URLRequestInterceptorTestHTTP, + NetworkDelegateNotificationOnResponseIntercept) { + // Intercept that error and respond with an OK response. + interceptor()->set_intercept_final_response(true); + + // Intercept with a real URLRequestHttpJob. + interceptor()->set_use_url_request_http_job(true); + + ASSERT_TRUE(test_server()->Start()); + + TestDelegate d; + scoped_ptr<URLRequest> req(default_context().CreateRequest( + test_server()->GetURL("files/simple.html"), DEFAULT_PRIORITY, + &d, nullptr)); + req->set_method("GET"); + req->Start(); + base::RunLoop().Run(); + + EXPECT_TRUE(interceptor()->did_intercept_final()); + + // Check we received one good response. + EXPECT_TRUE(req->status().is_success()); + if (req->status().is_success()) + EXPECT_EQ(200, req->response_headers()->response_code()); + EXPECT_EQ("hello", d.data_received()); + EXPECT_EQ(1, d.response_started_count()); + EXPECT_EQ(0, d.received_redirect_count()); + + EXPECT_EQ(1, default_network_delegate()->created_requests()); + EXPECT_EQ(2, default_network_delegate()->before_send_headers_count()); + EXPECT_EQ(2, default_network_delegate()->headers_received_count()); +} + class HTTPSRequestTest : public testing::Test { public: HTTPSRequestTest() : default_context_(true) { |