Index: net/http/http_stream_factory_impl_job_controller_unittest.cc |
diff --git a/net/http/http_stream_factory_impl_job_controller_unittest.cc b/net/http/http_stream_factory_impl_job_controller_unittest.cc |
index 395372995aeba3dba4f535ea7c029862ba479aae..dad4a1add61b761e421953a9127869bd9ca9465f 100644 |
--- a/net/http/http_stream_factory_impl_job_controller_unittest.cc |
+++ b/net/http/http_stream_factory_impl_job_controller_unittest.cc |
@@ -8,6 +8,8 @@ |
#include "base/memory/ptr_util.h" |
#include "base/run_loop.h" |
+#include "base/threading/platform_thread.h" |
+#include "net/base/test_proxy_delegate.h" |
#include "net/dns/mock_host_resolver.h" |
#include "net/http/http_basic_stream.h" |
#include "net/http/http_stream_factory_impl_request.h" |
@@ -18,6 +20,7 @@ |
#include "net/proxy/proxy_service.h" |
#include "net/quic/test_tools/quic_stream_factory_peer.h" |
#include "net/spdy/spdy_test_util_common.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
#include "testing/gmock_mutant.h" |
#include "testing/gtest/include/gtest/gtest.h" |
@@ -97,6 +100,11 @@ class JobControllerPeer { |
const base::TimeDelta& delay) { |
EXPECT_EQ(delay, job_controller->main_job_wait_time_); |
} |
+ |
+ static bool main_job_is_blocked( |
+ HttpStreamFactoryImpl::JobController* job_controller) { |
+ return job_controller->main_job_is_blocked_; |
+ } |
}; |
class HttpStreamFactoryImplJobControllerTest |
@@ -108,7 +116,21 @@ class HttpStreamFactoryImplJobControllerTest |
session_deps_.enable_quic = true; |
} |
- void Initialize() { |
+ void Initialize(bool use_alternative_proxy) { |
+ std::unique_ptr<TestProxyDelegate> test_proxy_delegate( |
+ new TestProxyDelegate()); |
+ test_proxy_delegate_ = test_proxy_delegate.get(); |
+ |
+ test_proxy_delegate->set_alternative_proxy_server( |
+ ProxyServer::FromPacString("QUIC myproxy.org:443")); |
+ EXPECT_TRUE(test_proxy_delegate->alternative_proxy_server().is_quic()); |
+ session_deps_.proxy_delegate.reset(test_proxy_delegate.release()); |
+ |
+ if (use_alternative_proxy) { |
+ std::unique_ptr<ProxyService> proxy_service = |
+ ProxyService::CreateFixedFromPacResult("HTTPS myproxy.org:443"); |
+ session_deps_.proxy_service.reset(proxy_service.release()); |
+ } |
session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_); |
factory_ = |
static_cast<HttpStreamFactoryImpl*>(session_->http_stream_factory()); |
@@ -117,6 +139,10 @@ class HttpStreamFactoryImplJobControllerTest |
HttpStreamFactoryImplPeer::AddJobController(factory_, job_controller_); |
} |
+ TestProxyDelegate* test_proxy_delegate() const { |
+ return test_proxy_delegate_; |
+ } |
+ |
~HttpStreamFactoryImplJobControllerTest() {} |
void SetAlternativeService(const HttpRequestInfo& request_info, |
@@ -128,6 +154,8 @@ class HttpStreamFactoryImplJobControllerTest |
server, alternative_service, expiration); |
} |
+ // Not owned by |this|. |
+ TestProxyDelegate* test_proxy_delegate_; |
TestJobFactory job_factory_; |
MockHttpStreamRequestDelegate request_delegate_; |
SpdySessionDependencies session_deps_; |
@@ -149,7 +177,7 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, |
session_deps_.proxy_service.reset(new ProxyService( |
base::WrapUnique(new ProxyConfigServiceFixed(proxy_config)), |
base::WrapUnique(proxy_resolver_factory), nullptr)); |
- Initialize(); |
+ Initialize(false); |
HttpRequestInfo request_info; |
request_info.method = "GET"; |
@@ -179,7 +207,7 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, |
session_deps_.proxy_service.reset(new ProxyService( |
base::WrapUnique(new ProxyConfigServiceFixed(proxy_config)), |
base::WrapUnique(proxy_resolver_factory), nullptr)); |
- Initialize(); |
+ Initialize(false); |
HttpRequestInfo request_info; |
request_info.method = "GET"; |
@@ -213,7 +241,7 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, CancelJobsBeforeBinding) { |
session_deps_.proxy_service.reset(new ProxyService( |
base::WrapUnique(new ProxyConfigServiceFixed(proxy_config)), |
base::WrapUnique(proxy_resolver_factory), nullptr)); |
- Initialize(); |
+ Initialize(false); |
HttpRequestInfo request_info; |
request_info.method = "GET"; |
@@ -246,7 +274,7 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, OnStreamFailedForBothJobs) { |
session_deps_.proxy_service.reset(new ProxyService( |
base::WrapUnique(new ProxyConfigServiceFixed(proxy_config)), |
base::WrapUnique(proxy_resolver_factory), nullptr)); |
- Initialize(); |
+ Initialize(false); |
HttpRequestInfo request_info; |
request_info.method = "GET"; |
@@ -290,7 +318,7 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, |
session_deps_.proxy_service.reset(new ProxyService( |
base::WrapUnique(new ProxyConfigServiceFixed(proxy_config)), |
base::WrapUnique(proxy_resolver_factory), nullptr)); |
- Initialize(); |
+ Initialize(false); |
HttpRequestInfo request_info; |
request_info.method = "GET"; |
@@ -342,7 +370,7 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, |
session_deps_.proxy_service.reset(new ProxyService( |
base::WrapUnique(new ProxyConfigServiceFixed(proxy_config)), |
base::WrapUnique(proxy_resolver_factory), nullptr)); |
- Initialize(); |
+ Initialize(false); |
HttpRequestInfo request_info; |
request_info.method = "GET"; |
@@ -390,7 +418,7 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, GetLoadStateAfterMainJobFailed) { |
session_deps_.proxy_service.reset(new ProxyService( |
base::WrapUnique(new ProxyConfigServiceFixed(proxy_config)), |
base::WrapUnique(proxy_resolver_factory), nullptr)); |
- Initialize(); |
+ Initialize(false); |
HttpRequestInfo request_info; |
request_info.method = "GET"; |
@@ -441,7 +469,7 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, DoNotResumeMainJobBeforeWait) { |
base::WrapUnique(new ProxyConfigServiceFixed(proxy_config)), |
base::WrapUnique(new FailingProxyResolverFactory), nullptr)); |
- Initialize(); |
+ Initialize(false); |
HttpRequestInfo request_info; |
request_info.method = "GET"; |
@@ -467,7 +495,7 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, DoNotResumeMainJobBeforeWait) { |
TEST_F(HttpStreamFactoryImplJobControllerTest, InvalidPortForQuic) { |
// Using a restricted port 101 for QUIC should fail and the alternative job |
// should post OnStreamFailedCall on the controller to resume the main job. |
- Initialize(); |
+ Initialize(false); |
HttpRequestInfo request_info; |
request_info.method = "GET"; |
@@ -509,7 +537,7 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, |
session_deps_.host_resolver.reset(host_resolver); |
session_deps_.host_resolver->set_synchronous_mode(false); |
- Initialize(); |
+ Initialize(false); |
HttpRequestInfo request_info; |
request_info.method = "GET"; |
@@ -573,7 +601,7 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, |
base::WrapUnique(new ProxyConfigServiceFixed(proxy_config)), |
base::WrapUnique(proxy_resolver_factory), nullptr)); |
- Initialize(); |
+ Initialize(false); |
HttpRequestInfo request_info; |
request_info.method = "GET"; |
@@ -626,7 +654,7 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, DelayedTCP) { |
HangingResolver* resolver = new HangingResolver(); |
session_deps_.host_resolver.reset(resolver); |
- Initialize(); |
+ Initialize(false); |
// Enable delayed TCP and set time delay for waiting job. |
QuicStreamFactory* quic_stream_factory = session_->quic_stream_factory(); |
@@ -663,4 +691,171 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, DelayedTCP) { |
base::RunLoop().RunUntilIdle(); |
} |
+ |
+// Verifies that the alternative proxy server job is not created if the URL |
+// scheme is HTTPS. |
+TEST_F(HttpStreamFactoryImplJobControllerTest, HttpsURL) { |
+ // Using hanging resolver will cause the alternative job to hang indefinitely. |
+ HangingResolver* resolver = new HangingResolver(); |
+ session_deps_.host_resolver.reset(resolver); |
+ |
+ Initialize(true); |
+ EXPECT_TRUE(test_proxy_delegate()->alternative_proxy_server().is_quic()); |
+ |
+ HttpRequestInfo request_info; |
+ request_info.method = "GET"; |
+ request_info.url = GURL("https://mail.example.org/"); |
+ |
+ request_.reset( |
+ job_controller_->Start(request_info, &request_delegate_, nullptr, |
+ BoundNetLog(), HttpStreamRequest::HTTP_STREAM, |
+ DEFAULT_PRIORITY, SSLConfig(), SSLConfig())); |
+ EXPECT_TRUE(job_controller_->main_job()); |
+ EXPECT_FALSE(job_controller_->main_job()->is_waiting()); |
+ EXPECT_FALSE(job_controller_->alternative_job()); |
+ |
+ EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(0); |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_EQ(0, test_proxy_delegate()->get_alternative_proxy_invocations()); |
+} |
+ |
+// Verifies that the alternative proxy server job is not created if the main job |
+// does not fetch the resource through a proxy. |
+TEST_F(HttpStreamFactoryImplJobControllerTest, HttpURLWithNoProxy) { |
+ // Using hanging resolver will cause the alternative job to hang indefinitely. |
+ HangingResolver* resolver = new HangingResolver(); |
+ session_deps_.host_resolver.reset(resolver); |
+ |
+ Initialize(false); |
+ EXPECT_TRUE(test_proxy_delegate()->alternative_proxy_server().is_quic()); |
+ |
+ HttpRequestInfo request_info; |
+ request_info.method = "GET"; |
+ request_info.url = GURL("http://mail.example.org/"); |
+ |
+ request_.reset( |
+ job_controller_->Start(request_info, &request_delegate_, nullptr, |
+ BoundNetLog(), HttpStreamRequest::HTTP_STREAM, |
+ DEFAULT_PRIORITY, SSLConfig(), SSLConfig())); |
+ EXPECT_TRUE(job_controller_->main_job()); |
+ EXPECT_FALSE(job_controller_->main_job()->is_waiting()); |
+ EXPECT_FALSE(job_controller_->alternative_job()); |
+ |
+ EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(0); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ EXPECT_EQ(0, test_proxy_delegate()->get_alternative_proxy_invocations()); |
+} |
+ |
+// Verifies that the main job is resumed properly after a delay when the |
+// alternative proxy server job hangs. |
+TEST_F(HttpStreamFactoryImplJobControllerTest, DelayedTCPAlternativeProxy) { |
+ // Using hanging resolver will cause the alternative job to hang indefinitely. |
+ HangingResolver* resolver = new HangingResolver(); |
+ session_deps_.host_resolver.reset(resolver); |
+ |
+ Initialize(true); |
+ EXPECT_TRUE(test_proxy_delegate()->alternative_proxy_server().is_quic()); |
+ |
+ // Enable delayed TCP and set time delay for waiting job. |
+ QuicStreamFactory* quic_stream_factory = session_->quic_stream_factory(); |
+ test::QuicStreamFactoryPeer::SetDelayTcpRace(quic_stream_factory, true); |
+ quic_stream_factory->set_require_confirmation(false); |
+ ServerNetworkStats stats1; |
+ stats1.srtt = base::TimeDelta::FromMicroseconds(10); |
+ session_->http_server_properties()->SetServerNetworkStats( |
+ url::SchemeHostPort(GURL("https://myproxy.org")), stats1); |
+ |
+ HttpRequestInfo request_info; |
+ request_info.method = "GET"; |
+ request_info.url = GURL("http://mail.example.org/"); |
+ |
+ request_.reset( |
+ job_controller_->Start(request_info, &request_delegate_, nullptr, |
+ BoundNetLog(), HttpStreamRequest::HTTP_STREAM, |
+ DEFAULT_PRIORITY, SSLConfig(), SSLConfig())); |
+ EXPECT_TRUE(job_controller_->main_job()); |
+ EXPECT_TRUE(job_controller_->main_job()->is_waiting()); |
+ EXPECT_TRUE(job_controller_->alternative_job()); |
+ EXPECT_TRUE(JobControllerPeer::main_job_is_blocked(job_controller_)); |
+ |
+ // The alternative proxy server job stalls when connecting to the alternative |
+ // proxy server, and controller should resume the main job after delay. |
+ // Verify the waiting time for delayed main job. |
+ EXPECT_CALL(*job_factory_.main_job(), Resume()) |
+ .WillOnce(Invoke(testing::CreateFunctor( |
+ &JobControllerPeer::VerifyWaitingTimeForMainJob, job_controller_, |
+ base::TimeDelta::FromMicroseconds(15)))); |
+ |
+ // This message loop should cause the alternative proxy server job to start, |
+ // and schedule resumption of the main job. |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_FALSE(JobControllerPeer::main_job_is_blocked(job_controller_)); |
+ |
+ // Wait for the Resume to post. |
+ base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); |
+ |
+ // This message loop should cause the main job to resume. |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_FALSE(JobControllerPeer::main_job_is_blocked(job_controller_)); |
+ |
+ JobControllerPeer::VerifyWaitingTimeForMainJob( |
+ job_controller_, base::TimeDelta::FromMicroseconds(0)); |
+ |
+ // Since the main job did not complete successfully, the alternative proxy |
+ // server should not be marked as bad. |
+ EXPECT_TRUE(test_proxy_delegate()->alternative_proxy_server().is_valid()); |
+ EXPECT_EQ(1, test_proxy_delegate()->get_alternative_proxy_invocations()); |
+} |
+ |
+// Verifies that the alternative proxy server job fails immediately, and the |
+// main job is not blocked. |
+TEST_F(HttpStreamFactoryImplJobControllerTest, FailAlternativeProxy) { |
+ // Using failing resolver will cause the alternative job to fail. |
+ FailingHostResolver* resolver = new FailingHostResolver(); |
+ session_deps_.host_resolver.reset(resolver); |
+ |
+ Initialize(true); |
+ EXPECT_TRUE(test_proxy_delegate()->alternative_proxy_server().is_quic()); |
+ |
+ // Enable delayed TCP and set time delay for waiting job. |
+ QuicStreamFactory* quic_stream_factory = session_->quic_stream_factory(); |
+ test::QuicStreamFactoryPeer::SetDelayTcpRace(quic_stream_factory, true); |
+ quic_stream_factory->set_require_confirmation(false); |
+ ServerNetworkStats stats1; |
+ stats1.srtt = base::TimeDelta::FromMicroseconds(300 * 1000); |
+ session_->http_server_properties()->SetServerNetworkStats( |
+ url::SchemeHostPort(GURL("https://myproxy.org")), stats1); |
+ |
+ HttpRequestInfo request_info; |
+ request_info.method = "GET"; |
+ request_info.url = GURL("http://mail.example.org/"); |
+ |
+ request_.reset( |
+ job_controller_->Start(request_info, &request_delegate_, nullptr, |
+ BoundNetLog(), HttpStreamRequest::HTTP_STREAM, |
+ DEFAULT_PRIORITY, SSLConfig(), SSLConfig())); |
+ EXPECT_TRUE(job_controller_->main_job()->is_waiting()); |
+ EXPECT_TRUE(job_controller_->alternative_job()); |
+ |
+ EXPECT_CALL(request_delegate_, OnStreamReady(_, _, _)).Times(0); |
+ EXPECT_CALL(*job_factory_.main_job(), MarkOtherJobComplete(_)).Times(1); |
+ |
+ // Since the alternative proxy server job is started in the next message loop, |
+ // the main job would remain blocked until the alternative proxy starts, and |
+ // fails. |
+ EXPECT_CALL(*job_factory_.main_job(), Resume()) |
+ .WillOnce(Invoke(testing::CreateFunctor( |
+ &JobControllerPeer::VerifyWaitingTimeForMainJob, job_controller_, |
+ base::TimeDelta::FromMicroseconds(0)))); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_FALSE(job_controller_->alternative_job()); |
+ EXPECT_TRUE(job_controller_->main_job()->is_waiting()); |
+ // Since the main job did not complete successfully, the alternative proxy |
+ // server should not be marked as bad. |
+ EXPECT_TRUE(test_proxy_delegate()->alternative_proxy_server().is_valid()); |
+ EXPECT_EQ(1, test_proxy_delegate()->get_alternative_proxy_invocations()); |
+} |
+ |
} // namespace net |