Index: net/http/http_stream_factory_impl_unittest.cc |
diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc |
index 2448768a001fffef2a04051f1816a9518ff1ff41..c007c12887b4bc3d94f4bb0fcb091e7527f583ec 100644 |
--- a/net/http/http_stream_factory_impl_unittest.cc |
+++ b/net/http/http_stream_factory_impl_unittest.cc |
@@ -14,6 +14,7 @@ |
#include "base/run_loop.h" |
#include "net/base/port_util.h" |
#include "net/base/test_completion_callback.h" |
+#include "net/base/test_proxy_delegate.h" |
#include "net/cert/ct_policy_enforcer.h" |
#include "net/cert/mock_cert_verifier.h" |
#include "net/cert/multi_log_ct_verifier.h" |
@@ -684,25 +685,30 @@ TEST_F(HttpStreamFactoryTest, JobNotifiesProxy) { |
EXPECT_TRUE(iter != retry_info.end()); |
} |
-TEST_F(HttpStreamFactoryTest, UnreachableQuicProxyMarkedAsBad) { |
- const int mock_error[] = {ERR_PROXY_CONNECTION_FAILED, |
- ERR_NAME_NOT_RESOLVED, |
- ERR_INTERNET_DISCONNECTED, |
- ERR_ADDRESS_UNREACHABLE, |
- ERR_CONNECTION_CLOSED, |
- ERR_CONNECTION_TIMED_OUT, |
- ERR_CONNECTION_RESET, |
- ERR_CONNECTION_REFUSED, |
- ERR_CONNECTION_ABORTED, |
- ERR_TIMED_OUT, |
- ERR_TUNNEL_CONNECTION_FAILED, |
- ERR_SOCKS_CONNECTION_FAILED, |
- ERR_PROXY_CERTIFICATE_INVALID, |
- ERR_QUIC_PROTOCOL_ERROR, |
- ERR_QUIC_HANDSHAKE_FAILED, |
- ERR_SSL_PROTOCOL_ERROR, |
- ERR_MSG_TOO_BIG}; |
- for (size_t i = 0; i < arraysize(mock_error); ++i) { |
+// List of errors that are used in the tests related to QUIC proxy. |
+const int quic_proxy_test_mock_errors[] = { |
+ ERR_PROXY_CONNECTION_FAILED, |
+ ERR_NAME_NOT_RESOLVED, |
+ ERR_INTERNET_DISCONNECTED, |
+ ERR_ADDRESS_UNREACHABLE, |
+ ERR_CONNECTION_CLOSED, |
+ ERR_CONNECTION_TIMED_OUT, |
+ ERR_CONNECTION_RESET, |
+ ERR_CONNECTION_REFUSED, |
+ ERR_CONNECTION_ABORTED, |
+ ERR_TIMED_OUT, |
+ ERR_TUNNEL_CONNECTION_FAILED, |
+ ERR_SOCKS_CONNECTION_FAILED, |
+ ERR_PROXY_CERTIFICATE_INVALID, |
+ ERR_QUIC_PROTOCOL_ERROR, |
+ ERR_QUIC_HANDSHAKE_FAILED, |
+ ERR_SSL_PROTOCOL_ERROR, |
+ ERR_MSG_TOO_BIG, |
+}; |
+ |
+// Tests that a bad QUIC proxy is added to the list of bad proxies. |
+TEST_F(HttpStreamFactoryTest, QuicProxyMarkedAsBad) { |
+ for (size_t i = 0; i < arraysize(quic_proxy_test_mock_errors); ++i) { |
std::unique_ptr<ProxyService> proxy_service; |
proxy_service = |
ProxyService::CreateFixedFromPacResult("QUIC bad:99; DIRECT"); |
@@ -733,7 +739,8 @@ TEST_F(HttpStreamFactoryTest, UnreachableQuicProxyMarkedAsBad) { |
session->quic_stream_factory()->set_require_confirmation(false); |
StaticSocketDataProvider socket_data1; |
- socket_data1.set_connect_data(MockConnect(ASYNC, mock_error[i])); |
+ socket_data1.set_connect_data( |
+ MockConnect(ASYNC, quic_proxy_test_mock_errors[i])); |
socket_factory.AddSocketDataProvider(&socket_data1); |
// Second connection attempt succeeds. |
@@ -758,11 +765,11 @@ TEST_F(HttpStreamFactoryTest, UnreachableQuicProxyMarkedAsBad) { |
// The proxy that failed should now be known to the proxy_service as bad. |
const ProxyRetryInfoMap& retry_info = |
session->proxy_service()->proxy_retry_info(); |
- EXPECT_EQ(1u, retry_info.size()) << mock_error[i]; |
+ EXPECT_EQ(1u, retry_info.size()) << quic_proxy_test_mock_errors[i]; |
EXPECT_TRUE(waiter.used_proxy_info().is_direct()); |
ProxyRetryInfoMap::const_iterator iter = retry_info.find("quic://bad:99"); |
- EXPECT_TRUE(iter != retry_info.end()) << mock_error[i]; |
+ EXPECT_TRUE(iter != retry_info.end()) << quic_proxy_test_mock_errors[i]; |
} |
} |
@@ -830,8 +837,260 @@ class MockQuicData { |
std::unique_ptr<SequencedSocketData> socket_data_; |
}; |
+void SetupForQuicAlternativeProxyTest( |
+ HttpNetworkSession::Params* params, |
+ MockClientSocketFactory* socket_factory, |
+ ProxyService* proxy_service, |
+ TestProxyDelegate* test_proxy_delegate, |
+ HttpServerPropertiesImpl* http_server_properties, |
+ MockCertVerifier* cert_verifier, |
+ CTPolicyEnforcer* ct_policy_enforcer, |
+ MultiLogCTVerifier* ct_verifier, |
+ SSLConfigServiceDefaults* ssl_config_service, |
+ MockHostResolver* host_resolver, |
+ TransportSecurityState* transport_security_state, |
+ bool set_alternative_proxy_server) { |
+ params->enable_quic = true; |
+ params->quic_disable_preconnect_if_0rtt = false; |
+ params->client_socket_factory = socket_factory; |
+ params->host_resolver = host_resolver; |
+ params->transport_security_state = transport_security_state; |
+ params->proxy_service = proxy_service; |
+ params->ssl_config_service = ssl_config_service; |
+ params->http_server_properties = http_server_properties; |
+ params->cert_verifier = cert_verifier; |
+ params->ct_policy_enforcer = ct_policy_enforcer; |
+ params->cert_transparency_verifier = ct_verifier; |
+ |
+ if (set_alternative_proxy_server) { |
+ test_proxy_delegate->set_alternative_proxy_server( |
+ ProxyServer::FromPacString("QUIC badproxy:99")); |
+ } |
+ params->proxy_delegate = test_proxy_delegate; |
+} |
+ |
} // namespace |
+// Tests that a HTTPS proxy that supports QUIC alternative proxy server is |
+// marked as bad if connecting to both the default proxy and the alternative |
+// proxy is unsuccessful. |
+TEST_F(HttpStreamFactoryTest, WithQUICAlternativeProxyMarkedAsBad) { |
+ const bool set_alternative_proxy_server_values[] = { |
+ false, true, |
+ }; |
+ |
+ for (auto mock_error : quic_proxy_test_mock_errors) { |
+ for (auto set_alternative_proxy_server : |
+ set_alternative_proxy_server_values) { |
+ HttpNetworkSession::Params params; |
+ MockClientSocketFactory socket_factory; |
+ std::unique_ptr<ProxyService> proxy_service = |
+ ProxyService::CreateFixedFromPacResult( |
+ "HTTPS badproxy:99; HTTPS badfallbackproxy:98; DIRECT"); |
+ TestProxyDelegate test_proxy_delegate; |
+ HttpServerPropertiesImpl http_server_properties; |
+ MockCertVerifier cert_verifier; |
+ CTPolicyEnforcer ct_policy_enforcer; |
+ MultiLogCTVerifier ct_verifier; |
+ scoped_refptr<SSLConfigServiceDefaults> ssl_config_service( |
+ new SSLConfigServiceDefaults); |
+ MockHostResolver host_resolver; |
+ TransportSecurityState transport_security_state; |
+ SetupForQuicAlternativeProxyTest( |
+ ¶ms, &socket_factory, proxy_service.get(), &test_proxy_delegate, |
+ &http_server_properties, &cert_verifier, &ct_policy_enforcer, |
+ &ct_verifier, ssl_config_service.get(), &host_resolver, |
+ &transport_security_state, set_alternative_proxy_server); |
+ |
+ std::unique_ptr<HttpNetworkSession> session( |
+ new HttpNetworkSession(params)); |
+ |
+ // Before starting the test, verify that there are no proxies marked as |
+ // bad. |
+ ASSERT_TRUE(session->proxy_service()->proxy_retry_info().empty()) |
+ << mock_error; |
+ |
+ StaticSocketDataProvider socket_data_proxy_main_job; |
+ socket_data_proxy_main_job.set_connect_data( |
+ MockConnect(ASYNC, mock_error)); |
+ socket_factory.AddSocketDataProvider(&socket_data_proxy_main_job); |
+ |
+ StaticSocketDataProvider socket_data_proxy_alternate_job; |
+ if (set_alternative_proxy_server) { |
+ // Mock socket used by the QUIC job. |
+ socket_data_proxy_alternate_job.set_connect_data( |
+ MockConnect(ASYNC, mock_error)); |
+ socket_factory.AddSocketDataProvider(&socket_data_proxy_alternate_job); |
+ } |
+ |
+ // When retrying the job using the second proxy (badFallback:98), |
+ // alternative job must not be created. So, socket data for only the |
+ // main job is needed. |
+ StaticSocketDataProvider socket_data_proxy_main_job_2; |
+ socket_data_proxy_main_job_2.set_connect_data( |
+ MockConnect(ASYNC, mock_error)); |
+ socket_factory.AddSocketDataProvider(&socket_data_proxy_main_job_2); |
+ |
+ // First request would use DIRECT, and succeed. |
+ StaticSocketDataProvider socket_data_direct_first_request; |
+ socket_data_direct_first_request.set_connect_data(MockConnect(ASYNC, OK)); |
+ socket_factory.AddSocketDataProvider(&socket_data_direct_first_request); |
+ |
+ // Second request would use DIRECT, and succeed. |
+ StaticSocketDataProvider socket_data_direct_second_request; |
+ socket_data_direct_second_request.set_connect_data( |
+ MockConnect(ASYNC, OK)); |
+ socket_factory.AddSocketDataProvider(&socket_data_direct_second_request); |
+ |
+ // Now request a stream. It should succeed using the DIRECT. |
+ HttpRequestInfo request_info; |
+ request_info.method = "GET"; |
+ request_info.url = GURL("http://www.google.com"); |
+ |
+ SSLConfig ssl_config; |
+ StreamRequestWaiter waiter; |
+ |
+ EXPECT_EQ(set_alternative_proxy_server, |
+ test_proxy_delegate.alternative_proxy_server().is_quic()); |
+ |
+ // Start two requests. The first request should consume data from |
+ // |socket_data_proxy_main_job|, |
+ // |socket_data_proxy_alternate_job| and |
+ // |socket_data_direct_first_request|. The second request should consume |
+ // data from |socket_data_direct_second_request|. |
+ for (size_t i = 0; i < 2; ++i) { |
+ std::unique_ptr<HttpStreamRequest> request( |
+ session->http_stream_factory()->RequestStream( |
+ request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter, |
+ BoundNetLog())); |
+ waiter.WaitForStream(); |
+ |
+ // The proxy that failed should now be known to the proxy_service as |
+ // bad. |
+ const ProxyRetryInfoMap retry_info = |
+ session->proxy_service()->proxy_retry_info(); |
+ EXPECT_EQ(2u, retry_info.size()) << mock_error; |
+ |
+ // Verify that request was fetched without proxy. |
+ EXPECT_TRUE(waiter.used_proxy_info().is_direct()); |
+ |
+ EXPECT_NE(retry_info.end(), retry_info.find("https://badproxy:99")); |
+ EXPECT_NE(retry_info.end(), |
+ retry_info.find("https://badfallbackproxy:98")); |
+ |
+ // If alternative proxy server was specified, it should have been marked |
+ // as invalid so that it is not used for subsequent requests. |
+ EXPECT_FALSE(test_proxy_delegate.alternative_proxy_server().is_valid()); |
+ |
+ if (set_alternative_proxy_server) { |
+ // GetAlternativeProxy should be called only once for the first |
+ // request. |
+ EXPECT_EQ(1, test_proxy_delegate.get_alternative_proxy_invocations()); |
+ } else { |
+ // Alternative proxy server job is never started. So, ProxyDelegate is |
+ // queried once per request. |
+ EXPECT_EQ(2, test_proxy_delegate.get_alternative_proxy_invocations()); |
+ } |
+ } |
+ } |
+ } |
+} |
+ |
+// Tests that a HTTPS proxy that supports QUIC alternative proxy server is |
+// not marked as bad if only the alternative proxy server job fails. |
+TEST_F(HttpStreamFactoryTest, WithQUICAlternativeProxyNotMarkedAsBad) { |
+ for (auto mock_error : quic_proxy_test_mock_errors) { |
+ HttpNetworkSession::Params params; |
+ MockClientSocketFactory socket_factory; |
+ std::unique_ptr<ProxyService> proxy_service = |
+ ProxyService::CreateFixedFromPacResult("HTTPS badproxy:99; DIRECT"); |
+ TestProxyDelegate test_proxy_delegate; |
+ HttpServerPropertiesImpl http_server_properties; |
+ MockCertVerifier cert_verifier; |
+ CTPolicyEnforcer ct_policy_enforcer; |
+ MultiLogCTVerifier ct_verifier; |
+ |
+ scoped_refptr<SSLConfigServiceDefaults> ssl_config_service( |
+ new SSLConfigServiceDefaults); |
+ MockHostResolver host_resolver; |
+ TransportSecurityState transport_security_state; |
+ |
+ SetupForQuicAlternativeProxyTest( |
+ ¶ms, &socket_factory, proxy_service.get(), &test_proxy_delegate, |
+ &http_server_properties, &cert_verifier, &ct_policy_enforcer, |
+ &ct_verifier, ssl_config_service.get(), &host_resolver, |
+ &transport_security_state, true); |
+ |
+ HostPortPair host_port_pair("badproxy", 99); |
+ std::unique_ptr<HttpNetworkSession> session(new HttpNetworkSession(params)); |
+ |
+ // Before starting the test, verify that there are no proxies marked as |
+ // bad. |
+ ASSERT_TRUE(session->proxy_service()->proxy_retry_info().empty()) |
+ << mock_error; |
+ |
+ StaticSocketDataProvider socket_data_proxy_main_job; |
+ socket_data_proxy_main_job.set_connect_data(MockConnect(ASYNC, mock_error)); |
+ socket_factory.AddSocketDataProvider(&socket_data_proxy_main_job); |
+ |
+ SSLSocketDataProvider ssl_data(ASYNC, OK); |
+ |
+ // Next connection attempt would use HTTPS proxy, and succeed. |
+ StaticSocketDataProvider socket_data_https_first; |
+ socket_data_https_first.set_connect_data(MockConnect(ASYNC, OK)); |
+ socket_factory.AddSocketDataProvider(&socket_data_https_first); |
+ socket_factory.AddSSLSocketDataProvider(&ssl_data); |
+ |
+ // Next connection attempt would use HTTPS proxy, and succeed. |
+ StaticSocketDataProvider socket_data_https_second; |
+ socket_data_https_second.set_connect_data(MockConnect(ASYNC, OK)); |
+ socket_factory.AddSocketDataProvider(&socket_data_https_second); |
+ socket_factory.AddSSLSocketDataProvider(&ssl_data); |
+ |
+ // Now request a stream. It should succeed using the second proxy in the |
+ // list. |
+ HttpRequestInfo request_info; |
+ request_info.method = "GET"; |
+ request_info.url = GURL("http://www.google.com"); |
+ |
+ SSLConfig ssl_config; |
+ StreamRequestWaiter waiter; |
+ |
+ EXPECT_TRUE(test_proxy_delegate.alternative_proxy_server().is_quic()); |
+ |
+ // Start two requests. The first request should consume data from |
+ // |socket_data_proxy_main_job| and |socket_data_https_first|. |
+ // The second request should consume data from |socket_data_https_second|. |
+ for (size_t i = 0; i < 2; ++i) { |
+ std::unique_ptr<HttpStreamRequest> request( |
+ session->http_stream_factory()->RequestStream( |
+ request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter, |
+ BoundNetLog())); |
+ waiter.WaitForStream(); |
+ |
+ // The proxy that failed should now be known to the proxy_service as |
+ // bad. |
+ const ProxyRetryInfoMap retry_info = |
+ session->proxy_service()->proxy_retry_info(); |
+ // Proxy should not be marked as bad. |
+ EXPECT_EQ(0u, retry_info.size()) << mock_error; |
+ // Verify that request was fetched using proxy. |
+ EXPECT_TRUE(waiter.used_proxy_info().is_https()); |
+ EXPECT_TRUE(host_port_pair.Equals( |
+ waiter.used_proxy_info().proxy_server().host_port_pair())); |
+ net::ProxyServer proxy_server; |
+ |
+ // Alternative proxy server should be marked as invalid so that it is |
+ // not used for subsequent requests. |
+ EXPECT_FALSE(test_proxy_delegate.alternative_proxy_server().is_quic()); |
+ |
+ // GetAlternativeProxy should be called only once per request. |
+ EXPECT_EQ(static_cast<int>(i + 1), |
+ test_proxy_delegate.get_alternative_proxy_invocations()); |
+ } |
+ } |
+} |
+ |
TEST_F(HttpStreamFactoryTest, QuicLossyProxyMarkedAsBad) { |
// Checks if a |
std::unique_ptr<ProxyService> proxy_service; |