1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/data_reduction_proxy/browser/data_reduction_proxy_settings.h"
7 #include "base/command_line.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "components/data_reduction_proxy/browser/data_reduction_proxy_settings_test_utils.h"
12 #include "components/data_reduction_proxy/common/data_reduction_proxy_pref_names.h"
13 #include "components/data_reduction_proxy/common/data_reduction_proxy_switches.h"
14 #include "net/http/http_auth.h"
15 #include "net/http/http_auth_cache.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
22 const char kDataReductionProxy[] = "https://foo.com:443/";
23 const char kDataReductionProxyDev[] = "http://foo-dev.com:80";
24 const char kDataReductionProxyFallback[] = "http://bar.com:80";
25 const char kDataReductionProxyKey[] = "12345";
27 const char kProbeURLWithOKResponse[] = "http://ok.org/";
28 const char kProbeURLWithBadResponse[] = "http://bad.org/";
29 const char kProbeURLWithNoResponse[] = "http://no.org/";
33 namespace data_reduction_proxy {
35 class DataReductionProxySettingsTest
36 : public ConcreteDataReductionProxySettingsTest<
37 DataReductionProxySettings> {
41 TEST_F(DataReductionProxySettingsTest, TestAuthenticationInit) {
42 AddProxyToCommandLine();
43 net::HttpAuthCache cache;
44 DataReductionProxySettings::InitDataReductionAuthentication(
45 &cache, kDataReductionProxyKey);
46 DataReductionProxySettings::DataReductionProxyList proxies =
47 DataReductionProxySettings::GetDataReductionProxies();
48 for (DataReductionProxySettings::DataReductionProxyList::iterator it =
49 proxies.begin(); it != proxies.end(); ++it) {
50 net::HttpAuthCache::Entry* entry = cache.LookupByPath(*it,
52 EXPECT_TRUE(entry != NULL);
53 EXPECT_EQ(net::HttpAuth::AUTH_SCHEME_SPDYPROXY, entry->scheme());
54 EXPECT_EQ("SpdyProxy", entry->auth_challenge().substr(0,9));
56 GURL bad_server = GURL("https://bad.proxy.com/");
57 net::HttpAuthCache::Entry* entry =
58 cache.LookupByPath(bad_server, std::string());
59 EXPECT_TRUE(entry == NULL);
62 TEST_F(DataReductionProxySettingsTest, TestGetDataReductionProxyOrigin) {
63 AddProxyToCommandLine();
64 // SetUp() adds the origin to the command line, which should be returned here.
66 DataReductionProxySettings::GetDataReductionProxyOrigin();
67 EXPECT_EQ(kDataReductionProxy, result);
70 TEST_F(DataReductionProxySettingsTest, TestGetDataReductionProxyDevOrigin) {
71 AddProxyToCommandLine();
72 CommandLine::ForCurrentProcess()->AppendSwitchASCII(
73 switches::kDataReductionProxyDev, kDataReductionProxyDev);
75 DataReductionProxySettings::GetDataReductionProxyOrigin();
76 EXPECT_EQ(kDataReductionProxyDev, result);
79 TEST_F(DataReductionProxySettingsTest, TestGetDataReductionProxies) {
80 DataReductionProxySettings::DataReductionProxyList proxies =
81 DataReductionProxySettings::GetDataReductionProxies();
83 unsigned int expected_proxy_size = 0u;
84 #if defined(SPDY_PROXY_AUTH_ORIGIN)
85 ++expected_proxy_size;
87 #if defined(DATA_REDUCTION_FALLBACK_HOST)
88 ++expected_proxy_size;
91 EXPECT_EQ(expected_proxy_size, proxies.size());
93 // Adding just the fallback on the command line shouldn't add a proxy unless
94 // there was already one compiled in.
95 CommandLine::ForCurrentProcess()->AppendSwitchASCII(
96 switches::kDataReductionProxyFallback, kDataReductionProxyFallback);
97 proxies = DataReductionProxySettings::GetDataReductionProxies();
99 // So: if there weren't any proxies before, there still won't be.
100 // If there were one or two, there will be two now.
101 expected_proxy_size = expected_proxy_size == 0u ? 0u : 2u;
103 EXPECT_EQ(expected_proxy_size, proxies.size());
105 CommandLine::ForCurrentProcess()->AppendSwitchASCII(
106 switches::kDataReductionProxy, kDataReductionProxy);
107 proxies = DataReductionProxySettings::GetDataReductionProxies();
108 EXPECT_EQ(2u, proxies.size());
110 // Command line proxies have precedence, so even if there were other values
111 // compiled in, these should be the ones in the list.
112 EXPECT_EQ("foo.com", proxies[0].host());
113 EXPECT_EQ(443 ,proxies[0].EffectiveIntPort());
114 EXPECT_EQ("bar.com", proxies[1].host());
115 EXPECT_EQ(80, proxies[1].EffectiveIntPort());
118 TEST_F(DataReductionProxySettingsTest, TestAuthHashGeneration) {
119 AddProxyToCommandLine();
120 std::string salt = "8675309"; // Jenny's number to test the hash generator.
121 std::string salted_key = salt + kDataReductionProxyKey + salt;
122 base::string16 expected_hash = base::UTF8ToUTF16(base::MD5String(salted_key));
123 EXPECT_EQ(expected_hash,
124 DataReductionProxySettings::AuthHashForSalt(
125 8675309, kDataReductionProxyKey));
128 // Test that the auth key set by preprocessor directive is not used
129 // when an origin is set via a switch. This test only does anything useful in
131 TEST_F(DataReductionProxySettingsTest,
132 TestAuthHashGenerationWithOriginSetViaSwitch) {
133 CommandLine::ForCurrentProcess()->AppendSwitchASCII(
134 switches::kDataReductionProxy, kDataReductionProxy);
135 EXPECT_EQ(base::string16(),
136 DataReductionProxySettings::AuthHashForSalt(
137 8675309, kDataReductionProxyKey));
140 TEST_F(DataReductionProxySettingsTest, TestIsProxyEnabledOrManaged) {
141 AddProxyToCommandLine();
142 settings_->InitPrefMembers();
143 base::MessageLoopForUI loop;
144 // The proxy is disabled initially.
145 settings_->enabled_by_user_ = false;
146 settings_->SetProxyConfigs(false, false, false);
148 EXPECT_FALSE(settings_->IsDataReductionProxyEnabled());
149 EXPECT_FALSE(settings_->IsDataReductionProxyManaged());
151 CheckOnPrefChange(true, true, false);
152 EXPECT_TRUE(settings_->IsDataReductionProxyEnabled());
153 EXPECT_FALSE(settings_->IsDataReductionProxyManaged());
155 CheckOnPrefChange(true, true, true);
156 EXPECT_TRUE(settings_->IsDataReductionProxyEnabled());
157 EXPECT_TRUE(settings_->IsDataReductionProxyManaged());
160 TEST_F(DataReductionProxySettingsTest, TestAcceptableChallenges) {
161 AddProxyToCommandLine();
165 bool expected_to_succeed;
168 challenge_test tests[] = {
169 {"foo.com:443", "", false}, // 0. No realm.
170 {"foo.com:443", "xxx", false}, // 1. Wrong realm.
171 {"foo.com:443", "spdyproxy", false}, // 2. Case matters.
172 {"foo.com:443", "SpdyProxy", true}, // 3. OK.
173 {"foo.com:443", "SpdyProxy1234567", true}, // 4. OK
174 {"bar.com:80", "SpdyProxy1234567", true}, // 5. OK.
175 {"foo.com:443", "SpdyProxyxxx", true}, // 6. OK
176 {"", "SpdyProxy1234567", false}, // 7. No challenger.
177 {"xxx.net:443", "SpdyProxy1234567", false}, // 8. Wrong host.
178 {"foo.com", "SpdyProxy1234567", false}, // 9. No port.
179 {"foo.com:80", "SpdyProxy1234567", false}, // 10.Wrong port.
180 {"bar.com:81", "SpdyProxy1234567", false}, // 11.Wrong port.
183 for (int i = 0; i <= 11; ++i) {
184 scoped_refptr<net::AuthChallengeInfo> auth_info(new net::AuthChallengeInfo);
185 auth_info->challenger = net::HostPortPair::FromString(tests[i].host);
186 auth_info->realm = tests[i].realm;
187 EXPECT_EQ(tests[i].expected_to_succeed,
188 DataReductionProxySettings::IsAcceptableAuthChallenge(
193 TEST_F(DataReductionProxySettingsTest, TestChallengeTokens) {
194 AddProxyToCommandLine();
197 bool expected_empty_token;
200 token_test tests[] = {
201 {"", true}, // 0. No realm.
202 {"xxx", true}, // 1. realm too short.
203 {"spdyproxy", true}, // 2. no salt.
204 {"SpdyProxyxxx", true}, // 3. Salt not an int.
205 {"SpdyProxy1234567", false}, // 4. OK
208 for (int i = 0; i <= 4; ++i) {
209 scoped_refptr<net::AuthChallengeInfo> auth_info(new net::AuthChallengeInfo);
210 auth_info->challenger =
211 net::HostPortPair::FromString(kDataReductionProxy);
212 auth_info->realm = tests[i].realm;
213 base::string16 token = settings_->GetTokenForAuthChallenge(auth_info.get());
214 EXPECT_EQ(tests[i].expected_empty_token, token.empty());
218 TEST_F(DataReductionProxySettingsTest, TestResetDataReductionStatistics) {
219 int64 original_content_length;
220 int64 received_content_length;
221 int64 last_update_time;
222 settings_->ResetDataReductionStatistics();
223 settings_->GetContentLengths(kNumDaysInHistory,
224 &original_content_length,
225 &received_content_length,
227 EXPECT_EQ(0L, original_content_length);
228 EXPECT_EQ(0L, received_content_length);
229 EXPECT_EQ(last_update_time_.ToInternalValue(), last_update_time);
232 TEST_F(DataReductionProxySettingsTest, TestContentLengths) {
233 int64 original_content_length;
234 int64 received_content_length;
235 int64 last_update_time;
237 // Request |kNumDaysInHistory| days.
238 settings_->GetContentLengths(kNumDaysInHistory,
239 &original_content_length,
240 &received_content_length,
242 const unsigned int days = kNumDaysInHistory;
243 // Received content length history values are 0 to |kNumDaysInHistory - 1|.
244 int64 expected_total_received_content_length = (days - 1L) * days / 2;
245 // Original content length history values are 0 to
246 // |2 * (kNumDaysInHistory - 1)|.
247 long expected_total_original_content_length = (days - 1L) * days;
248 EXPECT_EQ(expected_total_original_content_length, original_content_length);
249 EXPECT_EQ(expected_total_received_content_length, received_content_length);
250 EXPECT_EQ(last_update_time_.ToInternalValue(), last_update_time);
252 // Request |kNumDaysInHistory - 1| days.
253 settings_->GetContentLengths(kNumDaysInHistory - 1,
254 &original_content_length,
255 &received_content_length,
257 expected_total_received_content_length -= (days - 1);
258 expected_total_original_content_length -= 2 * (days - 1);
259 EXPECT_EQ(expected_total_original_content_length, original_content_length);
260 EXPECT_EQ(expected_total_received_content_length, received_content_length);
263 settings_->GetContentLengths(0,
264 &original_content_length,
265 &received_content_length,
267 expected_total_received_content_length = 0;
268 expected_total_original_content_length = 0;
269 EXPECT_EQ(expected_total_original_content_length, original_content_length);
270 EXPECT_EQ(expected_total_received_content_length, received_content_length);
272 // Request 1 day. First day had 0 bytes so should be same as 0 days.
273 settings_->GetContentLengths(1,
274 &original_content_length,
275 &received_content_length,
277 EXPECT_EQ(expected_total_original_content_length, original_content_length);
278 EXPECT_EQ(expected_total_received_content_length, received_content_length);
281 // TODO(marq): Add a test to verify that MaybeActivateDataReductionProxy
282 // is called when the pref in |settings_| is enabled.
283 TEST_F(DataReductionProxySettingsTest, TestMaybeActivateDataReductionProxy) {
284 AddProxyToCommandLine();
286 // Initialize the pref member in |settings_| without the usual callback
287 // so it won't trigger MaybeActivateDataReductionProxy when the pref value
289 settings_->spdy_proxy_auth_enabled_.Init(
290 prefs::kDataReductionProxyEnabled,
291 settings_->GetOriginalProfilePrefs());
293 // TODO(bengr): Test enabling/disabling while a probe is outstanding.
294 base::MessageLoopForUI loop;
295 // The proxy is enabled and unrestructed initially.
296 // Request succeeded but with bad response, expect proxy to be restricted.
297 CheckProbe(true, kProbeURLWithBadResponse, "Bad", true, true, true, false);
298 // Request succeeded with valid response, expect proxy to be unrestricted.
299 CheckProbe(true, kProbeURLWithOKResponse, "OK", true, true, false, false);
300 // Request failed, expect proxy to be enabled but restricted.
301 CheckProbe(true, kProbeURLWithNoResponse, "", false, true, true, false);
302 // The proxy is disabled initially. Probes should not be emitted to change
304 CheckProbe(false, kProbeURLWithOKResponse, "OK", true, false, false, false);
307 TEST_F(DataReductionProxySettingsTest, TestOnIPAddressChanged) {
308 AddProxyToCommandLine();
309 base::MessageLoopForUI loop;
310 // The proxy is enabled initially.
311 pref_service_.SetBoolean(prefs::kDataReductionProxyEnabled, true);
312 settings_->spdy_proxy_auth_enabled_.Init(
313 prefs::kDataReductionProxyEnabled,
314 settings_->GetOriginalProfilePrefs());
315 settings_->enabled_by_user_ = true;
316 settings_->restricted_by_carrier_ = false;
317 settings_->SetProxyConfigs(true, false, true);
318 // IP address change triggers a probe that succeeds. Proxy remains
320 CheckProbeOnIPChange(kProbeURLWithOKResponse, "OK", true, false, false);
321 // IP address change triggers a probe that fails. Proxy is restricted.
322 CheckProbeOnIPChange(kProbeURLWithBadResponse, "Bad", true, true, false);
323 // IP address change triggers a probe that fails. Proxy remains restricted.
324 CheckProbeOnIPChange(kProbeURLWithBadResponse, "Bad", true, true, false);
325 // IP address change triggers a probe that succeed. Proxy is unrestricted.
326 CheckProbeOnIPChange(kProbeURLWithBadResponse, "OK", true, false, false);
329 TEST_F(DataReductionProxySettingsTest, TestOnProxyEnabledPrefChange) {
330 AddProxyToCommandLine();
331 settings_->InitPrefMembers();
332 base::MessageLoopForUI loop;
333 // The proxy is enabled initially.
334 settings_->enabled_by_user_ = true;
335 settings_->SetProxyConfigs(true, false, true);
336 // The pref is disabled, so correspondingly should be the proxy.
337 CheckOnPrefChange(false, false, false);
338 // The pref is enabled, so correspondingly should be the proxy.
339 CheckOnPrefChange(true, true, false);
342 TEST_F(DataReductionProxySettingsTest, TestInitDataReductionProxyOn) {
343 MockSettings* settings = static_cast<MockSettings*>(settings_.get());
344 EXPECT_CALL(*settings, RecordStartupState(PROXY_ENABLED));
346 pref_service_.SetBoolean(prefs::kDataReductionProxyEnabled, true);
347 CheckInitDataReductionProxy(true);
350 TEST_F(DataReductionProxySettingsTest, TestInitDataReductionProxyOff) {
351 // InitDataReductionProxySettings with the preference off will directly call
353 MockSettings* settings = static_cast<MockSettings*>(settings_.get());
354 EXPECT_CALL(*settings, RecordStartupState(PROXY_DISABLED));
356 pref_service_.SetBoolean(prefs::kDataReductionProxyEnabled, false);
357 CheckInitDataReductionProxy(false);
360 TEST_F(DataReductionProxySettingsTest, TestSetProxyFromCommandLine) {
361 MockSettings* settings = static_cast<MockSettings*>(settings_.get());
362 EXPECT_CALL(*settings, RecordStartupState(PROXY_ENABLED));
364 CommandLine::ForCurrentProcess()->AppendSwitch(
365 switches::kEnableDataReductionProxy);
366 CheckInitDataReductionProxy(true);
369 TEST_F(DataReductionProxySettingsTest, TestGetDailyContentLengths) {
370 DataReductionProxySettings::ContentLengthList result =
371 settings_->GetDailyContentLengths(prefs::kDailyHttpOriginalContentLength);
373 ASSERT_FALSE(result.empty());
374 ASSERT_EQ(kNumDaysInHistory, result.size());
376 for (size_t i = 0; i < kNumDaysInHistory; ++i) {
377 long expected_length =
378 static_cast<long>((kNumDaysInHistory - 1 - i) * 2);
379 ASSERT_EQ(expected_length, result[i]);
383 TEST_F(DataReductionProxySettingsTest, CheckInitMetricsWhenNotAllowed) {
384 // No call to |AddProxyToCommandLine()| was made, so the proxy feature
385 // should be unavailable.
386 base::MessageLoopForUI loop;
387 DataReductionProxySettings::SetAllowed(false);
388 EXPECT_FALSE(DataReductionProxySettings::IsDataReductionProxyAllowed());
389 MockSettings* settings = static_cast<MockSettings*>(settings_.get());
390 EXPECT_CALL(*settings, RecordStartupState(PROXY_NOT_AVAILABLE));
392 scoped_ptr<DataReductionProxyConfigurator> configurator(
393 new TestDataReductionProxyConfig());
394 settings_->SetProxyConfigurator(configurator.Pass());
395 scoped_refptr<net::TestURLRequestContextGetter> request_context =
396 new net::TestURLRequestContextGetter(base::MessageLoopProxy::current());
397 settings_->InitDataReductionProxySettings(&pref_service_,
399 request_context.get());
401 base::MessageLoop::current()->RunUntilIdle();
404 } // namespace data_reduction_proxy