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.
4
5#include "components/data_reduction_proxy/browser/data_reduction_proxy_settings.h"
6
7#include "base/command_line.h"
8#include "base/md5.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_params.h"
12#include "components/data_reduction_proxy/browser/data_reduction_proxy_settings_test_utils.h"
13#include "components/data_reduction_proxy/common/data_reduction_proxy_pref_names.h"
14#include "components/data_reduction_proxy/common/data_reduction_proxy_switches.h"
15#include "net/http/http_auth.h"
16#include "net/http/http_auth_cache.h"
17#include "testing/gmock/include/gmock/gmock.h"
18#include "testing/gtest/include/gtest/gtest.h"
19#include "url/gurl.h"
20
21namespace {
22
23const char kProbeURLWithOKResponse[] = "http://ok.org/";
24const char kProbeURLWithBadResponse[] = "http://bad.org/";
25const char kProbeURLWithNoResponse[] = "http://no.org/";
26
27}  // namespace
28
29namespace data_reduction_proxy {
30
31class DataReductionProxySettingsTest
32    : public ConcreteDataReductionProxySettingsTest<
33          DataReductionProxySettings> {
34};
35
36TEST_F(DataReductionProxySettingsTest, TestGetDataReductionProxyOrigin) {
37  // SetUp() adds the origin to the command line, which should be returned here.
38  std::string result =
39      settings_->params()->origin().spec();
40  EXPECT_EQ(GURL(expected_params_->DefaultOrigin()), GURL(result));
41}
42
43TEST_F(DataReductionProxySettingsTest, TestGetDataReductionProxyDevOrigin) {
44  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
45      switches::kDataReductionProxyDev, expected_params_->DefaultDevOrigin());
46  ResetSettings(true, true, false, true, false);
47  std::string result =
48      settings_->params()->origin().spec();
49  EXPECT_EQ(GURL(expected_params_->DefaultDevOrigin()), GURL(result));
50}
51
52
53TEST_F(DataReductionProxySettingsTest, TestGetDataReductionProxies) {
54  DataReductionProxyParams::DataReductionProxyList proxies =
55      expected_params_->GetAllowedProxies();
56
57  unsigned int expected_proxy_size = 2u;
58  EXPECT_EQ(expected_proxy_size, proxies.size());
59
60  net::HostPortPair expected_origin =
61      net::HostPortPair::FromURL(GURL(expected_params_->DefaultOrigin()));
62  net::HostPortPair expected_fallback_origin =
63      net::HostPortPair::FromURL(
64          GURL(expected_params_->DefaultFallbackOrigin()));
65  EXPECT_EQ(expected_origin.host(), proxies[0].host());
66  EXPECT_EQ(expected_origin.port() ,proxies[0].EffectiveIntPort());
67  EXPECT_EQ(expected_fallback_origin.host(), proxies[1].host());
68  EXPECT_EQ(expected_fallback_origin.port(), proxies[1].EffectiveIntPort());
69}
70
71TEST_F(DataReductionProxySettingsTest, TestSetProxyConfigs) {
72  TestDataReductionProxyParams drp_params(
73      DataReductionProxyParams::kAllowed |
74      DataReductionProxyParams::kFallbackAllowed |
75      DataReductionProxyParams::kPromoAllowed,
76      TestDataReductionProxyParams::HAS_EVERYTHING &
77      ~TestDataReductionProxyParams::HAS_DEV_ORIGIN &
78      ~TestDataReductionProxyParams::HAS_DEV_FALLBACK_ORIGIN);
79  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
80      switches::kDataReductionProxyAlt, drp_params.DefaultAltOrigin());
81  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
82      switches::kDataReductionProxyAltFallback,
83      drp_params.DefaultAltFallbackOrigin());
84  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
85      switches::kDataReductionSSLProxy, drp_params.DefaultSSLOrigin());
86  ResetSettings(true, true, true, true, false);
87  TestDataReductionProxyConfig* config =
88      static_cast<TestDataReductionProxyConfig*>(
89          settings_->configurator());
90
91  settings_->SetProxyConfigs(true, true, false, false);
92  EXPECT_TRUE(config->enabled_);
93  EXPECT_TRUE(net::HostPortPair::FromString(
94      expected_params_->DefaultAltOrigin()).Equals(
95          net::HostPortPair::FromString(config->origin_)));
96  EXPECT_TRUE(net::HostPortPair::FromString(
97      expected_params_->DefaultAltFallbackOrigin()).Equals(
98          net::HostPortPair::FromString(config->fallback_origin_)));
99  EXPECT_TRUE(net::HostPortPair::FromString(
100      expected_params_->DefaultSSLOrigin()).Equals(
101          net::HostPortPair::FromString(config->ssl_origin_)));
102
103  settings_->SetProxyConfigs(true, false, false, false);
104  EXPECT_TRUE(config->enabled_);
105  EXPECT_TRUE(net::HostPortPair::FromString(drp_params.DefaultOrigin()).Equals(
106      net::HostPortPair::FromString(config->origin_)));
107  EXPECT_TRUE(net::HostPortPair::FromString(
108      drp_params.DefaultFallbackOrigin()).Equals(
109          net::HostPortPair::FromString(config->fallback_origin_)));
110  EXPECT_EQ("", config->ssl_origin_);
111
112  settings_->SetProxyConfigs(false, true, false, false);
113  EXPECT_FALSE(config->enabled_);
114  EXPECT_EQ("", config->origin_);
115  EXPECT_EQ("", config->fallback_origin_);
116  EXPECT_EQ("", config->ssl_origin_);
117
118  settings_->SetProxyConfigs(false, false, false, false);
119  EXPECT_FALSE(config->enabled_);
120  EXPECT_EQ("", config->origin_);
121  EXPECT_EQ("", config->fallback_origin_);
122  EXPECT_EQ("", config->ssl_origin_);
123}
124
125TEST_F(DataReductionProxySettingsTest, TestSetProxyConfigsHoldback) {
126  ResetSettings(true, true, true, true, true);
127  TestDataReductionProxyConfig* config =
128      static_cast<TestDataReductionProxyConfig*>(
129          settings_->configurator());
130
131   // Holdback.
132  settings_->SetProxyConfigs(true, true, false, false);
133  EXPECT_FALSE(config->enabled_);
134  EXPECT_EQ("", config->origin_);
135  EXPECT_EQ("", config->fallback_origin_);
136  EXPECT_EQ("", config->ssl_origin_);
137}
138
139TEST_F(DataReductionProxySettingsTest, TestIsProxyEnabledOrManaged) {
140  settings_->InitPrefMembers();
141  base::MessageLoopForUI loop;
142  // The proxy is disabled initially.
143  settings_->enabled_by_user_ = false;
144  settings_->SetProxyConfigs(false, false, false, false);
145
146  EXPECT_FALSE(settings_->IsDataReductionProxyEnabled());
147  EXPECT_FALSE(settings_->IsDataReductionProxyManaged());
148
149  CheckOnPrefChange(true, true, false);
150  EXPECT_TRUE(settings_->IsDataReductionProxyEnabled());
151  EXPECT_FALSE(settings_->IsDataReductionProxyManaged());
152
153  CheckOnPrefChange(true, true, true);
154  EXPECT_TRUE(settings_->IsDataReductionProxyEnabled());
155  EXPECT_TRUE(settings_->IsDataReductionProxyManaged());
156
157  base::MessageLoop::current()->RunUntilIdle();
158}
159
160TEST_F(DataReductionProxySettingsTest, TestResetDataReductionStatistics) {
161  int64 original_content_length;
162  int64 received_content_length;
163  int64 last_update_time;
164  settings_->ResetDataReductionStatistics();
165  settings_->GetContentLengths(kNumDaysInHistory,
166                               &original_content_length,
167                               &received_content_length,
168                               &last_update_time);
169  EXPECT_EQ(0L, original_content_length);
170  EXPECT_EQ(0L, received_content_length);
171  EXPECT_EQ(last_update_time_.ToInternalValue(), last_update_time);
172}
173
174TEST_F(DataReductionProxySettingsTest, TestContentLengths) {
175  int64 original_content_length;
176  int64 received_content_length;
177  int64 last_update_time;
178
179  // Request |kNumDaysInHistory| days.
180  settings_->GetContentLengths(kNumDaysInHistory,
181                               &original_content_length,
182                               &received_content_length,
183                               &last_update_time);
184  const unsigned int days = kNumDaysInHistory;
185  // Received content length history values are 0 to |kNumDaysInHistory - 1|.
186  int64 expected_total_received_content_length = (days - 1L) * days / 2;
187  // Original content length history values are 0 to
188  // |2 * (kNumDaysInHistory - 1)|.
189  long expected_total_original_content_length = (days - 1L) * days;
190  EXPECT_EQ(expected_total_original_content_length, original_content_length);
191  EXPECT_EQ(expected_total_received_content_length, received_content_length);
192  EXPECT_EQ(last_update_time_.ToInternalValue(), last_update_time);
193
194  // Request |kNumDaysInHistory - 1| days.
195  settings_->GetContentLengths(kNumDaysInHistory - 1,
196                               &original_content_length,
197                               &received_content_length,
198                               &last_update_time);
199  expected_total_received_content_length -= (days - 1);
200  expected_total_original_content_length -= 2 * (days - 1);
201  EXPECT_EQ(expected_total_original_content_length, original_content_length);
202  EXPECT_EQ(expected_total_received_content_length, received_content_length);
203
204  // Request 0 days.
205  settings_->GetContentLengths(0,
206                               &original_content_length,
207                               &received_content_length,
208                               &last_update_time);
209  expected_total_received_content_length = 0;
210  expected_total_original_content_length = 0;
211  EXPECT_EQ(expected_total_original_content_length, original_content_length);
212  EXPECT_EQ(expected_total_received_content_length, received_content_length);
213
214  // Request 1 day. First day had 0 bytes so should be same as 0 days.
215  settings_->GetContentLengths(1,
216                               &original_content_length,
217                               &received_content_length,
218                               &last_update_time);
219  EXPECT_EQ(expected_total_original_content_length, original_content_length);
220  EXPECT_EQ(expected_total_received_content_length, received_content_length);
221}
222
223// TODO(marq): Add a test to verify that MaybeActivateDataReductionProxy
224// is called when the pref in |settings_| is enabled.
225TEST_F(DataReductionProxySettingsTest, TestMaybeActivateDataReductionProxy) {
226  // Initialize the pref member in |settings_| without the usual callback
227  // so it won't trigger MaybeActivateDataReductionProxy when the pref value
228  // is set.
229  settings_->spdy_proxy_auth_enabled_.Init(
230      prefs::kDataReductionProxyEnabled,
231      settings_->GetOriginalProfilePrefs());
232  settings_->data_reduction_proxy_alternative_enabled_.Init(
233      prefs::kDataReductionProxyAltEnabled,
234      settings_->GetOriginalProfilePrefs());
235
236  // TODO(bengr): Test enabling/disabling while a probe is outstanding.
237  base::MessageLoopForUI loop;
238  // The proxy is enabled and unrestructed initially.
239  // Request succeeded but with bad response, expect proxy to be restricted.
240  CheckProbe(true,
241             kProbeURLWithBadResponse,
242             "Bad",
243             true,
244             true,
245             true,
246             false);
247  // Request succeeded with valid response, expect proxy to be unrestricted.
248  CheckProbe(true,
249             kProbeURLWithOKResponse,
250             "OK",
251             true,
252             true,
253             false,
254             false);
255  // Request failed, expect proxy to be enabled but restricted.
256  CheckProbe(true,
257             kProbeURLWithNoResponse,
258             "",
259             false,
260             true,
261             true,
262             false);
263  // The proxy is disabled initially. Probes should not be emitted to change
264  // state.
265  CheckProbe(false,
266             kProbeURLWithOKResponse,
267             "OK",
268             true,
269             false,
270             false,
271             false);
272}
273
274TEST_F(DataReductionProxySettingsTest, TestOnIPAddressChanged) {
275  base::MessageLoopForUI loop;
276  // The proxy is enabled initially.
277  pref_service_.SetBoolean(prefs::kDataReductionProxyEnabled, true);
278  settings_->spdy_proxy_auth_enabled_.Init(
279      prefs::kDataReductionProxyEnabled,
280      settings_->GetOriginalProfilePrefs());
281  settings_->data_reduction_proxy_alternative_enabled_.Init(
282      prefs::kDataReductionProxyAltEnabled,
283      settings_->GetOriginalProfilePrefs());
284  settings_->enabled_by_user_ = true;
285  settings_->restricted_by_carrier_ = false;
286  settings_->SetProxyConfigs(true, false, false, true);
287  // IP address change triggers a probe that succeeds. Proxy remains
288  // unrestricted.
289  CheckProbeOnIPChange(kProbeURLWithOKResponse,
290                       "OK",
291                       true,
292                       false,
293                       false);
294  // IP address change triggers a probe that fails. Proxy is restricted.
295  CheckProbeOnIPChange(kProbeURLWithBadResponse,
296                       "Bad",
297                       true,
298                       true,
299                       false);
300  // IP address change triggers a probe that fails. Proxy remains restricted.
301  CheckProbeOnIPChange(kProbeURLWithBadResponse,
302                       "Bad",
303                       true,
304                       true,
305                       false);
306  // IP address change triggers a probe that succeeds. Proxy is unrestricted.
307  CheckProbeOnIPChange(kProbeURLWithOKResponse,
308                       "OK",
309                       true,
310                       false,
311                       false);
312  // Simulate a VPN connection. The proxy should be disabled.
313  MockSettings* settings = static_cast<MockSettings*>(settings_.get());
314  settings->network_interfaces_.reset(new net::NetworkInterfaceList());
315  settings->network_interfaces_->push_back(net::NetworkInterface(
316      "tun0", /* network interface name */
317      "tun0", /* network interface friendly name */
318      0,      /* interface index */
319      net::NetworkChangeNotifier::CONNECTION_WIFI,
320      net::IPAddressNumber(),        /* IP address */
321      0,                             /* network prefix */
322      net::IP_ADDRESS_ATTRIBUTE_NONE /* ip address attribute */
323      ));
324  settings_->OnIPAddressChanged();
325  base::MessageLoop::current()->RunUntilIdle();
326  CheckProxyConfigs(false, false, false);
327
328  // Check that the proxy is re-enabled if a non-VPN connection is later used.
329  settings->network_interfaces_.reset(new net::NetworkInterfaceList());
330  settings->network_interfaces_->push_back(net::NetworkInterface(
331      "eth0", /* network interface name */
332      "eth0", /* network interface friendly name */
333      0,      /* interface index */
334      net::NetworkChangeNotifier::CONNECTION_WIFI,
335      net::IPAddressNumber(),
336      0,                             /* network prefix */
337      net::IP_ADDRESS_ATTRIBUTE_NONE /* ip address attribute */
338      ));
339  CheckProbeOnIPChange(kProbeURLWithOKResponse,
340                       "OK",
341                       true,
342                       false,
343                       false);
344}
345
346TEST_F(DataReductionProxySettingsTest, TestOnProxyEnabledPrefChange) {
347  settings_->InitPrefMembers();
348  base::MessageLoopForUI loop;
349  // The proxy is enabled initially.
350  settings_->enabled_by_user_ = true;
351  settings_->SetProxyConfigs(true, false, false, true);
352  // The pref is disabled, so correspondingly should be the proxy.
353  CheckOnPrefChange(false, false, false);
354  // The pref is enabled, so correspondingly should be the proxy.
355  CheckOnPrefChange(true, true, false);
356}
357
358TEST_F(DataReductionProxySettingsTest, TestInitDataReductionProxyOn) {
359  MockSettings* settings = static_cast<MockSettings*>(settings_.get());
360  EXPECT_CALL(*settings, RecordStartupState(PROXY_ENABLED));
361
362  pref_service_.SetBoolean(prefs::kDataReductionProxyEnabled, true);
363  CheckInitDataReductionProxy(true);
364}
365
366TEST_F(DataReductionProxySettingsTest, TestInitDataReductionProxyOff) {
367  // InitDataReductionProxySettings with the preference off will directly call
368  // LogProxyState.
369  MockSettings* settings = static_cast<MockSettings*>(settings_.get());
370  EXPECT_CALL(*settings, RecordStartupState(PROXY_DISABLED));
371
372  pref_service_.SetBoolean(prefs::kDataReductionProxyEnabled, false);
373  CheckInitDataReductionProxy(false);
374}
375
376TEST_F(DataReductionProxySettingsTest, TestEnableProxyFromCommandLine) {
377  MockSettings* settings = static_cast<MockSettings*>(settings_.get());
378  EXPECT_CALL(*settings, RecordStartupState(PROXY_ENABLED));
379
380  CommandLine::ForCurrentProcess()->AppendSwitch(
381      switches::kEnableDataReductionProxy);
382  CheckInitDataReductionProxy(true);
383}
384
385TEST_F(DataReductionProxySettingsTest, TestGetDailyContentLengths) {
386  DataReductionProxySettings::ContentLengthList result =
387      settings_->GetDailyContentLengths(prefs::kDailyHttpOriginalContentLength);
388
389  ASSERT_FALSE(result.empty());
390  ASSERT_EQ(kNumDaysInHistory, result.size());
391
392  for (size_t i = 0; i < kNumDaysInHistory; ++i) {
393    long expected_length =
394        static_cast<long>((kNumDaysInHistory - 1 - i) * 2);
395    ASSERT_EQ(expected_length, result[i]);
396  }
397}
398
399TEST_F(DataReductionProxySettingsTest, CheckInitMetricsWhenNotAllowed) {
400  // No call to |AddProxyToCommandLine()| was made, so the proxy feature
401  // should be unavailable.
402  base::MessageLoopForUI loop;
403  // Clear the command line. Setting flags can force the proxy to be allowed.
404  CommandLine::ForCurrentProcess()->InitFromArgv(0, NULL);
405
406  ResetSettings(false, false, false, false, false);
407  MockSettings* settings = static_cast<MockSettings*>(settings_.get());
408  EXPECT_FALSE(settings->params()->allowed());
409  EXPECT_CALL(*settings, RecordStartupState(PROXY_NOT_AVAILABLE));
410
411  scoped_ptr<DataReductionProxyConfigurator> configurator(
412      new TestDataReductionProxyConfig());
413  settings_->SetProxyConfigurator(configurator.get());
414  scoped_refptr<net::TestURLRequestContextGetter> request_context =
415      new net::TestURLRequestContextGetter(base::MessageLoopProxy::current());
416  settings_->InitDataReductionProxySettings(
417      &pref_service_,
418      request_context.get());
419  settings_->SetOnDataReductionEnabledCallback(
420      base::Bind(&DataReductionProxySettingsTestBase::
421                 RegisterSyntheticFieldTrialCallback,
422                 base::Unretained(this)));
423
424  base::MessageLoop::current()->RunUntilIdle();
425}
426
427}  // namespace data_reduction_proxy
428