| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h" |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <string> |
| #include <vector> |
| |
| #include "base/base64.h" |
| #include "base/command_line.h" |
| #include "base/macros.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/metrics/field_trial.h" |
| #include "base/run_loop.h" |
| #include "base/test/histogram_tester.h" |
| #include "base/test/mock_entropy_provider.h" |
| #include "base/time/time.h" |
| #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h" |
| #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h" |
| #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h" |
| #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h" |
| #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h" |
| #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h" |
| #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h" |
| #include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h" |
| #include "components/data_reduction_proxy/core/common/data_reduction_proxy_server.h" |
| #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h" |
| #include "components/data_reduction_proxy/proto/client_config.pb.h" |
| #include "net/base/network_change_notifier.h" |
| #include "net/http/http_request_headers.h" |
| #include "net/http/http_response_headers.h" |
| #include "net/proxy/proxy_server.h" |
| #include "net/socket/socket_test_util.h" |
| #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" |
| #include "net/url_request/url_request_context_storage.h" |
| #include "net/url_request/url_request_test_util.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/gurl.h" |
| |
| namespace { |
| |
| // The following values should match those in |
| // DataReductionProxyConfigServiceClientTest.config_: |
| const char kSuccessOrigin[] = "https://origin.net:443"; |
| const char kSuccessFallback[] = "fallback.net:80"; |
| const char kSuccessSessionKey[] = "SecretSessionKey"; |
| |
| // The following values should match those in |
| // DataReductionProxyConfigServiceClientTest.previous_config_: |
| const char kOldSuccessOrigin[] = "https://old.origin.net:443"; |
| const char kOldSuccessFallback[] = "old.fallback.net:80"; |
| const char kOldSuccessSessionKey[] = "OldSecretSessionKey"; |
| |
| // The following values should match those in |
| // DataReductionProxyConfigServiceClientTest.loaded_config_: |
| const char kPersistedOrigin[] = "https://persisted.net:443"; |
| const char kPersistedFallback[] = "persisted.net:80"; |
| const char kPersistedSessionKey[] = "PersistedSessionKey"; |
| |
| // Duration (in seconds) after which the config should be refreshed. |
| const int kConfigRefreshDurationSeconds = 600; |
| |
| #if defined(OS_ANDROID) |
| // Maximum duration to wait before fetching the config, while the application |
| // is in background. |
| const uint32_t kMaxBackgroundFetchIntervalSeconds = 6 * 60 * 60; // 6 hours. |
| #endif |
| |
| } // namespace |
| |
| namespace data_reduction_proxy { |
| |
| namespace { |
| |
| // Creates a new ClientConfig from the given parameters. |
| ClientConfig CreateConfig(const std::string& session_key, |
| int64_t expire_duration_seconds, |
| int64_t expire_duration_nanoseconds, |
| ProxyServer_ProxyScheme primary_scheme, |
| const std::string& primary_host, |
| int primary_port, |
| const ProxyServer_ProxyType& primary_proxy_type, |
| ProxyServer_ProxyScheme secondary_scheme, |
| const std::string& secondary_host, |
| int secondary_port, |
| const ProxyServer_ProxyType& secondary_proxy_type, |
| float reporting_fraction) { |
| ClientConfig config; |
| |
| config.set_session_key(session_key); |
| config.mutable_refresh_duration()->set_seconds(expire_duration_seconds); |
| config.mutable_refresh_duration()->set_nanos(expire_duration_nanoseconds); |
| |
| // Leave the pageload_metrics_config empty when |reporting_fraction| is not |
| // inclusively between zero and one. |
| if (reporting_fraction >= 0.0f && reporting_fraction <= 1.0f) { |
| config.mutable_pageload_metrics_config()->set_reporting_fraction( |
| reporting_fraction); |
| } |
| ProxyServer* primary_proxy = |
| config.mutable_proxy_config()->add_http_proxy_servers(); |
| primary_proxy->set_scheme(primary_scheme); |
| primary_proxy->set_host(primary_host); |
| primary_proxy->set_port(primary_port); |
| primary_proxy->set_type(primary_proxy_type); |
| |
| ProxyServer* secondary_proxy = |
| config.mutable_proxy_config()->add_http_proxy_servers(); |
| secondary_proxy->set_scheme(secondary_scheme); |
| secondary_proxy->set_host(secondary_host); |
| secondary_proxy->set_port(secondary_port); |
| secondary_proxy->set_type(secondary_proxy_type); |
| |
| return config; |
| } |
| |
| // Takes |config| and returns the base64 encoding of its serialized byte stream. |
| std::string EncodeConfig(const ClientConfig& config) { |
| std::string config_data; |
| std::string encoded_data; |
| EXPECT_TRUE(config.SerializeToString(&config_data)); |
| base::Base64Encode(config_data, &encoded_data); |
| return encoded_data; |
| } |
| |
| } // namespace |
| |
| class DataReductionProxyConfigServiceClientTest : public testing::Test { |
| protected: |
| DataReductionProxyConfigServiceClientTest() { |
| context_.reset(new net::TestURLRequestContext(true)); |
| context_storage_.reset(new net::URLRequestContextStorage(context_.get())); |
| mock_socket_factory_.reset(new net::MockClientSocketFactory()); |
| } |
| |
| void Init(bool use_mock_client_socket_factory) { |
| if (!use_mock_client_socket_factory) |
| mock_socket_factory_.reset(nullptr); |
| test_context_ = |
| DataReductionProxyTestContext::Builder() |
| .WithURLRequestContext(context_.get()) |
| .WithMockClientSocketFactory(mock_socket_factory_.get()) |
| .WithMockRequestOptions() |
| .WithTestConfigClient() |
| .SkipSettingsInitialization() |
| .Build(); |
| |
| context_->set_client_socket_factory(mock_socket_factory_.get()); |
| test_context_->AttachToURLRequestContext(context_storage_.get()); |
| delegate_ = test_context_->io_data()->CreateProxyDelegate(); |
| context_->set_proxy_delegate(delegate_.get()); |
| |
| context_->Init(); |
| |
| test_context_->InitSettings(); |
| ResetBackoffEntryReleaseTime(); |
| test_context_->test_config_client()->SetNow(base::Time::UnixEpoch()); |
| test_context_->test_config_client()->SetEnabled(true); |
| test_context_->test_config_client()->SetConfigServiceURL( |
| GURL("http://configservice.com")); |
| |
| ASSERT_NE(nullptr, context_->network_delegate()); |
| // Set up the various test ClientConfigs. |
| ClientConfig config = |
| CreateConfig(kSuccessSessionKey, kConfigRefreshDurationSeconds, 0, |
| ProxyServer_ProxyScheme_HTTPS, "origin.net", 443, |
| ProxyServer::CORE, ProxyServer_ProxyScheme_HTTP, |
| "fallback.net", 80, ProxyServer::UNSPECIFIED_TYPE, 0.5f); |
| config.SerializeToString(&config_); |
| encoded_config_ = EncodeConfig(config); |
| |
| ClientConfig previous_config = CreateConfig( |
| kOldSuccessSessionKey, kConfigRefreshDurationSeconds, 0, |
| ProxyServer_ProxyScheme_HTTPS, "old.origin.net", 443, ProxyServer::CORE, |
| ProxyServer_ProxyScheme_HTTP, "old.fallback.net", 80, |
| ProxyServer::UNSPECIFIED_TYPE, 0.0f); |
| previous_config.SerializeToString(&previous_config_); |
| |
| ClientConfig persisted = |
| CreateConfig(kPersistedSessionKey, kConfigRefreshDurationSeconds, 0, |
| ProxyServer_ProxyScheme_HTTPS, "persisted.net", 443, |
| ProxyServer::CORE, ProxyServer_ProxyScheme_HTTP, |
| "persisted.net", 80, ProxyServer::UNSPECIFIED_TYPE, 0.0f); |
| loaded_config_ = EncodeConfig(persisted); |
| |
| ClientConfig zero_reporting_fraction_config = |
| CreateConfig(kSuccessSessionKey, kConfigRefreshDurationSeconds, 0, |
| ProxyServer_ProxyScheme_HTTPS, "origin.net", 443, |
| ProxyServer::CORE, ProxyServer_ProxyScheme_HTTP, |
| "origin.net", 0, ProxyServer::UNSPECIFIED_TYPE, 0.0f); |
| zero_reporting_fraction_encoded_config_ = |
| EncodeConfig(zero_reporting_fraction_config); |
| |
| ClientConfig one_reporting_fraction_config = |
| CreateConfig(kSuccessSessionKey, kConfigRefreshDurationSeconds, 0, |
| ProxyServer_ProxyScheme_HTTPS, "", 443, ProxyServer::CORE, |
| ProxyServer_ProxyScheme_HTTP, "", 0, |
| ProxyServer::UNSPECIFIED_TYPE, 1.0f); |
| one_reporting_fraction_encoded_config_ = |
| EncodeConfig(one_reporting_fraction_config); |
| |
| // Passing in -1.0f as the reporting fraction causes the |
| // |empty_reporting_fraction_config| to have no pageload_metrics_config() |
| // set. |
| ClientConfig empty_reporting_fraction_config = |
| CreateConfig(kSuccessSessionKey, kConfigRefreshDurationSeconds, 0, |
| ProxyServer_ProxyScheme_HTTPS, "origin.net", 443, |
| ProxyServer::CORE, ProxyServer_ProxyScheme_HTTP, |
| "origin.net", 0, ProxyServer::UNSPECIFIED_TYPE, -1.0f); |
| empty_reporting_fraction_encoded_config_ = |
| EncodeConfig(empty_reporting_fraction_config); |
| |
| ClientConfig half_reporting_fraction_config = |
| CreateConfig(kSuccessSessionKey, kConfigRefreshDurationSeconds, 0, |
| ProxyServer_ProxyScheme_HTTPS, "origin.net", 443, |
| ProxyServer::CORE, ProxyServer_ProxyScheme_HTTP, |
| "origin.net", 0, ProxyServer::UNSPECIFIED_TYPE, 0.5f); |
| half_reporting_fraction_encoded_config_ = |
| EncodeConfig(half_reporting_fraction_config); |
| |
| success_reads_[0] = net::MockRead("HTTP/1.1 200 OK\r\n\r\n"); |
| success_reads_[1] = |
| net::MockRead(net::ASYNC, config_.c_str(), config_.length()); |
| success_reads_[2] = net::MockRead(net::SYNCHRONOUS, net::OK); |
| |
| previous_success_reads_[0] = net::MockRead("HTTP/1.1 200 OK\r\n\r\n"); |
| previous_success_reads_[1] = net::MockRead( |
| net::ASYNC, previous_config_.c_str(), previous_config_.length()); |
| previous_success_reads_[2] = net::MockRead(net::SYNCHRONOUS, net::OK); |
| |
| not_found_reads_[0] = net::MockRead("HTTP/1.1 404 Not found\r\n\r\n"); |
| not_found_reads_[1] = net::MockRead(net::SYNCHRONOUS, net::OK); |
| } |
| |
| void SetDataReductionProxyEnabled(bool enabled, bool secure_proxy_allowed) { |
| test_context_->config()->UpdateConfigForTesting(enabled, |
| secure_proxy_allowed, true); |
| } |
| |
| void ResetBackoffEntryReleaseTime() { |
| config_client()->SetCustomReleaseTime(base::TimeTicks::UnixEpoch()); |
| } |
| |
| void VerifyRemoteSuccess(bool expect_secure_proxies) { |
| std::vector<DataReductionProxyServer> expected_http_proxies; |
| if (expect_secure_proxies) { |
| expected_http_proxies.push_back(DataReductionProxyServer( |
| net::ProxyServer::FromURI(kSuccessOrigin, |
| net::ProxyServer::SCHEME_HTTP), |
| ProxyServer::CORE)); |
| } |
| expected_http_proxies.push_back(DataReductionProxyServer( |
| net::ProxyServer::FromURI(kSuccessFallback, |
| net::ProxyServer::SCHEME_HTTP), |
| ProxyServer::UNSPECIFIED_TYPE)); |
| |
| EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds), |
| config_client()->GetDelay()); |
| EXPECT_EQ(DataReductionProxyServer::ConvertToNetProxyServers( |
| expected_http_proxies), |
| GetConfiguredProxiesForHttp()); |
| EXPECT_EQ(kSuccessSessionKey, request_options()->GetSecureSession()); |
| // The config should be persisted on the pref. |
| EXPECT_EQ(encoded_config(), persisted_config()); |
| EXPECT_EQ(0.5f, pingback_reporting_fraction()); |
| |
| // Verify that the data reduction proxy servers are correctly set. |
| // The first proxy must have type CORE. The second proxy must have type |
| // UNSPECIFIED_TYPE since these are the types specified in the encoded |
| // configs. |
| ASSERT_EQ( |
| 2U, test_context_->mutable_config_values()->proxies_for_http().size()); |
| EXPECT_EQ(ProxyServer::CORE, test_context_->mutable_config_values() |
| ->proxies_for_http() |
| .at(0) |
| .GetProxyTypeForTesting()); |
| EXPECT_EQ(ProxyServer::UNSPECIFIED_TYPE, |
| test_context_->mutable_config_values() |
| ->proxies_for_http() |
| .at(1) |
| .GetProxyTypeForTesting()); |
| } |
| |
| void VerifyRemoteSuccessWithOldConfig() { |
| std::vector<DataReductionProxyServer> expected_http_proxies; |
| expected_http_proxies.push_back(DataReductionProxyServer( |
| net::ProxyServer::FromURI(kOldSuccessOrigin, |
| net::ProxyServer::SCHEME_HTTP), |
| ProxyServer::CORE)); |
| expected_http_proxies.push_back(DataReductionProxyServer( |
| net::ProxyServer::FromURI(kOldSuccessFallback, |
| net::ProxyServer::SCHEME_HTTP), |
| ProxyServer::UNSPECIFIED_TYPE)); |
| |
| EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds), |
| config_client()->GetDelay()); |
| EXPECT_EQ(DataReductionProxyServer::ConvertToNetProxyServers( |
| expected_http_proxies), |
| GetConfiguredProxiesForHttp()); |
| EXPECT_EQ(kOldSuccessSessionKey, request_options()->GetSecureSession()); |
| |
| // Verify that the data reduction proxy servers are correctly set. |
| // The first proxy must have type CORE. The second proxy must have type |
| // UNSPECIFIED_TYPE since these are the types specified in the encoded |
| // configs. |
| ASSERT_EQ( |
| 2U, test_context_->mutable_config_values()->proxies_for_http().size()); |
| EXPECT_EQ(ProxyServer::CORE, test_context_->mutable_config_values() |
| ->proxies_for_http() |
| .at(0) |
| .GetProxyTypeForTesting()); |
| EXPECT_EQ(ProxyServer::UNSPECIFIED_TYPE, |
| test_context_->mutable_config_values() |
| ->proxies_for_http() |
| .at(1) |
| .GetProxyTypeForTesting()); |
| } |
| |
| void VerifySuccessWithLoadedConfig(bool expect_secure_proxies) { |
| std::vector<DataReductionProxyServer> expected_http_proxies; |
| if (expect_secure_proxies) { |
| expected_http_proxies.push_back(DataReductionProxyServer( |
| net::ProxyServer::FromURI(kPersistedOrigin, |
| net::ProxyServer::SCHEME_HTTP), |
| ProxyServer::CORE)); |
| } |
| expected_http_proxies.push_back(DataReductionProxyServer( |
| net::ProxyServer::FromURI(kPersistedFallback, |
| net::ProxyServer::SCHEME_HTTP), |
| ProxyServer::UNSPECIFIED_TYPE)); |
| EXPECT_EQ(DataReductionProxyServer::ConvertToNetProxyServers( |
| expected_http_proxies), |
| GetConfiguredProxiesForHttp()); |
| EXPECT_EQ(kPersistedSessionKey, request_options()->GetSecureSession()); |
| |
| // Verify that the data reduction proxy servers are correctly set. |
| // The first proxy must have type CORE. The second proxy must have type |
| // UNSPECIFIED_TYPE since these are the types specified in the encoded |
| // configs. |
| ASSERT_EQ( |
| 2U, test_context_->mutable_config_values()->proxies_for_http().size()); |
| EXPECT_EQ(ProxyServer::CORE, test_context_->mutable_config_values() |
| ->proxies_for_http() |
| .at(0) |
| .GetProxyTypeForTesting()); |
| EXPECT_EQ(ProxyServer::UNSPECIFIED_TYPE, |
| test_context_->mutable_config_values() |
| ->proxies_for_http() |
| .at(1) |
| .GetProxyTypeForTesting()); |
| } |
| |
| TestDataReductionProxyConfigServiceClient* config_client() { |
| return test_context_->test_config_client(); |
| } |
| |
| DataReductionProxyConfigurator* configurator() { |
| return test_context_->configurator(); |
| } |
| |
| TestDataReductionProxyConfig* config() { return test_context_->config(); } |
| |
| MockDataReductionProxyRequestOptions* request_options() { |
| return test_context_->mock_request_options(); |
| } |
| |
| std::vector<net::ProxyServer> GetConfiguredProxiesForHttp() const { |
| return test_context_->GetConfiguredProxiesForHttp(); |
| } |
| |
| float pingback_reporting_fraction() const { |
| return test_context_->io_data()->pingback_reporting_fraction(); |
| } |
| |
| void RunUntilIdle() { |
| test_context_->RunUntilIdle(); |
| } |
| |
| void AddMockSuccess() { |
| socket_data_providers_.push_back( |
| (base::MakeUnique<net::StaticSocketDataProvider>( |
| success_reads_, arraysize(success_reads_), nullptr, 0))); |
| mock_socket_factory_->AddSocketDataProvider( |
| socket_data_providers_.back().get()); |
| } |
| |
| void AddMockPreviousSuccess() { |
| socket_data_providers_.push_back( |
| (base::MakeUnique<net::StaticSocketDataProvider>( |
| previous_success_reads_, arraysize(previous_success_reads_), |
| nullptr, 0))); |
| mock_socket_factory_->AddSocketDataProvider( |
| socket_data_providers_.back().get()); |
| } |
| |
| void AddMockFailure() { |
| socket_data_providers_.push_back( |
| (base::MakeUnique<net::StaticSocketDataProvider>( |
| not_found_reads_, arraysize(not_found_reads_), nullptr, 0))); |
| mock_socket_factory_->AddSocketDataProvider( |
| socket_data_providers_.back().get()); |
| } |
| |
| std::string persisted_config() const { |
| return test_context_->pref_service()->GetString( |
| prefs::kDataReductionProxyConfig); |
| } |
| |
| base::Time persisted_config_retrieval_time() const { |
| return base::Time() + |
| base::TimeDelta::FromMicroseconds( |
| test_context_->pref_service()->GetInt64( |
| prefs::kDataReductionProxyLastConfigRetrievalTime)); |
| } |
| |
| const std::string& success_response() const { return config_; } |
| |
| const std::string& encoded_config() const { return encoded_config_; } |
| |
| const std::string& previous_success_response() const { |
| return previous_config_; |
| } |
| const std::string& empty_reporting_fraction_encoded_config() const { |
| return empty_reporting_fraction_encoded_config_; |
| } |
| const std::string& one_reporting_fraction_encoded_config() const { |
| return one_reporting_fraction_encoded_config_; |
| } |
| const std::string& zero_reporting_fraction_encoded_config() const { |
| return zero_reporting_fraction_encoded_config_; |
| } |
| const std::string& half_reporting_fraction_encoded_config() const { |
| return half_reporting_fraction_encoded_config_; |
| } |
| |
| bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) const { |
| return delegate_->IsTrustedSpdyProxy(proxy_server); |
| } |
| |
| const std::string& loaded_config() const { return loaded_config_; } |
| |
| net::TestURLRequestContext* test_url_request_context() const { |
| return context_.get(); |
| } |
| |
| private: |
| base::MessageLoopForIO message_loop_; |
| std::unique_ptr<net::TestURLRequestContext> context_; |
| std::unique_ptr<net::MockClientSocketFactory> mock_socket_factory_; |
| |
| protected: |
| std::unique_ptr<DataReductionProxyTestContext> test_context_; |
| |
| private: |
| std::unique_ptr<DataReductionProxyRequestOptions> request_options_; |
| |
| std::unique_ptr<DataReductionProxyDelegate> delegate_; |
| |
| // A configuration from the current remote request. The encoded version is |
| // also stored. |
| std::string config_; |
| std::string encoded_config_; |
| |
| // A configuration from a previous remote request. |
| std::string previous_config_; |
| |
| // An encoded config that represents a previously saved configuration. |
| std::string loaded_config_; |
| |
| // A configuration where the pingback reporting fraction is not set. |
| std::string empty_reporting_fraction_encoded_config_; |
| |
| // A configuration where the pingback reporting fraction is set to 1.0f. |
| std::string one_reporting_fraction_encoded_config_; |
| |
| // A configuration where the pingback reporting fraction is set to 0.0f. |
| std::string zero_reporting_fraction_encoded_config_; |
| |
| // A configuration where the pingback reporting fraction is set to 0.5f. |
| std::string half_reporting_fraction_encoded_config_; |
| |
| // Mock socket data. |
| std::vector<std::unique_ptr<net::SocketDataProvider>> socket_data_providers_; |
| |
| // Mock socket reads. |
| net::MockRead success_reads_[3]; |
| net::MockRead previous_success_reads_[3]; |
| net::MockRead not_found_reads_[2]; |
| |
| std::unique_ptr<net::URLRequestContextStorage> context_storage_; |
| |
| DISALLOW_COPY_AND_ASSIGN(DataReductionProxyConfigServiceClientTest); |
| }; |
| |
| // Tests that backoff values increases with every time config cannot be fetched. |
| TEST_F(DataReductionProxyConfigServiceClientTest, EnsureBackoff) { |
| Init(true); |
| // Use a local/static config. |
| base::HistogramTester histogram_tester; |
| AddMockFailure(); |
| AddMockFailure(); |
| |
| EXPECT_EQ(0, config_client()->failed_attempts_before_success()); |
| |
| SetDataReductionProxyEnabled(true, true); |
| EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp()); |
| |
| // First attempt should be unsuccessful. |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp()); |
| EXPECT_EQ(base::TimeDelta::FromSeconds(20), config_client()->GetDelay()); |
| |
| #if defined(OS_ANDROID) |
| EXPECT_FALSE(config_client()->foreground_fetch_pending()); |
| #endif |
| |
| // Second attempt should be unsuccessful and backoff time should increase. |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp()); |
| EXPECT_EQ(base::TimeDelta::FromSeconds(40), config_client()->GetDelay()); |
| EXPECT_TRUE(persisted_config().empty()); |
| EXPECT_TRUE(persisted_config_retrieval_time().is_null()); |
| |
| #if defined(OS_ANDROID) |
| EXPECT_FALSE(config_client()->foreground_fetch_pending()); |
| #endif |
| |
| EXPECT_EQ(2, config_client()->failed_attempts_before_success()); |
| histogram_tester.ExpectTotalCount( |
| "DataReductionProxy.ConfigService.FetchFailedAttemptsBeforeSuccess", 0); |
| } |
| |
| // Tests that the config is read successfully on the first attempt. |
| TEST_F(DataReductionProxyConfigServiceClientTest, RemoteConfigSuccess) { |
| Init(true); |
| AddMockSuccess(); |
| SetDataReductionProxyEnabled(true, true); |
| EXPECT_FALSE(configurator()->GetProxyConfig().is_valid()); |
| EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp()); |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| VerifyRemoteSuccess(true); |
| EXPECT_TRUE(configurator()->GetProxyConfig().is_valid()); |
| #if defined(OS_ANDROID) |
| EXPECT_FALSE(config_client()->foreground_fetch_pending()); |
| #endif |
| } |
| |
| // Tests that the config is read successfully on the first attempt, and secure |
| // proxies are not used if the secure check failed. |
| TEST_F(DataReductionProxyConfigServiceClientTest, |
| RemoteConfigSuccessWithSecureCheckFail) { |
| Init(true); |
| AddMockSuccess(); |
| SetDataReductionProxyEnabled(true, false); |
| EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp()); |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| VerifyRemoteSuccess(false); |
| #if defined(OS_ANDROID) |
| EXPECT_FALSE(config_client()->foreground_fetch_pending()); |
| #endif |
| } |
| |
| // Tests that the config is read successfully on the first attempt, and secure |
| // proxies are not used if the secure proxy check fails later after some time. |
| TEST_F(DataReductionProxyConfigServiceClientTest, |
| RemoteConfigSuccessWithDelayedSecureCheckFail) { |
| Init(true); |
| AddMockSuccess(); |
| SetDataReductionProxyEnabled(true, true); |
| EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp()); |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| VerifyRemoteSuccess(true); |
| #if defined(OS_ANDROID) |
| EXPECT_FALSE(config_client()->foreground_fetch_pending()); |
| #endif |
| |
| std::vector<DataReductionProxyServer> http_proxies; |
| http_proxies.push_back(DataReductionProxyServer( |
| net::ProxyServer::FromURI(kSuccessOrigin, net::ProxyServer::SCHEME_HTTP), |
| ProxyServer::CORE)); |
| http_proxies.push_back(DataReductionProxyServer( |
| net::ProxyServer::FromURI(kSuccessFallback, |
| net::ProxyServer::SCHEME_HTTP), |
| ProxyServer::CORE)); |
| |
| // Secure check failed. |
| configurator()->Enable(true /* secure_transport_restricted */, false, |
| http_proxies); |
| VerifyRemoteSuccess(false); |
| } |
| |
| // Tests that the config is read successfully on the second attempt. |
| TEST_F(DataReductionProxyConfigServiceClientTest, |
| RemoteConfigSuccessAfterFailure) { |
| Init(true); |
| base::HistogramTester histogram_tester; |
| |
| AddMockFailure(); |
| AddMockSuccess(); |
| |
| EXPECT_EQ(0, config_client()->failed_attempts_before_success()); |
| |
| SetDataReductionProxyEnabled(true, true); |
| EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp()); |
| |
| // First attempt should be unsuccessful. |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| EXPECT_EQ(1, config_client()->failed_attempts_before_success()); |
| EXPECT_EQ(base::TimeDelta::FromSeconds(20), config_client()->GetDelay()); |
| EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp()); |
| EXPECT_TRUE(request_options()->GetSecureSession().empty()); |
| |
| // Second attempt should be successful. |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| VerifyRemoteSuccess(true); |
| EXPECT_EQ(0, config_client()->failed_attempts_before_success()); |
| |
| histogram_tester.ExpectUniqueSample( |
| "DataReductionProxy.ConfigService.FetchFailedAttemptsBeforeSuccess", 1, |
| 1); |
| } |
| |
| // Verifies that the config is fetched successfully after IP address changes. |
| TEST_F(DataReductionProxyConfigServiceClientTest, OnIPAddressChange) { |
| Init(true); |
| const struct { |
| bool secure_proxies_allowed; |
| } tests[] = { |
| { |
| true, |
| }, |
| { |
| false, |
| }, |
| }; |
| |
| for (size_t i = 0; i < arraysize(tests); ++i) { |
| SetDataReductionProxyEnabled(true, tests[i].secure_proxies_allowed); |
| config_client()->RetrieveConfig(); |
| |
| const int kFailureCount = 5; |
| |
| std::vector<std::unique_ptr<net::SocketDataProvider>> socket_data_providers; |
| for (int i = 0; i < kFailureCount; ++i) { |
| AddMockFailure(); |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| } |
| |
| // Verify that the backoff increased exponentially. |
| EXPECT_EQ(base::TimeDelta::FromSeconds(320), |
| config_client()->GetDelay()); // 320 = 20 * 2^(5-1) |
| EXPECT_EQ(kFailureCount, config_client()->GetBackoffErrorCount()); |
| |
| // IP address change should reset. |
| config_client()->OnIPAddressChanged(); |
| EXPECT_EQ(0, config_client()->GetBackoffErrorCount()); |
| EXPECT_EQ(i == 0, persisted_config().empty()); |
| EXPECT_EQ(i == 0, persisted_config_retrieval_time().is_null()); |
| ResetBackoffEntryReleaseTime(); |
| |
| // Fetching the config should be successful. |
| AddMockSuccess(); |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| VerifyRemoteSuccess(tests[i].secure_proxies_allowed); |
| |
| // Disable in preparation for the next test. |
| configurator()->Disable(); |
| } |
| } |
| |
| // Verifies that the config is fetched successfully after IP address changes, |
| // and secure proxies are not used if the secure proxy check fails later after |
| // some time. |
| TEST_F(DataReductionProxyConfigServiceClientTest, |
| OnIPAddressChangeDelayedSecureProxyCheckFail) { |
| Init(true); |
| |
| SetDataReductionProxyEnabled(true, true); |
| config_client()->RetrieveConfig(); |
| |
| const int kFailureCount = 5; |
| |
| std::vector<std::unique_ptr<net::SocketDataProvider>> socket_data_providers; |
| for (int i = 0; i < kFailureCount; ++i) { |
| AddMockFailure(); |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| } |
| |
| // Verify that the backoff increased exponentially. |
| EXPECT_EQ(base::TimeDelta::FromSeconds(320), |
| config_client()->GetDelay()); // 320 = 20 * 2^(5-1) |
| EXPECT_EQ(kFailureCount, config_client()->GetBackoffErrorCount()); |
| |
| // IP address change should reset. |
| config_client()->OnIPAddressChanged(); |
| EXPECT_EQ(0, config_client()->GetBackoffErrorCount()); |
| EXPECT_TRUE(persisted_config().empty()); |
| EXPECT_TRUE(persisted_config_retrieval_time().is_null()); |
| ResetBackoffEntryReleaseTime(); |
| |
| // Fetching the config should be successful. |
| AddMockSuccess(); |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| VerifyRemoteSuccess(true); |
| |
| std::vector<DataReductionProxyServer> http_proxies; |
| http_proxies.push_back(DataReductionProxyServer( |
| net::ProxyServer::FromURI(kSuccessOrigin, net::ProxyServer::SCHEME_HTTP), |
| ProxyServer::CORE)); |
| http_proxies.push_back(DataReductionProxyServer( |
| net::ProxyServer::FromURI(kSuccessFallback, |
| net::ProxyServer::SCHEME_HTTP), |
| ProxyServer::CORE)); |
| |
| // Secure check failed. |
| configurator()->Enable(true /* secure_transport_restricted */, false, |
| http_proxies); |
| VerifyRemoteSuccess(false); |
| } |
| |
| // Verifies that fetching the remote config has no effect if the config client |
| // is disabled. |
| TEST_F(DataReductionProxyConfigServiceClientTest, OnIPAddressChangeDisabled) { |
| Init(true); |
| config_client()->SetEnabled(false); |
| SetDataReductionProxyEnabled(true, true); |
| config_client()->RetrieveConfig(); |
| EXPECT_TRUE(request_options()->GetSecureSession().empty()); |
| |
| enum : int { kFailureCount = 5 }; |
| |
| for (int i = 0; i < kFailureCount; ++i) { |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| EXPECT_TRUE(request_options()->GetSecureSession().empty()); |
| } |
| |
| EXPECT_EQ(0, config_client()->GetBackoffErrorCount()); |
| config_client()->OnIPAddressChanged(); |
| EXPECT_EQ(0, config_client()->GetBackoffErrorCount()); |
| |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| |
| EXPECT_TRUE(request_options()->GetSecureSession().empty()); |
| } |
| |
| // Verifies the correctness of AuthFailure when the session key in the request |
| // headers matches the currrent session key. |
| TEST_F(DataReductionProxyConfigServiceClientTest, AuthFailure) { |
| Init(true); |
| net::HttpRequestHeaders request_headers; |
| request_headers.SetHeader( |
| "chrome-proxy", "something=something_else, s=" + |
| std::string(kOldSuccessSessionKey) + ", key=value"); |
| |
| base::HistogramTester histogram_tester; |
| AddMockPreviousSuccess(); |
| AddMockSuccess(); |
| AddMockPreviousSuccess(); |
| |
| SetDataReductionProxyEnabled(true, true); |
| EXPECT_FALSE(configurator()->GetProxyConfig().is_valid()); |
| histogram_tester.ExpectTotalCount( |
| "DataReductionProxy.ConfigService.AuthExpired", 0); |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| // First remote config should be fetched. |
| VerifyRemoteSuccessWithOldConfig(); |
| EXPECT_TRUE(configurator()->GetProxyConfig().is_valid()); |
| EXPECT_EQ(kOldSuccessSessionKey, request_options()->GetSecureSession()); |
| EXPECT_EQ(0, config_client()->GetBackoffErrorCount()); |
| histogram_tester.ExpectUniqueSample( |
| "DataReductionProxy.ConfigService.AuthExpired", false, 1); |
| |
| // Trigger an auth failure. |
| scoped_refptr<net::HttpResponseHeaders> parsed(new net::HttpResponseHeaders( |
| "HTTP/1.1 407 Proxy Authentication Required\n")); |
| net::ProxyServer origin = net::ProxyServer::FromURI( |
| kOldSuccessOrigin, net::ProxyServer::SCHEME_HTTP); |
| // Calling ShouldRetryDueToAuthFailure should trigger fetching of remote |
| // config. |
| net::LoadTimingInfo load_timing_info; |
| load_timing_info.request_start = |
| base::TimeTicks::Now() - base::TimeDelta::FromSeconds(1); |
| load_timing_info.send_start = load_timing_info.request_start; |
| EXPECT_TRUE(config_client()->ShouldRetryDueToAuthFailure( |
| request_headers, parsed.get(), origin, load_timing_info)); |
| EXPECT_EQ(1, config_client()->GetBackoffErrorCount()); |
| EXPECT_FALSE(configurator()->GetProxyConfig().is_valid()); |
| |
| // Persisted config on pref should be cleared. |
| EXPECT_TRUE(persisted_config().empty()); |
| histogram_tester.ExpectBucketCount( |
| "DataReductionProxy.ConfigService.AuthExpired", false, 1); |
| histogram_tester.ExpectBucketCount( |
| "DataReductionProxy.ConfigService.AuthExpired", true, 1); |
| RunUntilIdle(); |
| histogram_tester.ExpectTotalCount( |
| "DataReductionProxy.ConfigService.AuthFailure.LatencyPenalty", 1); |
| |
| // Second remote config should be fetched. |
| VerifyRemoteSuccess(true); |
| |
| // Trigger a second auth failure. |
| origin = |
| net::ProxyServer::FromURI(kSuccessOrigin, net::ProxyServer::SCHEME_HTTP); |
| |
| EXPECT_EQ(kSuccessSessionKey, request_options()->GetSecureSession()); |
| request_headers.SetHeader( |
| "chrome-proxy", "something=something_else, s=" + |
| std::string(kSuccessSessionKey) + ", key=value"); |
| // Calling ShouldRetryDueToAuthFailure should trigger fetching of remote |
| // config. |
| EXPECT_TRUE(config_client()->ShouldRetryDueToAuthFailure( |
| request_headers, parsed.get(), origin, load_timing_info)); |
| EXPECT_EQ(2, config_client()->GetBackoffErrorCount()); |
| histogram_tester.ExpectBucketCount( |
| "DataReductionProxy.ConfigService.AuthExpired", false, 2); |
| histogram_tester.ExpectBucketCount( |
| "DataReductionProxy.ConfigService.AuthExpired", true, 2); |
| histogram_tester.ExpectTotalCount( |
| "DataReductionProxy.ConfigService.AuthFailure.LatencyPenalty", 2); |
| RunUntilIdle(); |
| // Third remote config should be fetched. |
| VerifyRemoteSuccessWithOldConfig(); |
| |
| histogram_tester.ExpectUniqueSample( |
| "DataReductionProxy.ConfigService.AuthExpiredSessionKey", |
| 1 /* AUTH_EXPIRED_SESSION_KEY_MATCH */, 2); |
| } |
| |
| // Verifies that the persisted client config is fetched from the disk at |
| // startup, and that the persisted client config is used only if it is less |
| // than 24 hours old. |
| TEST_F(DataReductionProxyConfigServiceClientTest, |
| ValidatePersistedClientConfig) { |
| Init(true); |
| SetDataReductionProxyEnabled(true, true); |
| |
| const struct { |
| base::Optional<base::TimeDelta> staleness; |
| bool expect_valid_config; |
| } tests[] = { |
| { |
| base::nullopt, true, |
| }, |
| { |
| base::TimeDelta::FromHours(25), false, |
| }, |
| { |
| base::TimeDelta::FromHours(1), true, |
| }, |
| }; |
| |
| for (const auto& test : tests) { |
| base::HistogramTester histogram_tester; |
| // Reset the state. |
| test_context_->io_data()->test_request_options()->Invalidate(); |
| test_context_->pref_service()->ClearPref( |
| prefs::kDataReductionProxyLastConfigRetrievalTime); |
| RunUntilIdle(); |
| EXPECT_TRUE(request_options()->GetSecureSession().empty()); |
| |
| // Apply a valid config. This should be stored on the disk. |
| AddMockSuccess(); |
| config_client()->RetrieveConfig(); |
| |
| RunUntilIdle(); |
| EXPECT_EQ(kSuccessSessionKey, request_options()->GetSecureSession()); |
| |
| if (test.staleness) { |
| base::TimeDelta last_config_retrieval_time = |
| base::Time::Now() - base::Time() - test.staleness.value(); |
| |
| test_context_->pref_service()->SetInt64( |
| prefs::kDataReductionProxyLastConfigRetrievalTime, |
| last_config_retrieval_time.InMicroseconds()); |
| test_context_->pref_service()->SchedulePendingLossyWrites(); |
| test_context_->pref_service()->CommitPendingWrite(); |
| } |
| |
| RunUntilIdle(); |
| EXPECT_FALSE(persisted_config().empty()); |
| EXPECT_FALSE(persisted_config_retrieval_time().is_null()); |
| |
| // Simulate startup which should cause the empty persisted client config to |
| // be read from the disk. |
| config_client()->SetRemoteConfigApplied(false); |
| test_context_->io_data()->test_request_options()->Invalidate(); |
| test_context_->data_reduction_proxy_service()->SetIOData( |
| test_context_->io_data()->GetWeakPtr()); |
| RunUntilIdle(); |
| EXPECT_NE(test.expect_valid_config, |
| request_options()->GetSecureSession().empty()); |
| if (test.expect_valid_config) { |
| EXPECT_EQ(kSuccessSessionKey, request_options()->GetSecureSession()); |
| } |
| histogram_tester.ExpectUniqueSample( |
| "DataReductionProxy.ConfigService.PersistedConfigIsExpired", |
| !test.expect_valid_config, 1); |
| } |
| } |
| |
| // Verifies that a new config is not fetched due to auth failure while a |
| // previous client config fetch triggered due to auth failure is already in |
| // progress. |
| TEST_F(DataReductionProxyConfigServiceClientTest, MultipleAuthFailures) { |
| Init(true); |
| net::HttpRequestHeaders request_headers; |
| request_headers.SetHeader( |
| "chrome-proxy", "something=something_else, s=" + |
| std::string(kOldSuccessSessionKey) + ", key=value"); |
| |
| base::HistogramTester histogram_tester; |
| AddMockPreviousSuccess(); |
| AddMockSuccess(); |
| |
| SetDataReductionProxyEnabled(true, true); |
| EXPECT_FALSE(configurator()->GetProxyConfig().is_valid()); |
| histogram_tester.ExpectTotalCount( |
| "DataReductionProxy.ConfigService.AuthExpired", 0); |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| // First remote config should be fetched. |
| VerifyRemoteSuccessWithOldConfig(); |
| EXPECT_TRUE(configurator()->GetProxyConfig().is_valid()); |
| EXPECT_EQ(kOldSuccessSessionKey, request_options()->GetSecureSession()); |
| EXPECT_EQ(0, config_client()->GetBackoffErrorCount()); |
| histogram_tester.ExpectUniqueSample( |
| "DataReductionProxy.ConfigService.AuthExpired", false, 1); |
| |
| // Trigger an auth failure. |
| scoped_refptr<net::HttpResponseHeaders> parsed(new net::HttpResponseHeaders( |
| "HTTP/1.1 407 Proxy Authentication Required\n")); |
| net::ProxyServer origin = net::ProxyServer::FromURI( |
| kOldSuccessOrigin, net::ProxyServer::SCHEME_HTTP); |
| // Calling ShouldRetryDueToAuthFailure should trigger fetching of remote |
| // config. |
| net::LoadTimingInfo load_timing_info; |
| load_timing_info.request_start = |
| base::TimeTicks::Now() - base::TimeDelta::FromSeconds(1); |
| load_timing_info.send_start = load_timing_info.request_start; |
| EXPECT_TRUE(config_client()->ShouldRetryDueToAuthFailure( |
| request_headers, parsed.get(), origin, load_timing_info)); |
| EXPECT_EQ(1, config_client()->GetBackoffErrorCount()); |
| EXPECT_FALSE(configurator()->GetProxyConfig().is_valid()); |
| |
| // Persisted config on pref should be cleared. |
| EXPECT_TRUE(persisted_config().empty()); |
| histogram_tester.ExpectBucketCount( |
| "DataReductionProxy.ConfigService.AuthExpired", false, 1); |
| histogram_tester.ExpectBucketCount( |
| "DataReductionProxy.ConfigService.AuthExpired", true, 1); |
| histogram_tester.ExpectTotalCount( |
| "DataReductionProxy.ConfigService.AuthFailure.LatencyPenalty", 1); |
| |
| // Trigger a second auth failure. |
| EXPECT_EQ(std::string(), request_options()->GetSecureSession()); |
| request_headers.SetHeader( |
| "chrome-proxy", "something=something_else, s=" + |
| std::string(kSuccessSessionKey) + ", key=value"); |
| // Calling ShouldRetryDueToAuthFailure should trigger fetching of remote |
| // config. |
| EXPECT_FALSE(config_client()->ShouldRetryDueToAuthFailure( |
| request_headers, parsed.get(), origin, load_timing_info)); |
| EXPECT_EQ(1, config_client()->GetBackoffErrorCount()); |
| histogram_tester.ExpectBucketCount( |
| "DataReductionProxy.ConfigService.AuthExpired", false, 1); |
| histogram_tester.ExpectBucketCount( |
| "DataReductionProxy.ConfigService.AuthExpired", true, 1); |
| histogram_tester.ExpectTotalCount( |
| "DataReductionProxy.ConfigService.AuthFailure.LatencyPenalty", 1); |
| |
| RunUntilIdle(); |
| VerifyRemoteSuccess(true); |
| |
| // Config should be fetched successfully. |
| EXPECT_FALSE(persisted_config().empty()); |
| EXPECT_FALSE(persisted_config_retrieval_time().is_null()); |
| // The persisted config retrieval time should be very recent (less than 2 |
| // minutes old). 2 minutes of buffer is allowed to account for delays due to |
| // delays in running tests. |
| EXPECT_LE(persisted_config_retrieval_time(), base::Time::Now()); |
| EXPECT_GE(persisted_config_retrieval_time() + base::TimeDelta::FromMinutes(2), |
| base::Time::Now()); |
| |
| histogram_tester.ExpectUniqueSample( |
| "DataReductionProxy.ConfigService.AuthExpiredSessionKey", |
| 1 /* AUTH_EXPIRED_SESSION_KEY_MATCH */, 1); |
| histogram_tester.ExpectBucketCount( |
| "DataReductionProxy.ConfigService.AuthExpired", false, 2); |
| histogram_tester.ExpectBucketCount( |
| "DataReductionProxy.ConfigService.AuthExpired", true, 1); |
| |
| DCHECK(test_context_->data_reduction_proxy_service()); |
| test_context_->io_data()->test_request_options()->Invalidate(); |
| test_context_->data_reduction_proxy_service()->SetIOData( |
| test_context_->io_data()->GetWeakPtr()); |
| test_context_->RunUntilIdle(); |
| } |
| |
| // Verifies that a new config is not fetched due to auth failure while a |
| // previous client config fetch triggered due to IP address changeis already |
| // in progress. |
| TEST_F(DataReductionProxyConfigServiceClientTest, |
| IPAddressChangeWithAuthFailure) { |
| Init(true); |
| net::HttpRequestHeaders request_headers; |
| request_headers.SetHeader( |
| "chrome-proxy", "something=something_else, s=" + |
| std::string(kOldSuccessSessionKey) + ", key=value"); |
| |
| base::HistogramTester histogram_tester; |
| AddMockPreviousSuccess(); |
| AddMockSuccess(); |
| |
| SetDataReductionProxyEnabled(true, true); |
| EXPECT_FALSE(configurator()->GetProxyConfig().is_valid()); |
| histogram_tester.ExpectTotalCount( |
| "DataReductionProxy.ConfigService.AuthExpired", 0); |
| config_client()->RetrieveConfig(); |
| |
| RunUntilIdle(); |
| // First remote config should be fetched. |
| VerifyRemoteSuccessWithOldConfig(); |
| EXPECT_TRUE(configurator()->GetProxyConfig().is_valid()); |
| EXPECT_EQ(kOldSuccessSessionKey, request_options()->GetSecureSession()); |
| EXPECT_EQ(0, config_client()->GetBackoffErrorCount()); |
| histogram_tester.ExpectUniqueSample( |
| "DataReductionProxy.ConfigService.AuthExpired", false, 1); |
| |
| // Trigger IP address change again. |
| AddMockPreviousSuccess(); |
| AddMockPreviousSuccess(); |
| |
| SetDataReductionProxyEnabled(true, true); |
| EXPECT_TRUE(configurator()->GetProxyConfig().is_valid()); |
| config_client()->RetrieveConfig(); |
| |
| // Trigger an auth failure. |
| scoped_refptr<net::HttpResponseHeaders> parsed(new net::HttpResponseHeaders( |
| "HTTP/1.1 407 Proxy Authentication Required\n")); |
| net::ProxyServer origin = net::ProxyServer::FromURI( |
| kOldSuccessOrigin, net::ProxyServer::SCHEME_HTTP); |
| // Calling ShouldRetryDueToAuthFailure should trigger fetching of remote |
| // config. |
| net::LoadTimingInfo load_timing_info; |
| load_timing_info.request_start = |
| base::TimeTicks::Now() - base::TimeDelta::FromSeconds(1); |
| load_timing_info.send_start = load_timing_info.request_start; |
| EXPECT_TRUE(config_client()->ShouldRetryDueToAuthFailure( |
| request_headers, parsed.get(), origin, load_timing_info)); |
| EXPECT_EQ(1, config_client()->GetBackoffErrorCount()); |
| EXPECT_FALSE(configurator()->GetProxyConfig().is_valid()); |
| |
| // Persisted config on pref should be cleared. |
| EXPECT_TRUE(persisted_config().empty()); |
| histogram_tester.ExpectBucketCount( |
| "DataReductionProxy.ConfigService.AuthExpired", false, 1); |
| histogram_tester.ExpectBucketCount( |
| "DataReductionProxy.ConfigService.AuthExpired", true, 1); |
| |
| EXPECT_FALSE(configurator()->GetProxyConfig().is_valid()); |
| // Persisted config on pref should be cleared. |
| EXPECT_TRUE(persisted_config().empty()); |
| |
| // Config should be fetched now. |
| RunUntilIdle(); |
| VerifyRemoteSuccess(true); |
| |
| EXPECT_TRUE(configurator()->GetProxyConfig().is_valid()); |
| // Persisted config on pref should be cleared. |
| EXPECT_FALSE(persisted_config().empty()); |
| EXPECT_FALSE(persisted_config_retrieval_time().is_null()); |
| EXPECT_LE(persisted_config_retrieval_time(), base::Time::Now()); |
| EXPECT_GE(persisted_config_retrieval_time() + base::TimeDelta::FromMinutes(2), |
| base::Time::Now()); |
| EXPECT_EQ(kSuccessSessionKey, request_options()->GetSecureSession()); |
| EXPECT_EQ(0, config_client()->GetBackoffErrorCount()); |
| histogram_tester.ExpectBucketCount( |
| "DataReductionProxy.ConfigService.AuthExpired", false, 2); |
| histogram_tester.ExpectBucketCount( |
| "DataReductionProxy.ConfigService.AuthExpired", true, 1); |
| } |
| |
| // Verifies the correctness of AuthFailure when the session key in the request |
| // headers do not match the currrent session key. |
| TEST_F(DataReductionProxyConfigServiceClientTest, |
| AuthFailureWithRequestHeaders) { |
| Init(true); |
| net::HttpRequestHeaders request_headers; |
| const char kSessionKeyRequestHeaders[] = "123"; |
| ASSERT_NE(kOldSuccessSessionKey, kSessionKeyRequestHeaders); |
| request_headers.SetHeader("chrome-proxy", |
| "s=" + std::string(kSessionKeyRequestHeaders)); |
| base::HistogramTester histogram_tester; |
| AddMockPreviousSuccess(); |
| AddMockSuccess(); |
| AddMockPreviousSuccess(); |
| |
| SetDataReductionProxyEnabled(true, true); |
| histogram_tester.ExpectTotalCount( |
| "DataReductionProxy.ConfigService.AuthExpired", 0); |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| // First remote config should be fetched. |
| VerifyRemoteSuccessWithOldConfig(); |
| EXPECT_EQ(0, config_client()->GetBackoffErrorCount()); |
| histogram_tester.ExpectUniqueSample( |
| "DataReductionProxy.ConfigService.AuthExpired", false, 1); |
| |
| // Trigger an auth failure. |
| scoped_refptr<net::HttpResponseHeaders> parsed(new net::HttpResponseHeaders( |
| "HTTP/1.1 407 Proxy Authentication Required\n")); |
| net::ProxyServer origin = net::ProxyServer::FromURI( |
| kOldSuccessOrigin, net::ProxyServer::SCHEME_HTTP); |
| // Calling ShouldRetryDueToAuthFailure should not trigger fetching of remote |
| // config since the session key in the request headers do not match the |
| // current session key, but the request should be retried. |
| net::LoadTimingInfo load_timing_info; |
| load_timing_info.request_start = |
| base::TimeTicks::Now() - base::TimeDelta::FromSeconds(1); |
| load_timing_info.send_start = load_timing_info.request_start; |
| |
| EXPECT_TRUE(config_client()->ShouldRetryDueToAuthFailure( |
| request_headers, parsed.get(), origin, load_timing_info)); |
| EXPECT_EQ(0, config_client()->GetBackoffErrorCount()); |
| // Persisted config on pref should be cleared. |
| EXPECT_FALSE(persisted_config().empty()); |
| EXPECT_FALSE(persisted_config_retrieval_time().is_null()); |
| EXPECT_LE(persisted_config_retrieval_time(), base::Time::Now()); |
| EXPECT_GE(persisted_config_retrieval_time() + base::TimeDelta::FromMinutes(2), |
| base::Time::Now()); |
| histogram_tester.ExpectBucketCount( |
| "DataReductionProxy.ConfigService.AuthExpired", false, 1); |
| histogram_tester.ExpectBucketCount( |
| "DataReductionProxy.ConfigService.AuthExpired", true, 0); |
| RunUntilIdle(); |
| EXPECT_EQ(kOldSuccessSessionKey, request_options()->GetSecureSession()); |
| |
| histogram_tester.ExpectUniqueSample( |
| "DataReductionProxy.ConfigService.AuthExpiredSessionKey", |
| 0 /* AUTH_EXPIRED_SESSION_KEY_MISMATCH */, 1); |
| } |
| |
| // Verifies that requests that were not proxied through data saver proxy due |
| // to missing config are recorded properly. |
| TEST_F(DataReductionProxyConfigServiceClientTest, HTTPRequests) { |
| Init(false); |
| const struct { |
| std::string url; |
| bool enabled_by_user; |
| bool expect_histogram; |
| } tests[] = { |
| { |
| // Request should not be logged because data saver is disabled. |
| "http://www.one.example.com/", false, false, |
| }, |
| { |
| "http://www.two.example.com/", true, true, |
| }, |
| { |
| "https://www.three.example.com/", false, false, |
| }, |
| { |
| // Request should not be logged because request is HTTPS. |
| "https://www.four.example.com/", true, false, |
| }, |
| { |
| // Request to localhost should not be logged. |
| "http://127.0.0.1/", true, false, |
| }, |
| { |
| // Special use IPv4 address for testing purposes (RFC 5735). |
| "http://198.51.100.1/", true, true, |
| }, |
| }; |
| |
| for (size_t i = 0; i < arraysize(tests); ++i) { |
| base::HistogramTester histogram_tester; |
| SetDataReductionProxyEnabled(tests[i].enabled_by_user, true); |
| |
| net::TestDelegate test_delegate; |
| |
| std::unique_ptr<net::URLRequest> request( |
| test_url_request_context()->CreateRequest( |
| GURL(tests[i].url), net::IDLE, &test_delegate, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| request->Start(); |
| RunUntilIdle(); |
| |
| histogram_tester.ExpectTotalCount( |
| "DataReductionProxy.ConfigService.HTTPRequests", |
| tests[i].expect_histogram ? 1 : 0); |
| |
| if (tests[i].expect_histogram) { |
| histogram_tester.ExpectUniqueSample( |
| "DataReductionProxy.ConfigService.HTTPRequests", 0, 1); |
| } |
| } |
| } |
| |
| // Tests that remote config can be applied after the serialized config has |
| // been applied. |
| TEST_F(DataReductionProxyConfigServiceClientTest, ApplySerializedConfig) { |
| Init(true); |
| AddMockSuccess(); |
| |
| SetDataReductionProxyEnabled(true, true); |
| EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp()); |
| config_client()->ApplySerializedConfig(loaded_config()); |
| VerifySuccessWithLoadedConfig(true); |
| EXPECT_TRUE(persisted_config().empty()); |
| |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| VerifyRemoteSuccess(true); |
| } |
| |
| // Tests that remote config can be applied after the serialized config has |
| // been applied. Verifies that if the secure transport is restricted, then the |
| // secure proxies are not used. |
| TEST_F(DataReductionProxyConfigServiceClientTest, |
| ApplySerializedConfigWithSecureTransportRestricted) { |
| Init(true); |
| |
| AddMockSuccess(); |
| |
| SetDataReductionProxyEnabled(true, false); |
| EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp()); |
| config_client()->ApplySerializedConfig(loaded_config()); |
| VerifySuccessWithLoadedConfig(false); |
| EXPECT_TRUE(persisted_config().empty()); |
| |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| VerifyRemoteSuccess(false); |
| } |
| |
| // Tests that serialized config has no effect after the config has been |
| // retrieved successfully. |
| TEST_F(DataReductionProxyConfigServiceClientTest, |
| ApplySerializedConfigAfterReceipt) { |
| Init(true); |
| AddMockSuccess(); |
| |
| SetDataReductionProxyEnabled(true, true); |
| EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp()); |
| EXPECT_TRUE(request_options()->GetSecureSession().empty()); |
| |
| // Retrieve the remote config. |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| VerifyRemoteSuccess(true); |
| |
| // ApplySerializedConfig should not have any effect since the remote config |
| // is already applied. |
| config_client()->ApplySerializedConfig(encoded_config()); |
| VerifyRemoteSuccess(true); |
| } |
| |
| // Tests that a local serialized config can be applied successfully if remote |
| // config has not been fetched so far. |
| TEST_F(DataReductionProxyConfigServiceClientTest, ApplySerializedConfigLocal) { |
| Init(true); |
| SetDataReductionProxyEnabled(true, true); |
| EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp()); |
| EXPECT_TRUE(request_options()->GetSecureSession().empty()); |
| EXPECT_TRUE(persisted_config_retrieval_time().is_null()); |
| |
| // ApplySerializedConfig should apply the encoded config. |
| config_client()->ApplySerializedConfig(encoded_config()); |
| EXPECT_EQ(std::vector<net::ProxyServer>( |
| {net::ProxyServer::FromURI(kSuccessOrigin, |
| net::ProxyServer::SCHEME_HTTP), |
| net::ProxyServer::FromURI(kSuccessFallback, |
| net::ProxyServer::SCHEME_HTTP)}), |
| GetConfiguredProxiesForHttp()); |
| EXPECT_TRUE(persisted_config().empty()); |
| EXPECT_TRUE(persisted_config_retrieval_time().is_null()); |
| EXPECT_FALSE(request_options()->GetSecureSession().empty()); |
| } |
| |
| // Verifies that setting a client config sets the pingback reporting fraction |
| // correctly to 0.0f. |
| TEST_F(DataReductionProxyConfigServiceClientTest, |
| ApplySerializedConfigZeroReportingFraction) { |
| Init(true); |
| // ApplySerializedConfig should apply the encoded config. |
| config_client()->ApplySerializedConfig( |
| zero_reporting_fraction_encoded_config()); |
| EXPECT_EQ(0.0f, pingback_reporting_fraction()); |
| } |
| |
| // Verifies that setting a client config sets the pingback reporting fraction |
| // correctly to 0.0f when the pingback is not set in the protobuf. |
| TEST_F(DataReductionProxyConfigServiceClientTest, |
| ApplySerializedConfigEmptyReportingFraction) { |
| Init(true); |
| // ApplySerializedConfig should apply the encoded config. |
| config_client()->ApplySerializedConfig( |
| empty_reporting_fraction_encoded_config()); |
| EXPECT_EQ(0.0f, pingback_reporting_fraction()); |
| } |
| |
| // Verifies that setting a client config sets the pingback reporting fraction |
| // correctly to 1.0f. |
| TEST_F(DataReductionProxyConfigServiceClientTest, |
| ApplySerializedConfigOneReportingFraction) { |
| Init(true); |
| // ApplySerializedConfig should apply the encoded config. |
| config_client()->ApplySerializedConfig( |
| one_reporting_fraction_encoded_config()); |
| EXPECT_EQ(1.0f, pingback_reporting_fraction()); |
| } |
| |
| // Verifies that setting a client config sets the pingback reporting fraction |
| // correctly to 0.5f. |
| TEST_F(DataReductionProxyConfigServiceClientTest, |
| ApplySerializedConfigHalfReportingFraction) { |
| Init(true); |
| // ApplySerializedConfig should apply the encoded config. |
| config_client()->ApplySerializedConfig( |
| half_reporting_fraction_encoded_config()); |
| EXPECT_EQ(0.5f, pingback_reporting_fraction()); |
| } |
| |
| #if defined(OS_ANDROID) |
| // Verifies the correctness of fetching config when Chromium is in background |
| // and foreground. |
| TEST_F(DataReductionProxyConfigServiceClientTest, FetchConfigOnForeground) { |
| Init(true); |
| SetDataReductionProxyEnabled(true, true); |
| |
| { |
| // Tests that successful config fetches while Chromium is in background, |
| // does not trigger refetches when Chromium comes to foreground. |
| base::HistogramTester histogram_tester; |
| AddMockSuccess(); |
| config_client()->set_application_state_background(true); |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| VerifyRemoteSuccess(true); |
| EXPECT_FALSE(config_client()->foreground_fetch_pending()); |
| histogram_tester.ExpectTotalCount( |
| "DataReductionProxy.ConfigService.FetchLatency", 1); |
| EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds), |
| config_client()->GetDelay()); |
| config_client()->set_application_state_background(false); |
| config_client()->TriggerApplicationStatusToForeground(); |
| RunUntilIdle(); |
| EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds), |
| config_client()->GetDelay()); |
| histogram_tester.ExpectTotalCount( |
| "DataReductionProxy.ConfigService.FetchLatency", 1); |
| } |
| |
| { |
| // Tests that config fetch failures while Chromium is in foreground does not |
| // trigger refetches when Chromium comes to foreground again. |
| base::HistogramTester histogram_tester; |
| AddMockFailure(); |
| config_client()->set_application_state_background(false); |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| EXPECT_FALSE(config_client()->foreground_fetch_pending()); |
| histogram_tester.ExpectTotalCount( |
| "DataReductionProxy.ConfigService.FetchLatency", 0); |
| EXPECT_EQ(base::TimeDelta::FromSeconds(20), config_client()->GetDelay()); |
| config_client()->TriggerApplicationStatusToForeground(); |
| RunUntilIdle(); |
| histogram_tester.ExpectTotalCount( |
| "DataReductionProxy.ConfigService.FetchLatency", 0); |
| EXPECT_EQ(base::TimeDelta::FromSeconds(20), config_client()->GetDelay()); |
| } |
| |
| { |
| // Tests that config fetch failures while Chromium is in background, trigger |
| // a refetch when Chromium comes to foreground. |
| base::HistogramTester histogram_tester; |
| AddMockFailure(); |
| AddMockSuccess(); |
| config_client()->set_application_state_background(true); |
| config_client()->RetrieveConfig(); |
| RunUntilIdle(); |
| EXPECT_TRUE(config_client()->foreground_fetch_pending()); |
| histogram_tester.ExpectTotalCount( |
| "DataReductionProxy.ConfigService.FetchLatency", 0); |
| EXPECT_EQ(base::TimeDelta::FromSeconds(kMaxBackgroundFetchIntervalSeconds), |
| config_client()->GetDelay()); |
| config_client()->set_application_state_background(false); |
| config_client()->TriggerApplicationStatusToForeground(); |
| RunUntilIdle(); |
| EXPECT_FALSE(config_client()->foreground_fetch_pending()); |
| histogram_tester.ExpectTotalCount( |
| "DataReductionProxy.ConfigService.FetchLatency", 1); |
| EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds), |
| config_client()->GetDelay()); |
| VerifyRemoteSuccess(true); |
| } |
| } |
| #endif |
| |
| } // namespace data_reduction_proxy |