cc: Make ContentLayerClient subclasses create the DisplayItemList.
[chromium-blink-merge.git] / components / data_reduction_proxy / core / browser / data_reduction_proxy_request_options.cc
blob8cb3336390e200247fb0a850e42d125198de87de
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/core/browser/data_reduction_proxy_request_options.h"
7 #include <vector>
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/string_tokenizer.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/time/time.h"
18 #include "base/values.h"
19 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h"
20 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
21 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_client_config_parser.h"
22 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
23 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
24 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
25 #include "components/data_reduction_proxy/core/common/version.h"
26 #include "crypto/random.h"
27 #include "net/base/host_port_pair.h"
28 #include "net/base/load_flags.h"
29 #include "net/proxy/proxy_server.h"
30 #include "net/url_request/url_request.h"
32 #if !defined(OS_ANDROID) && !defined(OS_IOS)
33 #include "google_apis/google_api_keys.h"
34 #endif
36 namespace data_reduction_proxy {
37 namespace {
39 std::string FormatOption(const std::string& name, const std::string& value) {
40 return name + "=" + value;
43 bool ShouldForceDisableLoFi(const net::URLRequest* request) {
44 if (!request)
45 return false;
46 return (request->load_flags() & net::LOAD_BYPASS_CACHE) != 0;
49 } // namespace
51 const char kSessionHeaderOption[] = "ps";
52 const char kCredentialsHeaderOption[] = "sid";
53 const char kSecureSessionHeaderOption[] = "s";
54 const char kBuildNumberHeaderOption[] = "b";
55 const char kPatchNumberHeaderOption[] = "p";
56 const char kClientHeaderOption[] = "c";
57 const char kLoFiHeaderOption[] = "q";
58 const char kExperimentsOption[] = "exp";
60 // The empty version for the authentication protocol. Currently used by
61 // Android webview.
62 #if defined(OS_ANDROID)
63 const char kAndroidWebViewProtocolVersion[] = "";
64 #endif
66 #define CLIENT_ENUM(name, str_value) \
67 case name: return str_value;
68 const char* GetString(Client client) {
69 switch (client) {
70 CLIENT_ENUMS_LIST
72 NOTREACHED();
73 return "";
75 #undef CLIENT_ENUM
77 // static
78 bool DataReductionProxyRequestOptions::IsKeySetOnCommandLine() {
79 const base::CommandLine& command_line =
80 *base::CommandLine::ForCurrentProcess();
81 return command_line.HasSwitch(
82 data_reduction_proxy::switches::kDataReductionProxyKey);
85 // static
86 std::string DataReductionProxyRequestOptions::CreateLocalSessionKey(
87 const std::string& session,
88 const std::string& credentials) {
89 return base::StringPrintf("%s|%s", session.c_str(), credentials.c_str());
92 // static
93 bool DataReductionProxyRequestOptions::ParseLocalSessionKey(
94 const std::string& session_key,
95 std::string* session,
96 std::string* credentials) {
97 std::vector<std::string> auth_values;
98 base::SplitString(session_key, '|', &auth_values);
99 if (auth_values.size() == 2) {
100 *session = auth_values[0];
101 *credentials = auth_values[1];
102 return true;
105 return false;
108 DataReductionProxyRequestOptions::DataReductionProxyRequestOptions(
109 Client client,
110 DataReductionProxyConfig* config)
111 : client_(GetString(client)),
112 use_assigned_credentials_(false),
113 data_reduction_proxy_config_(config) {
114 GetChromiumBuildAndPatch(ChromiumVersion(), &build_, &patch_);
115 // Constructed on the UI thread, but should be checked on the IO thread.
116 thread_checker_.DetachFromThread();
119 DataReductionProxyRequestOptions::DataReductionProxyRequestOptions(
120 Client client,
121 const std::string& version,
122 DataReductionProxyConfig* config)
123 : client_(GetString(client)),
124 use_assigned_credentials_(false),
125 data_reduction_proxy_config_(config) {
126 GetChromiumBuildAndPatch(version, &build_, &patch_);
127 // Constructed on the UI thread, but should be checked on the IO thread.
128 thread_checker_.DetachFromThread();
131 DataReductionProxyRequestOptions::~DataReductionProxyRequestOptions() {
134 void DataReductionProxyRequestOptions::Init() {
135 key_ = GetDefaultKey(),
136 UpdateCredentials();
137 UpdateLoFi(false);
138 UpdateVersion();
139 UpdateExperiments();
142 std::string DataReductionProxyRequestOptions::ChromiumVersion() const {
143 #if defined(PRODUCT_VERSION)
144 return PRODUCT_VERSION;
145 #else
146 return std::string();
147 #endif
150 void DataReductionProxyRequestOptions::GetChromiumBuildAndPatch(
151 const std::string& version,
152 std::string* build,
153 std::string* patch) const {
154 std::vector<std::string> version_parts;
155 base::SplitString(version, '.', &version_parts);
156 if (version_parts.size() != 4)
157 return;
158 *build = version_parts[2];
159 *patch = version_parts[3];
162 void DataReductionProxyRequestOptions::UpdateVersion() {
163 GetChromiumBuildAndPatch(version_, &build_, &patch_);
164 RegenerateRequestHeaderValue();
167 void DataReductionProxyRequestOptions::UpdateLoFi(bool force_disable_lo_fi) {
168 if (force_disable_lo_fi) {
169 if (lofi_.empty())
170 return;
171 lofi_ = std::string();
172 RegenerateRequestHeaderValue();
173 return;
175 // LoFi was not enabled, but now is. Add the header option.
176 if (lofi_.empty() && DataReductionProxyParams::IsLoFiEnabled()) {
177 lofi_ = "low";
178 RegenerateRequestHeaderValue();
179 return;
181 // LoFi was enabled, but no longer is. Remove the header option.
182 if (!lofi_.empty() && !DataReductionProxyParams::IsLoFiEnabled()) {
183 lofi_ = std::string();
184 RegenerateRequestHeaderValue();
188 void DataReductionProxyRequestOptions::UpdateExperiments() {
189 std::string experiments =
190 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
191 data_reduction_proxy::switches::kDataReductionProxyExperiment);
192 if (experiments.empty())
193 return;
194 base::StringTokenizer experiment_tokenizer(experiments, ", ");
195 experiment_tokenizer.set_quote_chars("\"");
196 while (experiment_tokenizer.GetNext()) {
197 if (!experiment_tokenizer.token().empty())
198 experiments_.push_back(experiment_tokenizer.token());
200 RegenerateRequestHeaderValue();
203 // static
204 base::string16 DataReductionProxyRequestOptions::AuthHashForSalt(
205 int64 salt,
206 const std::string& key) {
207 std::string salted_key =
208 base::StringPrintf("%lld%s%lld",
209 static_cast<long long>(salt),
210 key.c_str(),
211 static_cast<long long>(salt));
212 return base::UTF8ToUTF16(base::MD5String(salted_key));
215 base::Time DataReductionProxyRequestOptions::Now() const {
216 return base::Time::Now();
219 void DataReductionProxyRequestOptions::RandBytes(void* output,
220 size_t length) const {
221 crypto::RandBytes(output, length);
224 void DataReductionProxyRequestOptions::MaybeAddRequestHeader(
225 net::URLRequest* request,
226 const net::ProxyServer& proxy_server,
227 net::HttpRequestHeaders* request_headers) {
228 DCHECK(thread_checker_.CalledOnValidThread());
229 if (!proxy_server.is_valid())
230 return;
231 if (proxy_server.is_direct())
232 return;
233 MaybeAddRequestHeaderImpl(proxy_server.host_port_pair(), false,
234 request_headers, ShouldForceDisableLoFi(request));
237 void DataReductionProxyRequestOptions::MaybeAddProxyTunnelRequestHandler(
238 const net::HostPortPair& proxy_server,
239 net::HttpRequestHeaders* request_headers) {
240 DCHECK(thread_checker_.CalledOnValidThread());
241 MaybeAddRequestHeaderImpl(proxy_server, true, request_headers, false);
244 void DataReductionProxyRequestOptions::SetHeader(
245 net::HttpRequestHeaders* headers,
246 bool force_disable_lo_fi) {
247 base::Time now = Now();
248 // Authorization credentials must be regenerated if they are expired.
249 if (!use_assigned_credentials_ && (now > credentials_expiration_time_))
250 UpdateCredentials();
251 UpdateLoFi(force_disable_lo_fi);
252 const char kChromeProxyHeader[] = "Chrome-Proxy";
253 std::string header_value;
254 if (headers->HasHeader(kChromeProxyHeader)) {
255 headers->GetHeader(kChromeProxyHeader, &header_value);
256 headers->RemoveHeader(kChromeProxyHeader);
257 header_value += ", ";
259 header_value += header_value_;
260 headers->SetHeader(kChromeProxyHeader, header_value);
263 void DataReductionProxyRequestOptions::ComputeCredentials(
264 const base::Time& now,
265 std::string* session,
266 std::string* credentials) const {
267 DCHECK(session);
268 DCHECK(credentials);
269 int64 timestamp =
270 (now - base::Time::UnixEpoch()).InMilliseconds() / 1000;
272 int32 rand[3];
273 RandBytes(rand, 3 * sizeof(rand[0]));
274 *session = base::StringPrintf("%lld-%u-%u-%u",
275 static_cast<long long>(timestamp),
276 rand[0],
277 rand[1],
278 rand[2]);
279 *credentials = base::UTF16ToUTF8(AuthHashForSalt(timestamp, key_));
281 DVLOG(1) << "session: [" << *session << "] "
282 << "password: [" << *credentials << "]";
285 void DataReductionProxyRequestOptions::UpdateCredentials() {
286 base::Time now = Now();
287 ComputeCredentials(now, &session_, &credentials_);
288 credentials_expiration_time_ = now + base::TimeDelta::FromHours(24);
289 RegenerateRequestHeaderValue();
292 void DataReductionProxyRequestOptions::SetKeyOnIO(const std::string& key) {
293 DCHECK(thread_checker_.CalledOnValidThread());
294 if(!key.empty()) {
295 key_ = key;
296 UpdateCredentials();
300 void DataReductionProxyRequestOptions::PopulateConfigResponse(
301 base::DictionaryValue* response) const {
302 DCHECK(thread_checker_.CalledOnValidThread());
303 std::string session;
304 std::string credentials;
305 base::Time now = Now();
306 base::Time expiration_time = now + base::TimeDelta::FromHours(24);
307 ComputeCredentials(now, &session, &credentials);
308 response->SetString("sessionKey",
309 CreateLocalSessionKey(session, credentials));
310 response->SetString("expireTime",
311 config_parser::TimeToISO8601(expiration_time));
314 void DataReductionProxyRequestOptions::SetCredentials(
315 const std::string& session,
316 const std::string& credentials) {
317 DCHECK(thread_checker_.CalledOnValidThread());
318 session_ = session;
319 credentials_ = credentials;
320 secure_session_.clear();
321 // Force skipping of credential regeneration. It should be handled by the
322 // caller.
323 use_assigned_credentials_ = true;
324 RegenerateRequestHeaderValue();
327 void DataReductionProxyRequestOptions::SetSecureSession(
328 const std::string& secure_session) {
329 DCHECK(thread_checker_.CalledOnValidThread());
330 session_.clear();
331 credentials_.clear();
332 secure_session_ = secure_session;
333 // Force skipping of credential regeneration. It should be handled by the
334 // caller.
335 use_assigned_credentials_ = true;
336 RegenerateRequestHeaderValue();
339 void DataReductionProxyRequestOptions::Invalidate() {
340 SetSecureSession(std::string());
343 std::string DataReductionProxyRequestOptions::GetDefaultKey() const {
344 const base::CommandLine& command_line =
345 *base::CommandLine::ForCurrentProcess();
346 std::string key =
347 command_line.GetSwitchValueASCII(switches::kDataReductionProxyKey);
348 // Android and iOS get the default key from a preprocessor constant. All other
349 // platforms get the key from google_apis
350 #if defined(OS_ANDROID) || defined(OS_IOS)
351 #if defined(SPDY_PROXY_AUTH_VALUE)
352 if (key.empty())
353 key = SPDY_PROXY_AUTH_VALUE;
354 #endif
355 #else
356 if (key.empty()) {
357 key = google_apis::GetSpdyProxyAuthValue();
359 #endif // defined(OS_ANDROID) || defined(OS_IOS)
360 return key;
363 const std::string& DataReductionProxyRequestOptions::GetSecureSession() const {
364 return secure_session_;
367 void DataReductionProxyRequestOptions::MaybeAddRequestHeaderImpl(
368 const net::HostPortPair& proxy_server,
369 bool expect_ssl,
370 net::HttpRequestHeaders* request_headers,
371 bool force_disable_lo_fi) {
372 if (proxy_server.IsEmpty())
373 return;
374 if (data_reduction_proxy_config_ &&
375 data_reduction_proxy_config_->IsDataReductionProxy(proxy_server, NULL) &&
376 data_reduction_proxy_config_->UsingHTTPTunnel(proxy_server) ==
377 expect_ssl) {
378 SetHeader(request_headers, force_disable_lo_fi);
382 void DataReductionProxyRequestOptions::RegenerateRequestHeaderValue() {
383 std::vector<std::string> headers;
384 if (!session_.empty())
385 headers.push_back(FormatOption(kSessionHeaderOption, session_));
386 if (!credentials_.empty())
387 headers.push_back(FormatOption(kCredentialsHeaderOption, credentials_));
388 if (!secure_session_.empty()) {
389 headers.push_back(
390 FormatOption(kSecureSessionHeaderOption, secure_session_));
392 if (!client_.empty())
393 headers.push_back(FormatOption(kClientHeaderOption, client_));
394 if (!build_.empty() && !patch_.empty()) {
395 headers.push_back(FormatOption(kBuildNumberHeaderOption, build_));
396 headers.push_back(FormatOption(kPatchNumberHeaderOption, patch_));
398 if (!lofi_.empty())
399 headers.push_back(FormatOption(kLoFiHeaderOption, lofi_));
400 for (const auto& experiment : experiments_)
401 headers.push_back(FormatOption(kExperimentsOption, experiment));
403 header_value_ = JoinString(headers, ", ");
406 } // namespace data_reduction_proxy