Index: components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc |
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc |
index 756102e5bbc498535070b98b71211139955014c6..c52934818a7600fc66aec0a430bded8bb400812a 100644 |
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc |
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc |
@@ -273,6 +273,79 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test { |
test_context_->EnableDataReductionProxyWithSecureProxyCheckSuccess(); |
} |
+ // Build the sockets by adding appropriate mock data for |
+ // |effective_connection_types.size()| number of requests. Data for |
+ // chrome-Proxy-ect header is added to the mock data if |expect_ect_header| |
+ // is true. |reads_list|, |mock_writes| and |writes_list| should be empty, and |
+ // are owned by the caller. |
+ void BuildSocket(const std::string& response_headers, |
+ const std::string& response_body, |
+ bool expect_ect_header, |
+ const std::vector<net::EffectiveConnectionType>& |
+ effective_connection_types, |
+ std::vector<net::MockRead>* reads_list, |
+ std::vector<std::string>* mock_writes, |
+ std::vector<net::MockWrite>* writes_list) { |
+ EXPECT_LT(0u, effective_connection_types.size()); |
+ EXPECT_TRUE(reads_list->empty()); |
+ EXPECT_TRUE(mock_writes->empty()); |
+ EXPECT_TRUE(writes_list->empty()); |
+ |
+ for (size_t i = 0; i < effective_connection_types.size(); ++i) { |
+ reads_list->push_back(net::MockRead(response_headers.c_str())); |
+ reads_list->push_back(net::MockRead(response_body.c_str())); |
+ } |
+ reads_list->push_back(net::MockRead(net::SYNCHRONOUS, net::OK)); |
+ |
+ std::string prefix = std::string("GET ") |
+ .append(kTestURL) |
+ .append(" HTTP/1.1\r\n") |
+ .append("Host: ") |
+ .append(GURL(kTestURL).host()) |
+ .append( |
+ "\r\n" |
+ "Proxy-Connection: keep-alive\r\n" |
+ "User-Agent:\r\n" |
+ "Accept-Encoding: gzip, deflate\r\n" |
+ "Accept-Language: en-us,fr\r\n"); |
+ |
+ if (io_data()->test_request_options()->GetHeaderValueForTesting().empty()) { |
+ // Force regeneration of Chrome-Proxy header. |
+ io_data()->test_request_options()->SetSecureSession("123"); |
+ } |
+ |
+ EXPECT_FALSE( |
+ io_data()->test_request_options()->GetHeaderValueForTesting().empty()); |
+ |
+ std::string suffix = |
+ std::string("Chrome-Proxy: ") + |
+ io_data()->test_request_options()->GetHeaderValueForTesting() + |
+ std::string("\r\n\r\n"); |
+ |
+ mock_socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider_); |
+ |
+ for (net::EffectiveConnectionType effective_connection_type : |
+ effective_connection_types) { |
+ std::string ect_header; |
+ if (expect_ect_header) { |
+ ect_header = "chrome-proxy-ect: " + |
+ std::string(net::GetNameForEffectiveConnectionType( |
+ effective_connection_type)) + |
+ "\r\n"; |
+ } |
+ |
+ std::string mock_write = prefix + ect_header + suffix; |
+ mock_writes->push_back(mock_write); |
+ writes_list->push_back(net::MockWrite(mock_writes->back().c_str())); |
+ } |
+ |
+ EXPECT_FALSE(socket_); |
+ socket_ = base::MakeUnique<net::StaticSocketDataProvider>( |
+ reads_list->data(), reads_list->size(), writes_list->data(), |
+ writes_list->size()); |
+ mock_socket_factory_.AddSocketDataProvider(socket_.get()); |
+ } |
+ |
static void VerifyHeaders(bool expected_data_reduction_proxy_used, |
bool expected_lofi_used, |
const net::HttpRequestHeaders& headers) { |
@@ -399,6 +472,10 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test { |
"User-Agent:\r\n"); |
std::string accept_language_header("Accept-Language: en-us,fr\r\n"); |
+ std::string ect_header = "chrome-proxy-ect: " + |
+ std::string(net::GetNameForEffectiveConnectionType( |
+ net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN)) + |
+ "\r\n"; |
// Brotli is included in accept-encoding header only if the request went |
// to the network (i.e., it was not a cached response), and if data |
@@ -414,13 +491,14 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test { |
std::string("\r\n\r\n"); |
std::string mock_write = prefix_headers + accept_language_header + |
- accept_encoding_header + suffix_headers; |
+ ect_header + accept_encoding_header + |
+ suffix_headers; |
if (expect_cached || !expect_brotli) { |
// Order of headers is different if the headers were modified by data |
// reduction proxy network delegate. |
mock_write = prefix_headers + accept_encoding_header + |
- accept_language_header + suffix_headers; |
+ accept_language_header + ect_header + suffix_headers; |
} |
net::MockWrite writes[] = {net::MockWrite(mock_write.c_str())}; |
@@ -516,6 +594,7 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test { |
"www.google.com\r\nProxy-Connection: " |
"keep-alive\r\nUser-Agent:\r\nAccept-Encoding: gzip, " |
"deflate\r\nAccept-Language: en-us,fr\r\n" |
+ "chrome-proxy-ect: 4G\r\n" |
"Chrome-Proxy: " + |
io_data()->test_request_options()->GetHeaderValueForTesting() + |
(page_id_value.empty() ? "" : (", " + page_id_value)) + "\r\n\r\n"; |
@@ -549,6 +628,51 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test { |
base::RunLoop().RunUntilIdle(); |
} |
+ // Fetches a request while the effective connection type is set to |
+ // |effective_connection_type|. Verifies that the request headers include the |
+ // chrome-proxy-ect header only if |expect_ect_header| is true. The response |
+ // must be served from the cache if |expect_cached| is true. |
+ void FetchURLRequestAndVerifyECTHeader( |
+ net::EffectiveConnectionType effective_connection_type, |
+ bool expect_ect_header, |
+ bool expect_cached) { |
+ test_network_quality_estimator()->set_effective_connection_type( |
+ effective_connection_type); |
+ |
+ net::TestDelegate delegate; |
+ std::unique_ptr<net::URLRequest> request = |
+ context_.CreateRequest(GURL(kTestURL), net::IDLE, &delegate); |
+ |
+ request->Start(); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ EXPECT_EQ(140, request->received_response_content_length()); |
+ EXPECT_EQ(expect_cached, request->was_cached()); |
+ EXPECT_EQ(expect_cached, request->GetTotalSentBytes() == 0); |
+ EXPECT_EQ(expect_cached, request->GetTotalReceivedBytes() == 0); |
+ |
+ net::HttpRequestHeaders sent_request_headers; |
+ EXPECT_NE(expect_cached, |
+ request->GetFullRequestHeaders(&sent_request_headers)); |
+ |
+ if (expect_cached) { |
+ // Request headers are missing. Return since there is nothing left to |
+ // check. |
+ return; |
+ } |
+ |
+ // Verify that chrome-proxy-ect header is present in the request headers |
+ // only if |expect_ect_header| is true. |
+ std::string ect_value; |
+ EXPECT_EQ(expect_ect_header, sent_request_headers.GetHeader( |
+ chrome_proxy_ect_header(), &ect_value)); |
+ |
+ if (!expect_ect_header) |
+ return; |
+ EXPECT_EQ(net::GetNameForEffectiveConnectionType(effective_connection_type), |
+ ect_value); |
+ } |
+ |
void DelegateStageDone(int result) {} |
void NotifyNetworkDelegate(net::URLRequest* request, |
@@ -1376,6 +1500,11 @@ TEST_F(DataReductionProxyNetworkDelegateTest, |
net::ProxyRetryInfoMap proxy_retry_info; |
// Send a request and verify the page ID is 1. |
+ network_delegate()->NotifyBeforeStartTransaction( |
+ request.get(), |
+ base::Bind(&DataReductionProxyNetworkDelegateTest::DelegateStageDone, |
+ base::Unretained(this)), |
+ &headers); |
network_delegate()->NotifyBeforeSendHeaders( |
request.get(), data_reduction_proxy_info, proxy_retry_info, &headers); |
DataReductionProxyData* data = |
@@ -1388,6 +1517,11 @@ TEST_F(DataReductionProxyNetworkDelegateTest, |
nullptr); |
request->SetLoadFlags(net::LOAD_MAIN_FRAME_DEPRECATED); |
+ network_delegate()->NotifyBeforeStartTransaction( |
+ request.get(), |
+ base::Bind(&DataReductionProxyNetworkDelegateTest::DelegateStageDone, |
+ base::Unretained(this)), |
+ &headers); |
network_delegate()->NotifyBeforeSendHeaders( |
request.get(), data_reduction_proxy_info, proxy_retry_info, &headers); |
data = DataReductionProxyData::GetData(*request.get()); |
@@ -1409,6 +1543,89 @@ TEST_F(DataReductionProxyNetworkDelegateTest, |
EXPECT_EQ(1u, data->page_id().value()); |
} |
+// Test that effective connection type is correctly added to the request |
+// headers when it is enabled using field trial. The server is varying on the |
+// effective connection type (ECT). |
+TEST_F(DataReductionProxyNetworkDelegateTest, ECTHeaderEnabledWithVary) { |
+ Init(USE_SECURE_PROXY, false /* enable_brotli_globally */); |
+ |
+ std::string response_headers = |
+ "HTTP/1.1 200 OK\r\n" |
+ "Content-Length: 140\r\n" |
+ "Via: 1.1 Chrome-Compression-Proxy\r\n" |
+ "Cache-Control: max-age=1200\r\n" |
+ "Vary: chrome-proxy-ect\r\n" |
+ "x-original-content-length: 200\r\n\r\n"; |
+ |
+ int response_body_size = 140; |
+ std::string response_body(base::checked_cast<size_t>(response_body_size), |
+ ' '); |
+ |
+ std::vector<net::MockRead> reads_list; |
+ std::vector<std::string> mock_writes; |
+ std::vector<net::MockWrite> writes_list; |
+ |
+ std::vector<net::EffectiveConnectionType> effective_connection_types; |
+ effective_connection_types.push_back(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G); |
+ effective_connection_types.push_back(net::EFFECTIVE_CONNECTION_TYPE_2G); |
+ |
+ BuildSocket(response_headers, response_body, true, effective_connection_types, |
+ &reads_list, &mock_writes, &writes_list); |
+ |
+ // Add 2 socket providers since 2 requests in this test are fetched from the |
+ // network. |
+ FetchURLRequestAndVerifyECTHeader(effective_connection_types[0], true, false); |
+ |
+ // When the ECT is set to the same value, fetching the same resource should |
+ // result in a cache hit. |
+ FetchURLRequestAndVerifyECTHeader(effective_connection_types[0], true, true); |
+ |
+ // When the ECT is set to a different value, the response should not be |
+ // served from the cache. |
+ FetchURLRequestAndVerifyECTHeader(effective_connection_types[1], true, false); |
+} |
+ |
+// Test that effective connection type is correctly added to the request |
+// headers when it is enabled using field trial. The server is not varying on |
+// the effective connection type (ECT). |
+TEST_F(DataReductionProxyNetworkDelegateTest, ECTHeaderEnabledWithoutVary) { |
+ Init(USE_SECURE_PROXY, false /* enable_brotli_globally */); |
+ |
+ std::string response_headers = |
+ "HTTP/1.1 200 OK\r\n" |
+ "Content-Length: 140\r\n" |
+ "Via: 1.1 Chrome-Compression-Proxy\r\n" |
+ "Cache-Control: max-age=1200\r\n" |
+ "x-original-content-length: 200\r\n\r\n"; |
+ |
+ int response_body_size = 140; |
+ std::string response_body(base::checked_cast<size_t>(response_body_size), |
+ ' '); |
+ |
+ std::vector<net::MockRead> reads_list; |
+ std::vector<std::string> mock_writes; |
+ std::vector<net::MockWrite> writes_list; |
+ |
+ std::vector<net::EffectiveConnectionType> effective_connection_types; |
+ effective_connection_types.push_back(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G); |
+ effective_connection_types.push_back(net::EFFECTIVE_CONNECTION_TYPE_2G); |
+ |
+ BuildSocket(response_headers, response_body, true, effective_connection_types, |
+ &reads_list, &mock_writes, &writes_list); |
+ |
+ // Add 1 socket provider since 1 request in this test is fetched from the |
+ // network. |
+ FetchURLRequestAndVerifyECTHeader(effective_connection_types[0], true, false); |
+ |
+ // When the ECT is set to the same value, fetching the same resource should |
+ // result in a cache hit. |
+ FetchURLRequestAndVerifyECTHeader(effective_connection_types[0], true, true); |
+ |
+ // When the ECT is set to a different value, the response should still be |
+ // served from the cache. |
+ FetchURLRequestAndVerifyECTHeader(effective_connection_types[1], true, true); |
+} |
+ |
} // namespace |
} // namespace data_reduction_proxy |