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 "chrome/browser/component_updater/chrome_component_updater_configurator.h"
6
7#include <algorithm>
8#include <string>
9#include <vector>
10
11#include "base/command_line.h"
12#include "base/compiler_specific.h"
13#include "base/strings/string_util.h"
14#include "base/version.h"
15#if defined(OS_WIN)
16#include "base/win/win_util.h"
17#endif  // OS_WIN
18#include "build/build_config.h"
19#include "chrome/browser/component_updater/component_patcher_operation_out_of_process.h"
20#include "chrome/browser/omaha_query_params/chrome_omaha_query_params_delegate.h"
21#include "chrome/common/chrome_version_info.h"
22#include "components/component_updater/component_updater_configurator.h"
23#include "components/component_updater/component_updater_switches.h"
24#include "content/public/browser/browser_thread.h"
25#include "net/url_request/url_request_context_getter.h"
26#include "url/gurl.h"
27
28namespace component_updater {
29
30namespace {
31
32// Default time constants.
33const int kDelayOneMinute = 60;
34const int kDelayOneHour = kDelayOneMinute * 60;
35
36// Debug values you can pass to --component-updater=value1,value2.
37// Speed up component checking.
38const char kSwitchFastUpdate[] = "fast-update";
39
40// Add "testrequest=1" attribute to the update check request.
41const char kSwitchRequestParam[] = "test-request";
42
43// Disables pings. Pings are the requests sent to the update server that report
44// the success or the failure of component install or update attempts.
45extern const char kSwitchDisablePings[] = "disable-pings";
46
47// Sets the URL for updates.
48const char kSwitchUrlSource[] = "url-source";
49
50#define COMPONENT_UPDATER_SERVICE_ENDPOINT \
51  "//clients2.google.com/service/update2"
52
53// The default URL for the v3 protocol service endpoint. In some cases, the
54// component updater is allowed to fall back to and alternate URL source, if
55// the request to the default URL source fails.
56// The value of |kDefaultUrlSource| can be overridden with
57// --component-updater=url-source=someurl.
58const char kDefaultUrlSource[] = "https:" COMPONENT_UPDATER_SERVICE_ENDPOINT;
59const char kAltUrlSource[] = "http:" COMPONENT_UPDATER_SERVICE_ENDPOINT;
60
61// Disables differential updates.
62const char kSwitchDisableDeltaUpdates[] = "disable-delta-updates";
63
64#if defined(OS_WIN)
65// Disables background downloads.
66const char kSwitchDisableBackgroundDownloads[] = "disable-background-downloads";
67#endif  // defined(OS_WIN)
68
69// Returns true if and only if |test| is contained in |vec|.
70bool HasSwitchValue(const std::vector<std::string>& vec, const char* test) {
71  if (vec.empty())
72    return 0;
73  return (std::find(vec.begin(), vec.end(), test) != vec.end());
74}
75
76// Returns true if falling back on an alternate, unsafe, service URL is
77// allowed. In the fallback case, the security of the component update relies
78// only on the integrity of the CRX payloads, which is self-validating.
79// This is allowed only for some of the pre-Windows Vista versions not including
80// Windows XP SP3. As a side note, pings could be sent to the alternate URL too.
81bool CanUseAltUrlSource() {
82#if defined(OS_WIN)
83  return !base::win::MaybeHasSHA256Support();
84#else
85  return false;
86#endif  // OS_WIN
87}
88
89// If there is an element of |vec| of the form |test|=.*, returns the right-
90// hand side of that assignment. Otherwise, returns an empty string.
91// The right-hand side may contain additional '=' characters, allowing for
92// further nesting of switch arguments.
93std::string GetSwitchArgument(const std::vector<std::string>& vec,
94                              const char* test) {
95  if (vec.empty())
96    return std::string();
97  for (std::vector<std::string>::const_iterator it = vec.begin();
98       it != vec.end();
99       ++it) {
100    const std::size_t found = it->find("=");
101    if (found != std::string::npos) {
102      if (it->substr(0, found) == test) {
103        return it->substr(found + 1);
104      }
105    }
106  }
107  return std::string();
108}
109
110class ChromeConfigurator : public Configurator {
111 public:
112  ChromeConfigurator(const CommandLine* cmdline,
113                     net::URLRequestContextGetter* url_request_getter);
114
115  virtual ~ChromeConfigurator() {}
116
117  virtual int InitialDelay() const OVERRIDE;
118  virtual int NextCheckDelay() OVERRIDE;
119  virtual int StepDelay() const OVERRIDE;
120  virtual int StepDelayMedium() OVERRIDE;
121  virtual int MinimumReCheckWait() const OVERRIDE;
122  virtual int OnDemandDelay() const OVERRIDE;
123  virtual std::vector<GURL> UpdateUrl() const OVERRIDE;
124  virtual std::vector<GURL> PingUrl() const OVERRIDE;
125  virtual base::Version GetBrowserVersion() const OVERRIDE;
126  virtual std::string GetChannel() const OVERRIDE;
127  virtual std::string GetLang() const OVERRIDE;
128  virtual std::string GetOSLongName() const OVERRIDE;
129  virtual std::string ExtraRequestParams() const OVERRIDE;
130  virtual size_t UrlSizeLimit() const OVERRIDE;
131  virtual net::URLRequestContextGetter* RequestContext() const OVERRIDE;
132  virtual scoped_refptr<OutOfProcessPatcher> CreateOutOfProcessPatcher()
133      const OVERRIDE;
134  virtual bool DeltasEnabled() const OVERRIDE;
135  virtual bool UseBackgroundDownloader() const OVERRIDE;
136  virtual scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner()
137      const OVERRIDE;
138  virtual scoped_refptr<base::SingleThreadTaskRunner>
139      GetSingleThreadTaskRunner() const OVERRIDE;
140
141 private:
142  net::URLRequestContextGetter* url_request_getter_;
143  std::string extra_info_;
144  GURL url_source_override_;
145  bool fast_update_;
146  bool pings_enabled_;
147  bool deltas_enabled_;
148  bool background_downloads_enabled_;
149  bool fallback_to_alt_source_url_enabled_;
150};
151
152ChromeConfigurator::ChromeConfigurator(
153    const CommandLine* cmdline,
154    net::URLRequestContextGetter* url_request_getter)
155    : url_request_getter_(url_request_getter),
156      fast_update_(false),
157      pings_enabled_(false),
158      deltas_enabled_(false),
159      background_downloads_enabled_(false),
160      fallback_to_alt_source_url_enabled_(false) {
161  // Parse comma-delimited debug flags.
162  std::vector<std::string> switch_values;
163  Tokenize(cmdline->GetSwitchValueASCII(switches::kComponentUpdater),
164           ",",
165           &switch_values);
166  fast_update_ = HasSwitchValue(switch_values, kSwitchFastUpdate);
167  pings_enabled_ = !HasSwitchValue(switch_values, kSwitchDisablePings);
168  deltas_enabled_ = !HasSwitchValue(switch_values, kSwitchDisableDeltaUpdates);
169
170#if defined(OS_WIN)
171  background_downloads_enabled_ =
172      !HasSwitchValue(switch_values, kSwitchDisableBackgroundDownloads);
173#else
174  background_downloads_enabled_ = false;
175#endif
176
177  const std::string switch_url_source =
178      GetSwitchArgument(switch_values, kSwitchUrlSource);
179  if (!switch_url_source.empty()) {
180    url_source_override_ = GURL(switch_url_source);
181    DCHECK(url_source_override_.is_valid());
182  }
183
184  if (HasSwitchValue(switch_values, kSwitchRequestParam))
185    extra_info_ += "testrequest=\"1\"";
186
187  fallback_to_alt_source_url_enabled_ = CanUseAltUrlSource();
188}
189
190int ChromeConfigurator::InitialDelay() const {
191  return fast_update_ ? 1 : (6 * kDelayOneMinute);
192}
193
194int ChromeConfigurator::NextCheckDelay() {
195  return fast_update_ ? 3 : (6 * kDelayOneHour);
196}
197
198int ChromeConfigurator::StepDelayMedium() {
199  return fast_update_ ? 3 : (15 * kDelayOneMinute);
200}
201
202int ChromeConfigurator::StepDelay() const {
203  return fast_update_ ? 1 : 1;
204}
205
206int ChromeConfigurator::MinimumReCheckWait() const {
207  return fast_update_ ? 30 : (6 * kDelayOneHour);
208}
209
210int ChromeConfigurator::OnDemandDelay() const {
211  return fast_update_ ? 2 : (30 * kDelayOneMinute);
212}
213
214std::vector<GURL> ChromeConfigurator::UpdateUrl() const {
215  std::vector<GURL> urls;
216  if (url_source_override_.is_valid()) {
217    urls.push_back(GURL(url_source_override_));
218  } else {
219    urls.push_back(GURL(kDefaultUrlSource));
220    if (fallback_to_alt_source_url_enabled_) {
221      urls.push_back(GURL(kAltUrlSource));
222    }
223  }
224  return urls;
225}
226
227std::vector<GURL> ChromeConfigurator::PingUrl() const {
228  return pings_enabled_ ? UpdateUrl() : std::vector<GURL>();
229}
230
231base::Version ChromeConfigurator::GetBrowserVersion() const {
232  return base::Version(chrome::VersionInfo().Version());
233}
234
235std::string ChromeConfigurator::GetChannel() const {
236  return ChromeOmahaQueryParamsDelegate::GetChannelString();
237}
238
239std::string ChromeConfigurator::GetLang() const {
240  return ChromeOmahaQueryParamsDelegate::GetLang();
241}
242
243std::string ChromeConfigurator::GetOSLongName() const {
244  return chrome::VersionInfo().OSType();
245}
246
247std::string ChromeConfigurator::ExtraRequestParams() const {
248  return extra_info_;
249}
250
251size_t ChromeConfigurator::UrlSizeLimit() const {
252  return 1024ul;
253}
254
255net::URLRequestContextGetter* ChromeConfigurator::RequestContext() const {
256  return url_request_getter_;
257}
258
259scoped_refptr<OutOfProcessPatcher>
260ChromeConfigurator::CreateOutOfProcessPatcher() const {
261  return make_scoped_refptr(new ChromeOutOfProcessPatcher);
262}
263
264bool ChromeConfigurator::DeltasEnabled() const {
265  return deltas_enabled_;
266}
267
268bool ChromeConfigurator::UseBackgroundDownloader() const {
269  return background_downloads_enabled_;
270}
271
272scoped_refptr<base::SequencedTaskRunner>
273ChromeConfigurator::GetSequencedTaskRunner() const {
274  return content::BrowserThread::GetBlockingPool()
275      ->GetSequencedTaskRunnerWithShutdownBehavior(
276          content::BrowserThread::GetBlockingPool()->GetSequenceToken(),
277          base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
278}
279
280scoped_refptr<base::SingleThreadTaskRunner>
281ChromeConfigurator::GetSingleThreadTaskRunner() const {
282  return content::BrowserThread::GetMessageLoopProxyForThread(
283      content::BrowserThread::FILE);
284}
285
286}  // namespace
287
288Configurator* MakeChromeComponentUpdaterConfigurator(
289    const base::CommandLine* cmdline,
290    net::URLRequestContextGetter* context_getter) {
291  return new ChromeConfigurator(cmdline, context_getter);
292}
293
294}  // namespace component_updater
295