Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(350)

Unified Diff: net/http/http_stream_factory_impl_unittest.cc

Issue 2260623002: Race TCP connection to proxies with QUIC connections (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed Cherie's comments Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..34e9f1028c1adf0cc25af5848d3a5e453337932e 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,246 @@ 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(
+ &params, &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());
+ }
+ }
+ }
+}
+
+// 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(
+ &params, &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());
+ }
+ }
+}
+
TEST_F(HttpStreamFactoryTest, QuicLossyProxyMarkedAsBad) {
// Checks if a
std::unique_ptr<ProxyService> proxy_service;

Powered by Google App Engine
This is Rietveld 408576698