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

Side by Side Diff: components/data_reduction_proxy/browser/data_reduction_proxy_settings.cc

Issue 286013002: Added alternative configuration for the data reduction proxy (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: DCHECK fix Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/data_reduction_proxy/browser/data_reduction_proxy_settings. h" 5 #include "components/data_reduction_proxy/browser/data_reduction_proxy_settings. h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/metrics/field_trial.h" 9 #include "base/metrics/field_trial.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
11 #include "base/prefs/pref_member.h" 11 #include "base/prefs/pref_member.h"
12 #include "base/prefs/pref_service.h" 12 #include "base/prefs/pref_service.h"
13 #include "base/prefs/scoped_user_pref_update.h" 13 #include "base/prefs/scoped_user_pref_update.h"
14 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h" 15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h" 16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.h" 17 #include "base/strings/utf_string_conversions.h"
18 #include "components/data_reduction_proxy/browser/data_reduction_proxy_configura tor.h" 18 #include "components/data_reduction_proxy/browser/data_reduction_proxy_configura tor.h"
19 #include "components/data_reduction_proxy/browser/data_reduction_proxy_params.h"
19 #include "components/data_reduction_proxy/common/data_reduction_proxy_pref_names .h" 20 #include "components/data_reduction_proxy/common/data_reduction_proxy_pref_names .h"
20 #include "components/data_reduction_proxy/common/data_reduction_proxy_switches.h " 21 #include "components/data_reduction_proxy/common/data_reduction_proxy_switches.h "
21 #include "crypto/random.h" 22 #include "crypto/random.h"
22 #include "net/base/auth.h" 23 #include "net/base/auth.h"
23 #include "net/base/host_port_pair.h" 24 #include "net/base/host_port_pair.h"
24 #include "net/base/load_flags.h" 25 #include "net/base/load_flags.h"
25 #include "net/base/net_errors.h" 26 #include "net/base/net_errors.h"
26 #include "net/http/http_auth.h" 27 #include "net/http/http_auth.h"
27 #include "net/http/http_auth_cache.h" 28 #include "net/http/http_auth_cache.h"
28 #include "net/http/http_network_session.h" 29 #include "net/http/http_network_session.h"
29 #include "net/http/http_response_headers.h" 30 #include "net/http/http_response_headers.h"
30 #include "net/url_request/url_fetcher.h" 31 #include "net/url_request/url_fetcher.h"
31 #include "net/url_request/url_fetcher_delegate.h" 32 #include "net/url_request/url_fetcher_delegate.h"
32 #include "net/url_request/url_request_context_getter.h" 33 #include "net/url_request/url_request_context_getter.h"
33 #include "net/url_request/url_request_status.h" 34 #include "net/url_request/url_request_status.h"
34 #include "url/gurl.h" 35 #include "url/gurl.h"
35 36
36 using base::FieldTrialList; 37
37 using base::StringPrintf; 38 using base::StringPrintf;
38 39
39 namespace { 40 namespace {
40 41
41 // Key of the UMA DataReductionProxy.StartupState histogram. 42 // Key of the UMA DataReductionProxy.StartupState histogram.
42 const char kUMAProxyStartupStateHistogram[] = 43 const char kUMAProxyStartupStateHistogram[] =
43 "DataReductionProxy.StartupState"; 44 "DataReductionProxy.StartupState";
44 45
45 // Key of the UMA DataReductionProxy.ProbeURL histogram. 46 // Key of the UMA DataReductionProxy.ProbeURL histogram.
46 const char kUMAProxyProbeURL[] = "DataReductionProxy.ProbeURL"; 47 const char kUMAProxyProbeURL[] = "DataReductionProxy.ProbeURL";
47 48
48 const char kEnabled[] = "Enabled";
49
50 // TODO(marq): Factor this string out into a constant here and in 49 // TODO(marq): Factor this string out into a constant here and in
51 // http_auth_handler_spdyproxy. 50 // http_auth_handler_spdyproxy.
52 const char kAuthenticationRealmName[] = "SpdyProxy"; 51 const char kAuthenticationRealmName[] = "SpdyProxy";
53 52
54 int64 GetInt64PrefValue(const base::ListValue& list_value, size_t index) { 53 int64 GetInt64PrefValue(const base::ListValue& list_value, size_t index) {
55 int64 val = 0; 54 int64 val = 0;
56 std::string pref_value; 55 std::string pref_value;
57 bool rv = list_value.GetString(index, &pref_value); 56 bool rv = list_value.GetString(index, &pref_value);
58 DCHECK(rv); 57 DCHECK(rv);
59 if (rv) { 58 if (rv) {
60 rv = base::StringToInt64(pref_value, &val); 59 rv = base::StringToInt64(pref_value, &val);
61 DCHECK(rv); 60 DCHECK(rv);
62 } 61 }
63 return val; 62 return val;
64 } 63 }
65 64
66 } // namespace 65 } // namespace
67 66
68 namespace data_reduction_proxy { 67 namespace data_reduction_proxy {
69 68
70 bool DataReductionProxySettings::allowed_; 69 DataReductionProxySettings::DataReductionProxySettings(
71 bool DataReductionProxySettings::promo_allowed_; 70 DataReductionProxyParams* params)
72
73 // static
74 bool DataReductionProxySettings::IsProxyOriginSetOnCommandLine() {
75 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
76 return command_line.HasSwitch(
77 data_reduction_proxy::switches::kDataReductionProxy);
78 }
79
80 // static
81 bool DataReductionProxySettings::IsProxyKeySetOnCommandLine() {
82 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
83 return command_line.HasSwitch(
84 data_reduction_proxy::switches::kEnableDataReductionProxy);
85 }
86
87 // static
88 bool DataReductionProxySettings::IsIncludedInFieldTrialOrFlags() {
89 return (base::FieldTrialList::FindFullName(
90 "DataCompressionProxyRollout") == kEnabled ||
91 IsProxyOriginSetOnCommandLine());
92 }
93
94 // static
95 void DataReductionProxySettings::SetAllowed(bool allowed) {
96 allowed_ = allowed;
97 }
98
99 // static
100 void DataReductionProxySettings::SetPromoAllowed(bool promo_allowed) {
101 promo_allowed_ = promo_allowed;
102 }
103
104 DataReductionProxySettings::DataReductionProxySettings()
105 : restricted_by_carrier_(false), 71 : restricted_by_carrier_(false),
106 enabled_by_user_(false), 72 enabled_by_user_(false),
107 prefs_(NULL), 73 prefs_(NULL),
108 local_state_prefs_(NULL), 74 local_state_prefs_(NULL),
109 url_request_context_getter_(NULL), 75 url_request_context_getter_(NULL) {
110 fallback_allowed_(true) { 76 DCHECK(params);
77 params_.reset(params);
111 } 78 }
112 79
113 DataReductionProxySettings::~DataReductionProxySettings() { 80 DataReductionProxySettings::~DataReductionProxySettings() {
114 if (IsDataReductionProxyAllowed()) 81 if (params_->allowed())
115 spdy_proxy_auth_enabled_.Destroy(); 82 spdy_proxy_auth_enabled_.Destroy();
116 } 83 }
117 84
118 void DataReductionProxySettings::InitPrefMembers() { 85 void DataReductionProxySettings::InitPrefMembers() {
119 DCHECK(thread_checker_.CalledOnValidThread()); 86 DCHECK(thread_checker_.CalledOnValidThread());
120 spdy_proxy_auth_enabled_.Init( 87 spdy_proxy_auth_enabled_.Init(
121 prefs::kDataReductionProxyEnabled, 88 prefs::kDataReductionProxyEnabled,
122 GetOriginalProfilePrefs(), 89 GetOriginalProfilePrefs(),
123 base::Bind(&DataReductionProxySettings::OnProxyEnabledPrefChange, 90 base::Bind(&DataReductionProxySettings::OnProxyEnabledPrefChange,
124 base::Unretained(this))); 91 base::Unretained(this)));
92 data_reduction_proxy_alternative_enabled_.Init(
93 prefs::kDataReductionProxyAltEnabled,
94 GetOriginalProfilePrefs(),
95 base::Bind(
96 &DataReductionProxySettings::OnProxyAlternativeEnabledPrefChange,
97 base::Unretained(this)));
125 } 98 }
126 99
127 void DataReductionProxySettings::InitDataReductionProxySettings( 100 void DataReductionProxySettings::InitDataReductionProxySettings(
128 PrefService* prefs, 101 PrefService* prefs,
129 PrefService* local_state_prefs, 102 PrefService* local_state_prefs,
130 net::URLRequestContextGetter* url_request_context_getter) { 103 net::URLRequestContextGetter* url_request_context_getter) {
131 DCHECK(thread_checker_.CalledOnValidThread()); 104 DCHECK(thread_checker_.CalledOnValidThread());
132 DCHECK(prefs); 105 DCHECK(prefs);
133 DCHECK(local_state_prefs); 106 DCHECK(local_state_prefs);
134 DCHECK(url_request_context_getter); 107 DCHECK(url_request_context_getter);
135 prefs_ = prefs; 108 prefs_ = prefs;
136 local_state_prefs_ = local_state_prefs; 109 local_state_prefs_ = local_state_prefs;
137 url_request_context_getter_ = url_request_context_getter; 110 url_request_context_getter_ = url_request_context_getter;
138 InitPrefMembers(); 111 InitPrefMembers();
139 RecordDataReductionInit(); 112 RecordDataReductionInit();
140 113
141 // Disable the proxy if it is not allowed to be used. 114 // Disable the proxy if it is not allowed to be used.
142 if (!IsDataReductionProxyAllowed()) 115 if (!params_->allowed())
143 return; 116 return;
144 117
145 AddDefaultProxyBypassRules(); 118 AddDefaultProxyBypassRules();
146 net::NetworkChangeNotifier::AddIPAddressObserver(this); 119 net::NetworkChangeNotifier::AddIPAddressObserver(this);
147 120
148 // We set or reset the proxy pref at startup. 121 // We set or reset the proxy pref at startup.
149 MaybeActivateDataReductionProxy(true); 122 MaybeActivateDataReductionProxy(true);
150 } 123 }
151 124
152 void DataReductionProxySettings::InitDataReductionProxySettings( 125 void DataReductionProxySettings::InitDataReductionProxySettings(
153 PrefService* prefs, 126 PrefService* prefs,
154 PrefService* local_state_prefs, 127 PrefService* local_state_prefs,
155 net::URLRequestContextGetter* url_request_context_getter, 128 net::URLRequestContextGetter* url_request_context_getter,
156 scoped_ptr<DataReductionProxyConfigurator> config) { 129 scoped_ptr<DataReductionProxyConfigurator> configurator) {
157 InitDataReductionProxySettings(prefs, 130 InitDataReductionProxySettings(prefs,
158 local_state_prefs, 131 local_state_prefs,
159 url_request_context_getter); 132 url_request_context_getter);
160 SetProxyConfigurator(config.Pass()); 133 SetProxyConfigurator(configurator.Pass());
161 } 134 }
162 135
163 void DataReductionProxySettings::SetProxyConfigurator( 136 void DataReductionProxySettings::SetProxyConfigurator(
164 scoped_ptr<DataReductionProxyConfigurator> configurator) { 137 scoped_ptr<DataReductionProxyConfigurator> configurator) {
165 DCHECK(configurator); 138 DCHECK(configurator);
166 config_ = configurator.Pass(); 139 configurator_ = configurator.Pass();
167 } 140 }
168 141
169 // static 142 // static
170 void DataReductionProxySettings::InitDataReductionProxySession( 143 void DataReductionProxySettings::InitDataReductionProxySession(
171 net::HttpNetworkSession* session, 144 net::HttpNetworkSession* session,
172 const std::string& key) { 145 const DataReductionProxyParams* params) {
173 // This is a no-op unless the key is set. (even though values for them may be 146 // This is a no-op unless the authentication parameters are compiled in.
174 // specified on the command line). Authentication will still work if the 147 // (even though values for them may be specified on the command line).
175 // command line parameters are used, however there will be a round-trip 148 // Authentication will still work if the command line parameters are used,
176 // overhead for each challenge/response (typically once per session). 149 // however there will be a round-trip overhead for each challenge/response
177 // TODO(bengr):Pass a configuration struct into 150 // (typically once per session).
178 // DataReductionProxyConfigurator's constructor. 151 // TODO(bengr):Pass a configuration struct into DataReductionProxyConfigurator's
179 if (key.empty()) 152 // constructor. The struct would carry everything in the preprocessor flags.
180 return;
181 DCHECK(session); 153 DCHECK(session);
182 net::HttpAuthCache* auth_cache = session->http_auth_cache(); 154 net::HttpAuthCache* auth_cache = session->http_auth_cache();
183 DCHECK(auth_cache); 155 DCHECK(auth_cache);
184 InitDataReductionAuthentication(auth_cache, key); 156 InitDataReductionAuthentication(auth_cache, params);
185 } 157 }
186 158
187 // static 159 // static
188 void DataReductionProxySettings::InitDataReductionAuthentication( 160 void DataReductionProxySettings::InitDataReductionAuthentication(
189 net::HttpAuthCache* auth_cache, 161 net::HttpAuthCache* auth_cache,
190 const std::string& key) { 162 const DataReductionProxyParams* params) {
191 DCHECK(auth_cache); 163 DCHECK(auth_cache);
164 DCHECK(params);
192 int64 timestamp = 165 int64 timestamp =
193 (base::Time::Now() - base::Time::UnixEpoch()).InMilliseconds() / 1000; 166 (base::Time::Now() - base::Time::UnixEpoch()).InMilliseconds() / 1000;
194 167
195 DataReductionProxyList proxies = GetDataReductionProxies(); 168 DataReductionProxyParams::DataReductionProxyList proxies =
196 for (DataReductionProxyList::iterator it = proxies.begin(); 169 params->GetAllowedProxies();
197 it != proxies.end(); ++it) { 170 for (DataReductionProxyParams::DataReductionProxyList::iterator it =
171 proxies.begin();
172 it != proxies.end(); ++it) {
198 GURL auth_origin = (*it).GetOrigin(); 173 GURL auth_origin = (*it).GetOrigin();
174
199 int32 rand[3]; 175 int32 rand[3];
200 crypto::RandBytes(rand, 3 * sizeof(rand[0])); 176 crypto::RandBytes(rand, 3 * sizeof(rand[0]));
201 177
202 std::string realm = 178 std::string realm =
203 base::StringPrintf("%s%lld", kAuthenticationRealmName, 179 base::StringPrintf("%s%lld", kAuthenticationRealmName,
204 static_cast<long long>(timestamp)); 180 static_cast<long long>(timestamp));
205 std::string challenge = base::StringPrintf( 181 std::string challenge = base::StringPrintf(
206 "%s realm=\"%s\", ps=\"%lld-%u-%u-%u\"", 182 "%s realm=\"%s\", ps=\"%lld-%u-%u-%u\"",
207 kAuthenticationRealmName, 183 kAuthenticationRealmName,
208 realm.data(), 184 realm.data(),
209 static_cast<long long>(timestamp), 185 static_cast<long long>(timestamp),
210 rand[0], 186 rand[0],
211 rand[1], 187 rand[1],
212 rand[2]); 188 rand[2]);
213 base::string16 password = AuthHashForSalt(timestamp, key); 189 base::string16 password = AuthHashForSalt(timestamp, params->key());
214 190
215 DVLOG(1) << "origin: [" << auth_origin << "] realm: [" << realm 191 DVLOG(1) << "origin: [" << auth_origin << "] realm: [" << realm
216 << "] challenge: [" << challenge << "] password: [" << password << "]"; 192 << "] challenge: [" << challenge << "] password: [" << password << "]";
217 193
218 net::AuthCredentials credentials(base::string16(), password); 194 net::AuthCredentials credentials(base::string16(), password);
219 // |HttpAuthController| searches this cache by origin and path, the latter 195 // |HttpAuthController| searches this cache by origin and path, the latter
220 // being '/' in the case of the data reduction proxy. 196 // being '/' in the case of the data reduction proxy.
221 auth_cache->Add(auth_origin, 197 auth_cache->Add(auth_origin,
222 realm, 198 realm,
223 net::HttpAuth::AUTH_SCHEME_SPDYPROXY, 199 net::HttpAuth::AUTH_SCHEME_SPDYPROXY,
224 challenge, 200 challenge,
225 credentials, 201 credentials,
226 std::string("/")); 202 std::string("/"));
227 } 203 }
228 } 204 }
229 205
230 // TODO(bengr): Use a configuration struct to carry field trial state as well.
231 // static
232 bool DataReductionProxySettings::IsDataReductionProxyAllowed() {
233 return allowed_;
234 }
235
236 // static
237 bool DataReductionProxySettings::IsDataReductionProxyPromoAllowed() {
238 return IsProxyOriginSetOnCommandLine() ||
239 (IsDataReductionProxyAllowed() && promo_allowed_);
240 }
241
242 // static
243 bool DataReductionProxySettings::IsPreconnectHintingAllowed() {
244 if (!IsDataReductionProxyAllowed())
245 return false;
246 return FieldTrialList::FindFullName("DataCompressionProxyPreconnectHints") ==
247 kEnabled;
248 }
249
250 // static
251 std::string DataReductionProxySettings::GetDataReductionProxyOrigin() {
252 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
253 if (command_line.HasSwitch(switches::kDataReductionProxyDev))
254 return command_line.GetSwitchValueASCII(switches::kDataReductionProxyDev);
255 if (command_line.HasSwitch(switches::kDataReductionProxy))
256 return command_line.GetSwitchValueASCII(switches::kDataReductionProxy);
257 #if defined(DATA_REDUCTION_DEV_HOST)
258 if (FieldTrialList::FindFullName("DataCompressionProxyDevRollout") ==
259 kEnabled) {
260 return DATA_REDUCTION_DEV_HOST;
261 }
262 #endif
263 #if defined(SPDY_PROXY_AUTH_ORIGIN)
264 return SPDY_PROXY_AUTH_ORIGIN;
265 #else
266 return std::string();
267 #endif
268 }
269
270 // static
271 std::string DataReductionProxySettings::GetDataReductionProxyFallback() {
272 // Regardless of what else is defined, only return a value if the main proxy
273 // origin is defined.
274 if (GetDataReductionProxyOrigin().empty())
275 return std::string();
276 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
277 if (command_line.HasSwitch(switches::kDataReductionProxyFallback)) {
278 return command_line.GetSwitchValueASCII(
279 switches::kDataReductionProxyFallback);
280 }
281 #if defined(DATA_REDUCTION_FALLBACK_HOST)
282 return DATA_REDUCTION_FALLBACK_HOST;
283 #else
284 return std::string();
285 #endif
286 }
287
288 // static
289 bool DataReductionProxySettings::IsAcceptableAuthChallenge( 206 bool DataReductionProxySettings::IsAcceptableAuthChallenge(
290 net::AuthChallengeInfo* auth_info) { 207 net::AuthChallengeInfo* auth_info) {
291 // Challenge realm must start with the authentication realm name. 208 // Challenge realm must start with the authentication realm name.
292 std::string realm_prefix = 209 std::string realm_prefix =
293 auth_info->realm.substr(0, strlen(kAuthenticationRealmName)); 210 auth_info->realm.substr(0, strlen(kAuthenticationRealmName));
294 if (realm_prefix != kAuthenticationRealmName) 211 if (realm_prefix != kAuthenticationRealmName)
295 return false; 212 return false;
296 213
297 // The challenger must be one of the configured proxies. 214 // The challenger must be one of the configured proxies.
298 DataReductionProxyList proxies = GetDataReductionProxies(); 215 DataReductionProxyParams::DataReductionProxyList proxies =
299 for (DataReductionProxyList::iterator it = proxies.begin(); 216 params_->GetAllowedProxies();
217 for (DataReductionProxyParams::DataReductionProxyList::iterator it =
218 proxies.begin();
300 it != proxies.end(); ++it) { 219 it != proxies.end(); ++it) {
301 net::HostPortPair origin_host = net::HostPortPair::FromURL(*it); 220 net::HostPortPair origin_host = net::HostPortPair::FromURL(*it);
302 if (origin_host.Equals(auth_info->challenger)) 221 if (origin_host.Equals(auth_info->challenger))
303 return true; 222 return true;
304 } 223 }
305 return false; 224 return false;
306 } 225 }
307 226
308 base::string16 DataReductionProxySettings::GetTokenForAuthChallenge( 227 base::string16 DataReductionProxySettings::GetTokenForAuthChallenge(
309 net::AuthChallengeInfo* auth_info) { 228 net::AuthChallengeInfo* auth_info) {
310 if (auth_info->realm.length() > strlen(kAuthenticationRealmName)) { 229 if (auth_info->realm.length() > strlen(kAuthenticationRealmName)) {
311 int64 salt; 230 int64 salt;
312 std::string realm_suffix = 231 std::string realm_suffix =
313 auth_info->realm.substr(strlen(kAuthenticationRealmName)); 232 auth_info->realm.substr(strlen(kAuthenticationRealmName));
314 if (base::StringToInt64(realm_suffix, &salt)) { 233 if (base::StringToInt64(realm_suffix, &salt)) {
315 return AuthHashForSalt(salt, key_); 234 return AuthHashForSalt(salt, params_->key());
316 } else { 235 } else {
317 DVLOG(1) << "Unable to parse realm name " << auth_info->realm 236 DVLOG(1) << "Unable to parse realm name " << auth_info->realm
318 << "into an int for salting."; 237 << "into an int for salting.";
319 return base::string16(); 238 return base::string16();
320 } 239 }
321 } else { 240 } else {
322 return base::string16(); 241 return base::string16();
323 } 242 }
324 } 243 }
325 244
326 bool DataReductionProxySettings::IsDataReductionProxyEnabled() { 245 bool DataReductionProxySettings::IsDataReductionProxyEnabled() {
327 return spdy_proxy_auth_enabled_.GetValue() || 246 return spdy_proxy_auth_enabled_.GetValue() ||
328 IsProxyKeySetOnCommandLine(); 247 DataReductionProxyParams::IsKeySetOnCommandLine();
248 }
249
250 bool DataReductionProxySettings::IsDataReductionProxyAlternativeEnabled() {
251 return data_reduction_proxy_alternative_enabled_.GetValue();
329 } 252 }
330 253
331 bool DataReductionProxySettings::IsDataReductionProxyManaged() { 254 bool DataReductionProxySettings::IsDataReductionProxyManaged() {
332 return spdy_proxy_auth_enabled_.IsManaged(); 255 return spdy_proxy_auth_enabled_.IsManaged();
333 } 256 }
334 257
335 // static
336 DataReductionProxySettings::DataReductionProxyList
337 DataReductionProxySettings::GetDataReductionProxies() {
338 DataReductionProxyList proxies;
339 std::string proxy = GetDataReductionProxyOrigin();
340 std::string fallback = GetDataReductionProxyFallback();
341
342 if (!proxy.empty())
343 proxies.push_back(GURL(proxy));
344
345 if (!fallback.empty()) {
346 // Sanity check: fallback isn't the only proxy.
347 DCHECK(!proxies.empty());
348 proxies.push_back(GURL(fallback));
349 }
350
351 return proxies;
352 }
353
354 void DataReductionProxySettings::SetDataReductionProxyEnabled(bool enabled) { 258 void DataReductionProxySettings::SetDataReductionProxyEnabled(bool enabled) {
355 DCHECK(thread_checker_.CalledOnValidThread()); 259 DCHECK(thread_checker_.CalledOnValidThread());
356 // Prevent configuring the proxy when it is not allowed to be used. 260 // Prevent configuring the proxy when it is not allowed to be used.
357 if (!IsDataReductionProxyAllowed()) 261 if (!params_->allowed())
358 return; 262 return;
359 263
360 if (spdy_proxy_auth_enabled_.GetValue() != enabled) { 264 if (spdy_proxy_auth_enabled_.GetValue() != enabled) {
361 spdy_proxy_auth_enabled_.SetValue(enabled); 265 spdy_proxy_auth_enabled_.SetValue(enabled);
362 OnProxyEnabledPrefChange(); 266 OnProxyEnabledPrefChange();
363 } 267 }
364 } 268 }
365 269
270 void DataReductionProxySettings::SetDataReductionProxyAlternativeEnabled(
271 bool enabled) {
272 DCHECK(thread_checker_.CalledOnValidThread());
273 // Prevent configuring the proxy when it is not allowed to be used.
274 if (!params_->alternative_allowed())
275 return;
276 if (data_reduction_proxy_alternative_enabled_.GetValue() != enabled) {
277 data_reduction_proxy_alternative_enabled_.SetValue(enabled);
278 OnProxyAlternativeEnabledPrefChange();
279 }
280 }
281
366 int64 DataReductionProxySettings::GetDataReductionLastUpdateTime() { 282 int64 DataReductionProxySettings::GetDataReductionLastUpdateTime() {
367 DCHECK(thread_checker_.CalledOnValidThread()); 283 DCHECK(thread_checker_.CalledOnValidThread());
368 PrefService* local_state = GetLocalStatePrefs(); 284 PrefService* local_state = GetLocalStatePrefs();
369 int64 last_update_internal = 285 int64 last_update_internal =
370 local_state->GetInt64(prefs::kDailyHttpContentLengthLastUpdateDate); 286 local_state->GetInt64(prefs::kDailyHttpContentLengthLastUpdateDate);
371 base::Time last_update = base::Time::FromInternalValue(last_update_internal); 287 base::Time last_update = base::Time::FromInternalValue(last_update_internal);
372 return static_cast<int64>(last_update.ToJsTime()); 288 return static_cast<int64>(last_update.ToJsTime());
373 } 289 }
374 290
375 DataReductionProxySettings::ContentLengthList 291 DataReductionProxySettings::ContentLengthList
(...skipping 24 matching lines...) Expand all
400 if ("OK" == response.substr(0, 2)) { 316 if ("OK" == response.substr(0, 2)) {
401 DVLOG(1) << "The data reduction proxy is unrestricted."; 317 DVLOG(1) << "The data reduction proxy is unrestricted.";
402 318
403 if (enabled_by_user_) { 319 if (enabled_by_user_) {
404 if (restricted_by_carrier_) { 320 if (restricted_by_carrier_) {
405 // The user enabled the proxy, but sometime previously in the session, 321 // The user enabled the proxy, but sometime previously in the session,
406 // the network operator had blocked the canary and restricted the user. 322 // the network operator had blocked the canary and restricted the user.
407 // The current network doesn't block the canary, so don't restrict the 323 // The current network doesn't block the canary, so don't restrict the
408 // proxy configurations. 324 // proxy configurations.
409 SetProxyConfigs(true /* enabled */, 325 SetProxyConfigs(true /* enabled */,
326 IsDataReductionProxyAlternativeEnabled(),
410 false /* restricted */, 327 false /* restricted */,
411 false /* at_startup */); 328 false /* at_startup */);
412 RecordProbeURLFetchResult(SUCCEEDED_PROXY_ENABLED); 329 RecordProbeURLFetchResult(SUCCEEDED_PROXY_ENABLED);
413 } else { 330 } else {
414 RecordProbeURLFetchResult(SUCCEEDED_PROXY_ALREADY_ENABLED); 331 RecordProbeURLFetchResult(SUCCEEDED_PROXY_ALREADY_ENABLED);
415 } 332 }
416 } 333 }
417 restricted_by_carrier_ = false; 334 restricted_by_carrier_ = false;
418 return; 335 return;
419 } 336 }
420 DVLOG(1) << "The data reduction proxy is restricted to the configured " 337 DVLOG(1) << "The data reduction proxy is restricted to the configured "
421 << "fallback proxy."; 338 << "fallback proxy.";
422 if (enabled_by_user_) { 339 if (enabled_by_user_) {
423 if (!restricted_by_carrier_) { 340 if (!restricted_by_carrier_) {
424 // Restrict the proxy. 341 // Restrict the proxy.
425 SetProxyConfigs(true /* enabled */, 342 SetProxyConfigs(true /* enabled */,
343 IsDataReductionProxyAlternativeEnabled(),
426 true /* restricted */, 344 true /* restricted */,
427 false /* at_startup */); 345 false /* at_startup */);
428 RecordProbeURLFetchResult(FAILED_PROXY_DISABLED); 346 RecordProbeURLFetchResult(FAILED_PROXY_DISABLED);
429 } else { 347 } else {
430 RecordProbeURLFetchResult(FAILED_PROXY_ALREADY_DISABLED); 348 RecordProbeURLFetchResult(FAILED_PROXY_ALREADY_DISABLED);
431 } 349 }
432 } 350 }
433 restricted_by_carrier_ = true; 351 restricted_by_carrier_ = true;
434 } 352 }
435 353
436 void DataReductionProxySettings::OnIPAddressChanged() { 354 PrefService* DataReductionProxySettings::GetOriginalProfilePrefs() {
437 DCHECK(thread_checker_.CalledOnValidThread()); 355 DCHECK(thread_checker_.CalledOnValidThread());
438 if (enabled_by_user_) { 356 return prefs_;
439 DCHECK(IsDataReductionProxyAllowed());
440 ProbeWhetherDataReductionProxyIsAvailable();
441 }
442 } 357 }
443 358
444 void DataReductionProxySettings::OnProxyEnabledPrefChange() { 359 PrefService* DataReductionProxySettings::GetLocalStatePrefs() {
445 DCHECK(thread_checker_.CalledOnValidThread()); 360 DCHECK(thread_checker_.CalledOnValidThread());
446 if (!DataReductionProxySettings::IsDataReductionProxyAllowed()) 361 return local_state_prefs_;
447 return;
448 MaybeActivateDataReductionProxy(false);
449 } 362 }
450 363
451 void DataReductionProxySettings::AddDefaultProxyBypassRules() { 364 void DataReductionProxySettings::AddDefaultProxyBypassRules() {
452 // localhost 365 // localhost
453 config_->AddHostPatternToBypass("<local>"); 366 configurator_->AddHostPatternToBypass("<local>");
454 // RFC1918 private addresses. 367 // RFC1918 private addresses.
455 config_->AddHostPatternToBypass("10.0.0.0/8"); 368 configurator_->AddHostPatternToBypass("10.0.0.0/8");
456 config_->AddHostPatternToBypass("172.16.0.0/12"); 369 configurator_->AddHostPatternToBypass("172.16.0.0/12");
457 config_->AddHostPatternToBypass("192.168.0.0/16"); 370 configurator_->AddHostPatternToBypass("192.168.0.0/16");
458 // RFC4193 private addresses. 371 // RFC4193 private addresses.
459 config_->AddHostPatternToBypass("fc00::/7"); 372 configurator_->AddHostPatternToBypass("fc00::/7");
460 // IPV6 probe addresses. 373 // IPV6 probe addresses.
461 config_->AddHostPatternToBypass("*-ds.metric.gstatic.com"); 374 configurator_->AddHostPatternToBypass("*-ds.metric.gstatic.com");
462 config_->AddHostPatternToBypass("*-v4.metric.gstatic.com"); 375 configurator_->AddHostPatternToBypass("*-v4.metric.gstatic.com");
463 } 376 }
464 377
465 void DataReductionProxySettings::LogProxyState( 378 void DataReductionProxySettings::LogProxyState(
466 bool enabled, bool restricted, bool at_startup) { 379 bool enabled, bool restricted, bool at_startup) {
467 // This must stay a LOG(WARNING); the output is used in processing customer 380 // This must stay a LOG(WARNING); the output is used in processing customer
468 // feedback. 381 // feedback.
469 const char kAtStartup[] = "at startup"; 382 const char kAtStartup[] = "at startup";
470 const char kByUser[] = "by user action"; 383 const char kByUser[] = "by user action";
471 const char kOn[] = "ON"; 384 const char kOn[] = "ON";
472 const char kOff[] = "OFF"; 385 const char kOff[] = "OFF";
473 const char kRestricted[] = "(Restricted)"; 386 const char kRestricted[] = "(Restricted)";
474 const char kUnrestricted[] = "(Unrestricted)"; 387 const char kUnrestricted[] = "(Unrestricted)";
475 388
476 std::string annotated_on = 389 std::string annotated_on =
477 kOn + std::string(" ") + (restricted ? kRestricted : kUnrestricted); 390 kOn + std::string(" ") + (restricted ? kRestricted : kUnrestricted);
478 391
479 LOG(WARNING) << "SPDY proxy " << (enabled ? annotated_on : kOff) 392 LOG(WARNING) << "SPDY proxy " << (enabled ? annotated_on : kOff)
480 << " " << (at_startup ? kAtStartup : kByUser); 393 << " " << (at_startup ? kAtStartup : kByUser);
481 } 394 }
482 395
483 PrefService* DataReductionProxySettings::GetOriginalProfilePrefs() { 396 void DataReductionProxySettings::OnIPAddressChanged() {
484 DCHECK(thread_checker_.CalledOnValidThread()); 397 DCHECK(thread_checker_.CalledOnValidThread());
485 return prefs_; 398 if (enabled_by_user_) {
399 DCHECK(params_->allowed());
400 ProbeWhetherDataReductionProxyIsAvailable();
401 }
486 } 402 }
487 403
488 PrefService* DataReductionProxySettings::GetLocalStatePrefs() { 404 void DataReductionProxySettings::OnProxyEnabledPrefChange() {
489 DCHECK(thread_checker_.CalledOnValidThread()); 405 DCHECK(thread_checker_.CalledOnValidThread());
490 return local_state_prefs_; 406 if (!params_->allowed())
407 return;
408 MaybeActivateDataReductionProxy(false);
409 }
410
411 void DataReductionProxySettings::OnProxyAlternativeEnabledPrefChange() {
412 DCHECK(thread_checker_.CalledOnValidThread());
413 if (!params_->alternative_allowed())
414 return;
415 MaybeActivateDataReductionProxy(false);
491 } 416 }
492 417
493 void DataReductionProxySettings::ResetDataReductionStatistics() { 418 void DataReductionProxySettings::ResetDataReductionStatistics() {
494 DCHECK(thread_checker_.CalledOnValidThread()); 419 DCHECK(thread_checker_.CalledOnValidThread());
495 PrefService* prefs = GetLocalStatePrefs(); 420 PrefService* prefs = GetLocalStatePrefs();
496 if (!prefs) 421 if (!prefs)
497 return; 422 return;
498 ListPrefUpdate original_update(prefs, prefs::kDailyHttpOriginalContentLength); 423 ListPrefUpdate original_update(prefs, prefs::kDailyHttpOriginalContentLength);
499 ListPrefUpdate received_update(prefs, prefs::kDailyHttpReceivedContentLength); 424 ListPrefUpdate received_update(prefs, prefs::kDailyHttpReceivedContentLength);
500 original_update->Clear(); 425 original_update->Clear();
501 received_update->Clear(); 426 received_update->Clear();
502 for (size_t i = 0; i < kNumDaysInHistory; ++i) { 427 for (size_t i = 0; i < kNumDaysInHistory; ++i) {
503 original_update->AppendString(base::Int64ToString(0)); 428 original_update->AppendString(base::Int64ToString(0));
504 received_update->AppendString(base::Int64ToString(0)); 429 received_update->AppendString(base::Int64ToString(0));
505 } 430 }
506 } 431 }
507 432
508 void DataReductionProxySettings::MaybeActivateDataReductionProxy( 433 void DataReductionProxySettings::MaybeActivateDataReductionProxy(
509 bool at_startup) { 434 bool at_startup) {
510 DCHECK(thread_checker_.CalledOnValidThread()); 435 DCHECK(thread_checker_.CalledOnValidThread());
511 PrefService* prefs = GetOriginalProfilePrefs(); 436 PrefService* prefs = GetOriginalProfilePrefs();
512 // TODO(marq): Consider moving this so stats are wiped the first time the 437 // TODO(marq): Consider moving this so stats are wiped the first time the
513 // proxy settings are actually (not maybe) turned on. 438 // proxy settings are actually (not maybe) turned on.
514 if (spdy_proxy_auth_enabled_.GetValue() && 439 if (spdy_proxy_auth_enabled_.GetValue() &&
515 !prefs->GetBoolean(prefs::kDataReductionProxyWasEnabledBefore)) { 440 !prefs->GetBoolean(prefs::kDataReductionProxyWasEnabledBefore)) {
516 prefs->SetBoolean(prefs::kDataReductionProxyWasEnabledBefore, true); 441 prefs->SetBoolean(prefs::kDataReductionProxyWasEnabledBefore, true);
517 ResetDataReductionStatistics(); 442 ResetDataReductionStatistics();
518 } 443 }
519 444
520 std::string proxy = GetDataReductionProxyOrigin(); 445 // Configure use of the data reduction proxy if it is enabled.
521 // Configure use of the data reduction proxy if it is enabled and the proxy 446 enabled_by_user_= IsDataReductionProxyEnabled();
522 // origin is non-empty. 447 SetProxyConfigs(enabled_by_user_,
523 enabled_by_user_= IsDataReductionProxyEnabled() && !proxy.empty(); 448 IsDataReductionProxyAlternativeEnabled(),
524 SetProxyConfigs(enabled_by_user_, restricted_by_carrier_, at_startup); 449 restricted_by_carrier_,
450 at_startup);
525 451
526 // Check if the proxy has been restricted explicitly by the carrier. 452 // Check if the proxy has been restricted explicitly by the carrier.
527 if (enabled_by_user_) 453 if (enabled_by_user_)
528 ProbeWhetherDataReductionProxyIsAvailable(); 454 ProbeWhetherDataReductionProxyIsAvailable();
529 } 455 }
530 456
531 void DataReductionProxySettings::SetProxyConfigs( 457 void DataReductionProxySettings::SetProxyConfigs(bool enabled,
532 bool enabled, bool restricted, bool at_startup) { 458 bool alternative_enabled,
459 bool restricted,
460 bool at_startup) {
533 DCHECK(thread_checker_.CalledOnValidThread()); 461 DCHECK(thread_checker_.CalledOnValidThread());
534 // If |restricted| is true and there is no defined fallback proxy.
535 // treat this as a disable.
536 std::string fallback = GetDataReductionProxyFallback();
537 if (fallback.empty() && enabled && restricted)
538 enabled = false;
539
540 LogProxyState(enabled, restricted, at_startup); 462 LogProxyState(enabled, restricted, at_startup);
463 // The alternative is only configured if the standard configuration is
464 // is enabled.
541 if (enabled) { 465 if (enabled) {
542 config_->Enable(restricted, 466 if (alternative_enabled) {
543 !fallback_allowed_, 467 configurator_->Enable(restricted,
544 GetDataReductionProxyOrigin(), 468 !params_->fallback_allowed(),
545 fallback); 469 params_->alt_origin().spec(),
470 params_->alt_fallback_origin().spec(),
471 params_->ssl_origin().spec());
472 } else {
473 configurator_->Enable(restricted,
474 !params_->fallback_allowed(),
475 params_->origin().spec(),
476 params_->fallback_origin().spec(),
477 std::string());
478 }
546 } else { 479 } else {
547 config_->Disable(); 480 configurator_->Disable();
548 } 481 }
549 } 482 }
550 483
551 // Metrics methods 484 // Metrics methods
552 void DataReductionProxySettings::RecordDataReductionInit() { 485 void DataReductionProxySettings::RecordDataReductionInit() {
553 DCHECK(thread_checker_.CalledOnValidThread()); 486 DCHECK(thread_checker_.CalledOnValidThread());
554 ProxyStartupState state = PROXY_NOT_AVAILABLE; 487 ProxyStartupState state = PROXY_NOT_AVAILABLE;
555 if (IsDataReductionProxyAllowed()) { 488 if (params_->allowed()) {
556 if (IsDataReductionProxyEnabled()) 489 if (IsDataReductionProxyEnabled())
557 state = PROXY_ENABLED; 490 state = PROXY_ENABLED;
558 else 491 else
559 state = PROXY_DISABLED; 492 state = PROXY_DISABLED;
560 } 493 }
561 494
562 RecordStartupState(state); 495 RecordStartupState(state);
563 } 496 }
564 497
565 void DataReductionProxySettings::RecordProbeURLFetchResult( 498 void DataReductionProxySettings::RecordProbeURLFetchResult(
566 ProbeURLFetchResult result) { 499 ProbeURLFetchResult result) {
567 UMA_HISTOGRAM_ENUMERATION(kUMAProxyProbeURL, 500 UMA_HISTOGRAM_ENUMERATION(kUMAProxyProbeURL,
568 result, 501 result,
569 PROBE_URL_FETCH_RESULT_COUNT); 502 PROBE_URL_FETCH_RESULT_COUNT);
570 } 503 }
571 504
572 void DataReductionProxySettings::RecordStartupState(ProxyStartupState state) { 505 void DataReductionProxySettings::RecordStartupState(ProxyStartupState state) {
573 UMA_HISTOGRAM_ENUMERATION(kUMAProxyStartupStateHistogram, 506 UMA_HISTOGRAM_ENUMERATION(kUMAProxyStartupStateHistogram,
574 state, 507 state,
575 PROXY_STARTUP_STATE_COUNT); 508 PROXY_STARTUP_STATE_COUNT);
576 } 509 }
577 510
511 void DataReductionProxySettings::ResetParamsForTest(
512 DataReductionProxyParams* params) {
513 params_.reset(params);
514 }
515
578 DataReductionProxySettings::ContentLengthList 516 DataReductionProxySettings::ContentLengthList
579 DataReductionProxySettings::GetDailyContentLengths(const char* pref_name) { 517 DataReductionProxySettings::GetDailyContentLengths(const char* pref_name) {
580 DCHECK(thread_checker_.CalledOnValidThread()); 518 DCHECK(thread_checker_.CalledOnValidThread());
581 DataReductionProxySettings::ContentLengthList content_lengths; 519 DataReductionProxySettings::ContentLengthList content_lengths;
582 const base::ListValue* list_value = GetLocalStatePrefs()->GetList(pref_name); 520 const base::ListValue* list_value = GetLocalStatePrefs()->GetList(pref_name);
583 if (list_value->GetSize() == kNumDaysInHistory) { 521 if (list_value->GetSize() == kNumDaysInHistory) {
584 for (size_t i = 0; i < kNumDaysInHistory; ++i) { 522 for (size_t i = 0; i < kNumDaysInHistory; ++i) {
585 content_lengths.push_back(GetInt64PrefValue(*list_value, i)); 523 content_lengths.push_back(GetInt64PrefValue(*list_value, i));
586 } 524 }
587 } 525 }
588 return content_lengths; 526 return content_lengths;
589 } 527 }
590 528
591 void DataReductionProxySettings::GetContentLengths( 529 void DataReductionProxySettings::GetContentLengths(
592 unsigned int days, 530 unsigned int days,
593 int64* original_content_length, 531 int64* original_content_length,
594 int64* received_content_length, 532 int64* received_content_length,
595 int64* last_update_time) { 533 int64* last_update_time) {
596 DCHECK(thread_checker_.CalledOnValidThread()); 534 DCHECK(thread_checker_.CalledOnValidThread());
597 DCHECK_LE(days, kNumDaysInHistory); 535 DCHECK_LE(days, kNumDaysInHistory);
598 PrefService* local_state = GetLocalStatePrefs(); 536 PrefService* local_state = GetLocalStatePrefs();
599 if (!local_state) { 537 if (!local_state) {
(...skipping 23 matching lines...) Expand all
623 i < kNumDaysInHistory; ++i) { 561 i < kNumDaysInHistory; ++i) {
624 orig += GetInt64PrefValue(*original_list, i); 562 orig += GetInt64PrefValue(*original_list, i);
625 recv += GetInt64PrefValue(*received_list, i); 563 recv += GetInt64PrefValue(*received_list, i);
626 } 564 }
627 *original_content_length = orig; 565 *original_content_length = orig;
628 *received_content_length = recv; 566 *received_content_length = recv;
629 *last_update_time = 567 *last_update_time =
630 local_state->GetInt64(prefs::kDailyHttpContentLengthLastUpdateDate); 568 local_state->GetInt64(prefs::kDailyHttpContentLengthLastUpdateDate);
631 } 569 }
632 570
633 std::string DataReductionProxySettings::GetProxyCheckURL() {
634 if (!IsDataReductionProxyAllowed())
635 return std::string();
636 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
637 if (command_line.HasSwitch(switches::kDataReductionProxyProbeURL)) {
638 return command_line.GetSwitchValueASCII(
639 switches::kDataReductionProxyProbeURL);
640 }
641 #if defined(DATA_REDUCTION_PROXY_PROBE_URL)
642 return DATA_REDUCTION_PROXY_PROBE_URL;
643 #else
644 return std::string();
645 #endif
646 }
647
648 // static 571 // static
649 base::string16 DataReductionProxySettings::AuthHashForSalt( 572 base::string16 DataReductionProxySettings::AuthHashForSalt(
650 int64 salt, 573 int64 salt,
651 const std::string& key) { 574 const std::string& key) {
652 std::string active_key;
653
654 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
655 if (command_line.HasSwitch(switches::kDataReductionProxy)) {
656 // If an origin is provided via a switch, then only consider the value
657 // that is provided by a switch. Do not use the preprocessor constant.
658 // Don't expose |key_| to a proxy passed in via the command line.
659 if (!command_line.HasSwitch(switches::kDataReductionProxyKey))
660 return base::string16();
661 active_key = command_line.GetSwitchValueASCII(
662 switches::kDataReductionProxyKey);
663 } else {
664 active_key = key;
665 }
666 DCHECK(!active_key.empty());
667
668 std::string salted_key = 575 std::string salted_key =
669 base::StringPrintf("%lld%s%lld", 576 base::StringPrintf("%lld%s%lld",
670 static_cast<long long>(salt), 577 static_cast<long long>(salt),
671 active_key.c_str(), 578 key.c_str(),
672 static_cast<long long>(salt)); 579 static_cast<long long>(salt));
673 return base::UTF8ToUTF16(base::MD5String(salted_key)); 580 return base::UTF8ToUTF16(base::MD5String(salted_key));
674 } 581 }
675 582
676 net::URLFetcher* DataReductionProxySettings::GetURLFetcher() { 583 net::URLFetcher* DataReductionProxySettings::GetURLFetcher() {
677 DCHECK(url_request_context_getter_); 584 DCHECK(url_request_context_getter_);
678 std::string url = GetProxyCheckURL(); 585 net::URLFetcher* fetcher = net::URLFetcher::Create(params_->probe_url(),
679 if (url.empty())
680 return NULL;
681 net::URLFetcher* fetcher = net::URLFetcher::Create(GURL(url),
682 net::URLFetcher::GET, 586 net::URLFetcher::GET,
683 this); 587 this);
684 fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE | net::LOAD_BYPASS_PROXY); 588 fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE | net::LOAD_BYPASS_PROXY);
685 fetcher->SetRequestContext(url_request_context_getter_); 589 fetcher->SetRequestContext(url_request_context_getter_);
686 // Configure max retries to be at most kMaxRetries times for 5xx errors. 590 // Configure max retries to be at most kMaxRetries times for 5xx errors.
687 static const int kMaxRetries = 5; 591 static const int kMaxRetries = 5;
688 fetcher->SetMaxRetriesOn5xx(kMaxRetries); 592 fetcher->SetMaxRetriesOn5xx(kMaxRetries);
689 return fetcher; 593 return fetcher;
690 } 594 }
691 595
692 void DataReductionProxySettings::ProbeWhetherDataReductionProxyIsAvailable() { 596 void DataReductionProxySettings::ProbeWhetherDataReductionProxyIsAvailable() {
693 net::URLFetcher* fetcher = GetURLFetcher(); 597 net::URLFetcher* fetcher = GetURLFetcher();
694 if (!fetcher) 598 if (!fetcher)
695 return; 599 return;
696 fetcher_.reset(fetcher); 600 fetcher_.reset(fetcher);
697 fetcher_->Start(); 601 fetcher_->Start();
698 } 602 }
699 603
700 } // namespace data_reduction_proxy 604 } // namespace data_reduction_proxy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698