1010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// found in the LICENSE file.
4010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
5010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "components/data_reduction_proxy/browser/data_reduction_proxy_config_service.h"
6010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
7010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/bind.h"
8010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/memory/ref_counted.h"
9010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/message_loop/message_loop.h"
10010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/strings/string_util.h"
11010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
12010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)namespace data_reduction_proxy {
13010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
14010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)DataReductionProxyConfigService::DataReductionProxyConfigService(
15010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    scoped_ptr<net::ProxyConfigService> base_service)
16010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    : config_read_pending_(true),
17010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      registered_observer_(false),
18010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      enabled_(false),
19010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      restricted_(false) {
20010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  base_service_ = base_service.Pass();
21010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
22010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
23010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)DataReductionProxyConfigService::~DataReductionProxyConfigService() {
24010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (registered_observer_ && base_service_.get())
25010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    base_service_->RemoveObserver(this);
26010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
27010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
28010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void DataReductionProxyConfigService::AddObserver(
29010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    net::ProxyConfigService::Observer* observer) {
30010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  RegisterObserver();
31010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  observers_.AddObserver(observer);
32010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
33010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
34010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void DataReductionProxyConfigService::RemoveObserver(
35010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    net::ProxyConfigService::Observer* observer) {
36010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  observers_.RemoveObserver(observer);
37010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
38010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
39010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)net::ProxyConfigService::ConfigAvailability
40010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)DataReductionProxyConfigService::GetLatestProxyConfig(
41010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    net::ProxyConfig* config) {
42010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  RegisterObserver();
43010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
44010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (enabled_) {
45010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    *config = config_;
46010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return net::ProxyConfigService::CONFIG_VALID;
47010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
48010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
49010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Ask the base service if available.
50010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  net::ProxyConfig system_config;
51010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  ConfigAvailability system_availability =
52010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      net::ProxyConfigService::CONFIG_UNSET;
53010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (base_service_.get()) {
54010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    system_availability = base_service_->GetLatestProxyConfig(&system_config);
55010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    *config = system_config;
56010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
57010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (system_availability == net::ProxyConfigService::CONFIG_UNSET) {
58010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    *config = net::ProxyConfig::CreateDirect();
59010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
60010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
61010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return net::ProxyConfigService::CONFIG_VALID;
62010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
63010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
64010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void DataReductionProxyConfigService::OnLazyPoll() {
65010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (base_service_.get())
66010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    base_service_->OnLazyPoll();
67010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
68010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
69010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void DataReductionProxyConfigService::UpdateProxyConfig(
70010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    bool enabled,
71010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const net::ProxyConfig& config) {
72010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
73010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  config_read_pending_ = false;
74010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  enabled_ = enabled;
75010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  config_ = config;
76010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
77010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!observers_.might_have_observers())
78010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
79010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
80010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Evaluate the proxy configuration. If GetLatestProxyConfig returns
81010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // CONFIG_PENDING, we are using the system proxy service, but it doesn't have
82010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // a valid configuration yet. Once it is ready, OnProxyConfigChanged() will be
83010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // called and broadcast the proxy configuration.
84010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Note: If a switch between a preference proxy configuration and the system
85010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // proxy configuration occurs an unnecessary notification might get sent if
86010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // the two configurations agree. This case should be rare however, so we don't
87010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // handle that case specially.
88010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  net::ProxyConfig new_config;
89010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  ConfigAvailability availability = GetLatestProxyConfig(&new_config);
90010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (availability != CONFIG_PENDING) {
91010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    FOR_EACH_OBSERVER(net::ProxyConfigService::Observer, observers_,
92010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                      OnProxyConfigChanged(new_config, availability));
93010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
94010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
95010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
96010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void DataReductionProxyConfigService::OnProxyConfigChanged(
97010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const net::ProxyConfig& config,
98010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    ConfigAvailability availability) {
99010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
100010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Check whether the data reduction proxy is enabled. In this case that proxy
101010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // configuration takes precedence and the change event from the delegate proxy
102010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // service can be disregarded.
103010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!enabled_) {
104010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    net::ProxyConfig actual_config;
105010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    availability = GetLatestProxyConfig(&actual_config);
106010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    FOR_EACH_OBSERVER(net::ProxyConfigService::Observer, observers_,
107010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                      OnProxyConfigChanged(actual_config, availability));
108010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
109010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
110010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
111010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void DataReductionProxyConfigService::RegisterObserver() {
112010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!registered_observer_ && base_service_.get()) {
113010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    base_service_->AddObserver(this);
114010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    registered_observer_ = true;
115010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
116010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
117010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
118010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)DataReductionProxyConfigTracker::DataReductionProxyConfigTracker(
1196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    base::Callback<void(bool, const net::ProxyConfig&)> update_proxy_config,
120010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    base::TaskRunner* task_runner)
1216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    : update_proxy_config_(update_proxy_config),
122010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      task_runner_(task_runner) {
123010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
124010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
125010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)DataReductionProxyConfigTracker::~DataReductionProxyConfigTracker() {
126010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
127010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
128010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void DataReductionProxyConfigTracker::Enable(
129010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    bool primary_restricted,
130010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    bool fallback_restricted,
131010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const std::string& primary_origin,
13246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const std::string& fallback_origin,
13346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const std::string& ssl_origin) {
134010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
135010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  std::vector<std::string> proxies;
136010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!primary_restricted) {
137010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    std::string trimmed_primary;
138010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    base::TrimString(primary_origin, "/", &trimmed_primary);
139010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (!trimmed_primary.empty())
140010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      proxies.push_back(trimmed_primary);
141010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
142010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!fallback_restricted) {
143010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    std::string trimmed_fallback;
144010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    base::TrimString(fallback_origin, "/", &trimmed_fallback);
145010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (!trimmed_fallback.empty())
146010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      proxies.push_back(trimmed_fallback);
147010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
148010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (proxies.empty()) {
149010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    std::string mode;
150010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    Disable();
151010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
152010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
153010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
15446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  std::string trimmed_ssl;
15546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::TrimString(ssl_origin, "/", &trimmed_ssl);
15646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
15746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  std::string server = "http=" + JoinString(proxies, ",") + ",direct://;"
15846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      + (ssl_origin.empty() ? "" : ("https=" + ssl_origin + ",direct://;"));
15946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
160010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  net::ProxyConfig config;
16146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  config.proxy_rules().ParseFromString(server);
162010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  config.proxy_rules().bypass_rules.ParseFromString(
163010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      JoinString(bypass_rules_, ", "));
164010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  UpdateProxyConfigOnIOThread(true, config);
165010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
166010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
167010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
168010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void DataReductionProxyConfigTracker::Disable() {
169010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  net::ProxyConfig config = net::ProxyConfig::CreateDirect();
170010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  UpdateProxyConfigOnIOThread(false, config);
171010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
172010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
173010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void DataReductionProxyConfigTracker::AddHostPatternToBypass(
174010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const std::string& pattern) {
175010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  bypass_rules_.push_back(pattern);
176010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
177010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
178010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void DataReductionProxyConfigTracker::AddURLPatternToBypass(
179010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const std::string& pattern) {
180010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  size_t pos = pattern.find("/");
181010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (pattern.find("/", pos + 1) == pos + 1)
182010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    pos = pattern.find("/", pos + 2);
183010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
184010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  std::string host_pattern;
185010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (pos != std::string::npos)
186010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    host_pattern = pattern.substr(0, pos);
187010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  else
188010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    host_pattern = pattern;
189010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
190010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  AddHostPatternToBypass(host_pattern);
191010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
192010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
193010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void DataReductionProxyConfigTracker::UpdateProxyConfigOnIOThread(
194010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    bool enabled,
195010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const net::ProxyConfig& config) {
1966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  task_runner_->PostTask(
1976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      FROM_HERE, base::Bind(update_proxy_config_, enabled, config));
198010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
199010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
200010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}  // namespace data_reduction_proxy
201