Index: net/url_request/url_request_unittest.cc |
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc |
index 139b6f3ee270e404ab14d9d93af038a02184c667..2aeecc639e7b5e06eeb9c892942da2249196d47b 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) { |
@@ -7590,7 +8310,7 @@ static bool SystemUsesChromiumEVMetadata() { |
} |
static bool SystemSupportsOCSP() { |
-#if defined(USE_OPENSSL) |
+#if defined(USE_OPENSSL_CERTS) |
// http://crbug.com/117478 - OpenSSL does not support OCSP. |
return false; |
#elif defined(OS_WIN) |
@@ -7603,6 +8323,16 @@ static bool SystemSupportsOCSP() { |
#endif |
} |
+static bool SystemSupportsOCSPStapling() { |
+#if defined(USE_NSS) |
+ return true; |
+#elif defined(OS_WIN) |
+ return base::win::GetVersion() >= base::win::VERSION_VISTA; |
+#else |
+ return false; |
+#endif |
+} |
+ |
TEST_F(HTTPSOCSPTest, Valid) { |
if (!SystemSupportsOCSP()) { |
LOG(WARNING) << "Skipping test because system doesn't support OCSP"; |
@@ -7666,6 +8396,51 @@ TEST_F(HTTPSOCSPTest, Invalid) { |
EXPECT_TRUE(cert_status & CERT_STATUS_REV_CHECKING_ENABLED); |
} |
+TEST_F(HTTPSOCSPTest, ValidStapled) { |
+ if (!SystemSupportsOCSPStapling()) { |
+ LOG(WARNING) |
+ << "Skipping test because system doesn't support OCSP stapling"; |
+ return; |
+ } |
+ |
+ SpawnedTestServer::SSLOptions ssl_options( |
+ SpawnedTestServer::SSLOptions::CERT_AUTO); |
+ ssl_options.ocsp_status = SpawnedTestServer::SSLOptions::OCSP_OK; |
+ ssl_options.staple_ocsp_response = true; |
+ ssl_options.ocsp_server_unavailable = true; |
+ |
+ CertStatus cert_status; |
+ DoConnection(ssl_options, &cert_status); |
+ |
+ EXPECT_EQ(0u, cert_status & CERT_STATUS_ALL_ERRORS); |
+ |
+ EXPECT_EQ(SystemUsesChromiumEVMetadata(), |
+ static_cast<bool>(cert_status & CERT_STATUS_IS_EV)); |
+ |
+ EXPECT_TRUE(cert_status & CERT_STATUS_REV_CHECKING_ENABLED); |
+} |
+ |
+TEST_F(HTTPSOCSPTest, RevokedStapled) { |
+ if (!SystemSupportsOCSPStapling()) { |
+ LOG(WARNING) |
+ << "Skipping test because system doesn't support OCSP stapling"; |
+ return; |
+ } |
+ |
+ SpawnedTestServer::SSLOptions ssl_options( |
+ SpawnedTestServer::SSLOptions::CERT_AUTO); |
+ ssl_options.ocsp_status = SpawnedTestServer::SSLOptions::OCSP_REVOKED; |
+ ssl_options.staple_ocsp_response = true; |
+ ssl_options.ocsp_server_unavailable = true; |
+ |
+ CertStatus cert_status; |
+ DoConnection(ssl_options, &cert_status); |
+ |
+ EXPECT_EQ(CERT_STATUS_REVOKED, cert_status & CERT_STATUS_ALL_ERRORS); |
+ EXPECT_FALSE(cert_status & CERT_STATUS_IS_EV); |
+ EXPECT_TRUE(cert_status & CERT_STATUS_REV_CHECKING_ENABLED); |
+} |
+ |
class HTTPSHardFailTest : public HTTPSOCSPTest { |
protected: |
void SetupContext(URLRequestContext* context) override { |
@@ -7677,7 +8452,6 @@ class HTTPSHardFailTest : public HTTPSOCSPTest { |
} |
}; |
- |
TEST_F(HTTPSHardFailTest, FailsOnOCSPInvalid) { |
if (!SystemSupportsOCSP()) { |
LOG(WARNING) << "Skipping test because system doesn't support OCSP"; |