1// Copyright (c) 2011 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/chromeos/proxy_cros_settings_provider.h"
6
7#include "base/command_line.h"
8#include "base/string_util.h"
9#include "chrome/browser/browser_process.h"
10#include "chrome/browser/ui/browser_list.h"
11#include "chrome/common/chrome_switches.h"
12
13namespace chromeos {
14
15static const char kProxyPacUrl[]         = "cros.session.proxy.pacurl";
16static const char kProxySingleHttp[]     = "cros.session.proxy.singlehttp";
17static const char kProxySingleHttpPort[] = "cros.session.proxy.singlehttpport";
18static const char kProxyHttpUrl[]        = "cros.session.proxy.httpurl";
19static const char kProxyHttpPort[]       = "cros.session.proxy.httpport";
20static const char kProxyHttpsUrl[]       = "cros.session.proxy.httpsurl";
21static const char kProxyHttpsPort[]      = "cros.session.proxy.httpsport";
22static const char kProxyType[]           = "cros.session.proxy.type";
23static const char kProxySingle[]         = "cros.session.proxy.single";
24static const char kProxyFtpUrl[]         = "cros.session.proxy.ftpurl";
25static const char kProxyFtpPort[]        = "cros.session.proxy.ftpport";
26static const char kProxySocks[]          = "cros.session.proxy.socks";
27static const char kProxySocksPort[]      = "cros.session.proxy.socksport";
28static const char kProxyIgnoreList[]     = "cros.session.proxy.ignorelist";
29
30//------------------ ProxyCrosSettingsProvider: public methods -----------------
31
32ProxyCrosSettingsProvider::ProxyCrosSettingsProvider() { }
33
34void ProxyCrosSettingsProvider::DoSet(const std::string& path,
35                                      Value* in_value) {
36  if (!in_value) {
37    return;
38  }
39
40  chromeos::ProxyConfigServiceImpl* config_service = GetConfigService();
41  // Don't persist settings to device for guest session.
42  config_service->UISetPersistToDevice(
43      !CommandLine::ForCurrentProcess()->HasSwitch(switches::kGuestSession));
44  // Retrieve proxy config.
45  chromeos::ProxyConfigServiceImpl::ProxyConfig config;
46  config_service->UIGetProxyConfig(&config);
47
48  if (path == kProxyPacUrl) {
49    std::string val;
50    if (in_value->GetAsString(&val)) {
51      GURL url(val);
52      config_service->UISetProxyConfigToPACScript(url);
53    }
54  } else if (path == kProxySingleHttp) {
55    std::string val;
56    if (in_value->GetAsString(&val)) {
57      config_service->UISetProxyConfigToSingleProxy(CreateProxyServerFromHost(
58          val, config.single_proxy, net::ProxyServer::SCHEME_HTTP));
59    }
60  } else if (path == kProxySingleHttpPort) {
61    int val;
62    if (in_value->GetAsInteger(&val)) {
63      config_service->UISetProxyConfigToSingleProxy(CreateProxyServerFromPort(
64          val, config.single_proxy, net::ProxyServer::SCHEME_HTTP));
65    }
66  } else if (path == kProxyHttpUrl) {
67    std::string val;
68    if (in_value->GetAsString(&val)) {
69      config_service->UISetProxyConfigToProxyPerScheme("http",
70          CreateProxyServerFromHost(
71              val, config.http_proxy, net::ProxyServer::SCHEME_HTTP));
72    }
73  } else if (path == kProxyHttpPort) {
74    int val;
75    if (in_value->GetAsInteger(&val)) {
76      config_service->UISetProxyConfigToProxyPerScheme("http",
77          CreateProxyServerFromPort(
78              val, config.http_proxy, net::ProxyServer::SCHEME_HTTP));
79    }
80  } else if (path == kProxyHttpsUrl) {
81    std::string val;
82    if (in_value->GetAsString(&val)) {
83      config_service->UISetProxyConfigToProxyPerScheme("https",
84          CreateProxyServerFromHost(
85              val, config.https_proxy, net::ProxyServer::SCHEME_HTTP));
86    }
87  } else if (path == kProxyHttpsPort) {
88    int val;
89    if (in_value->GetAsInteger(&val)) {
90      config_service->UISetProxyConfigToProxyPerScheme("https",
91          CreateProxyServerFromPort(
92              val, config.https_proxy, net::ProxyServer::SCHEME_HTTP));
93    }
94  } else if (path == kProxyType) {
95    int val;
96    if (in_value->GetAsInteger(&val)) {
97      if (val == 3) {
98        if (config.automatic_proxy.pac_url.is_valid())
99          config_service->UISetProxyConfigToPACScript(
100              config.automatic_proxy.pac_url);
101        else
102          config_service->UISetProxyConfigToAutoDetect();
103      } else if (val == 2) {
104        if (config.single_proxy.server.is_valid()) {
105          config_service->UISetProxyConfigToSingleProxy(
106              config.single_proxy.server);
107        } else {
108          bool set_config = false;
109          if (config.http_proxy.server.is_valid()) {
110            config_service->UISetProxyConfigToProxyPerScheme("http",
111                config.http_proxy.server);
112            set_config = true;
113          }
114          if (config.https_proxy.server.is_valid()) {
115            config_service->UISetProxyConfigToProxyPerScheme("https",
116                config.https_proxy.server);
117            set_config = true;
118          }
119          if (config.ftp_proxy.server.is_valid()) {
120            config_service->UISetProxyConfigToProxyPerScheme("ftp",
121                config.ftp_proxy.server);
122            set_config = true;
123          }
124          if (config.socks_proxy.server.is_valid()) {
125            config_service->UISetProxyConfigToProxyPerScheme("socks",
126                config.socks_proxy.server);
127            set_config = true;
128          }
129          if (!set_config) {
130            config_service->UISetProxyConfigToProxyPerScheme("http",
131                net::ProxyServer());
132          }
133        }
134      } else {
135        config_service->UISetProxyConfigToDirect();
136      }
137    }
138  } else if (path == kProxySingle) {
139    bool val;
140    if (in_value->GetAsBoolean(&val)) {
141      if (val)
142        config_service->UISetProxyConfigToSingleProxy(
143            config.single_proxy.server);
144      else
145        config_service->UISetProxyConfigToProxyPerScheme("http",
146            config.http_proxy.server);
147    }
148  } else if (path == kProxyFtpUrl) {
149    std::string val;
150    if (in_value->GetAsString(&val)) {
151      config_service->UISetProxyConfigToProxyPerScheme("ftp",
152          CreateProxyServerFromHost(
153              val, config.ftp_proxy, net::ProxyServer::SCHEME_HTTP));
154    }
155  } else if (path == kProxyFtpPort) {
156    int val;
157    if (in_value->GetAsInteger(&val)) {
158      config_service->UISetProxyConfigToProxyPerScheme("ftp",
159          CreateProxyServerFromPort(
160              val, config.ftp_proxy, net::ProxyServer::SCHEME_HTTP));
161    }
162  } else if (path == kProxySocks) {
163    std::string val;
164    if (in_value->GetAsString(&val)) {
165      config_service->UISetProxyConfigToProxyPerScheme("socks",
166          CreateProxyServerFromHost(val, config.socks_proxy,
167                                    StartsWithASCII(val, "socks5://", false) ?
168                                        net::ProxyServer::SCHEME_SOCKS5 :
169                                        net::ProxyServer::SCHEME_SOCKS4));
170    }
171  } else if (path == kProxySocksPort) {
172    int val;
173    if (in_value->GetAsInteger(&val)) {
174      std::string host = config.socks_proxy.server.host_port_pair().host();
175      config_service->UISetProxyConfigToProxyPerScheme("socks",
176          CreateProxyServerFromPort(val, config.socks_proxy,
177                                    StartsWithASCII(host, "socks5://", false) ?
178                                        net::ProxyServer::SCHEME_SOCKS5 :
179                                        net::ProxyServer::SCHEME_SOCKS4));
180    }
181  } else if (path == kProxyIgnoreList) {
182    net::ProxyBypassRules bypass_rules;
183    if (in_value->GetType() == Value::TYPE_LIST) {
184      const ListValue* list_value = static_cast<const ListValue*>(in_value);
185      for (size_t x = 0; x < list_value->GetSize(); x++) {
186        std::string val;
187        if (list_value->GetString(x, &val)) {
188          bypass_rules.AddRuleFromString(val);
189        }
190      }
191      config_service->UISetProxyConfigBypassRules(bypass_rules);
192    }
193  }
194}
195
196bool ProxyCrosSettingsProvider::Get(const std::string& path,
197                                    Value** out_value) const {
198  bool found = false;
199  bool managed = false;
200  Value* data;
201  chromeos::ProxyConfigServiceImpl* config_service = GetConfigService();
202  chromeos::ProxyConfigServiceImpl::ProxyConfig config;
203  config_service->UIGetProxyConfig(&config);
204
205  if (path == kProxyPacUrl) {
206    if (config.automatic_proxy.pac_url.is_valid()) {
207      data = Value::CreateStringValue(config.automatic_proxy.pac_url.spec());
208      found = true;
209    }
210  } else if (path == kProxySingleHttp) {
211    found = (data = CreateServerHostValue(config.single_proxy));
212  } else if (path == kProxySingleHttpPort) {
213    found = (data = CreateServerPortValue(config.single_proxy));
214  } else if (path == kProxyHttpUrl) {
215    found = (data = CreateServerHostValue(config.http_proxy));
216  } else if (path == kProxyHttpsUrl) {
217    found = (data = CreateServerHostValue(config.https_proxy));
218  } else if (path == kProxyType) {
219    if (config.mode ==
220        chromeos::ProxyConfigServiceImpl::ProxyConfig::MODE_AUTO_DETECT ||
221        config.mode ==
222        chromeos::ProxyConfigServiceImpl::ProxyConfig::MODE_PAC_SCRIPT) {
223      data = Value::CreateIntegerValue(3);
224    } else if (config.mode ==
225        chromeos::ProxyConfigServiceImpl::ProxyConfig::MODE_SINGLE_PROXY ||
226        config.mode ==
227        chromeos::ProxyConfigServiceImpl::ProxyConfig::MODE_PROXY_PER_SCHEME) {
228      data = Value::CreateIntegerValue(2);
229    } else {
230      data = Value::CreateIntegerValue(1);
231    }
232    found = true;
233  } else if (path == kProxySingle) {
234    data = Value::CreateBooleanValue(config.mode ==
235        chromeos::ProxyConfigServiceImpl::ProxyConfig::MODE_SINGLE_PROXY);
236    found = true;
237  } else if (path == kProxyFtpUrl) {
238    found = (data = CreateServerHostValue(config.ftp_proxy));
239  } else if (path == kProxySocks) {
240    found = (data = CreateServerHostValue(config.socks_proxy));
241  } else if (path == kProxyHttpPort) {
242    found = (data = CreateServerPortValue(config.http_proxy));
243  } else if (path == kProxyHttpsPort) {
244    found = (data = CreateServerPortValue(config.https_proxy));
245  } else if (path == kProxyFtpPort) {
246    found = (data = CreateServerPortValue(config.ftp_proxy));
247  } else if (path == kProxySocksPort) {
248    found = (data = CreateServerPortValue(config.socks_proxy));
249  } else if (path == kProxyIgnoreList) {
250    ListValue* list =  new ListValue();
251    net::ProxyBypassRules::RuleList bypass_rules = config.bypass_rules.rules();
252    for (size_t x = 0; x < bypass_rules.size(); x++) {
253      list->Append(Value::CreateStringValue(bypass_rules[x]->ToString()));
254    }
255    *out_value = list;
256    return true;
257  }
258  if (found) {
259    DictionaryValue* dict = new DictionaryValue;
260    dict->Set("value", data);
261    dict->SetBoolean("managed", managed);
262    *out_value = dict;
263    return true;
264  } else {
265    *out_value = NULL;
266    return false;
267  }
268}
269
270bool ProxyCrosSettingsProvider::HandlesSetting(const std::string& path) {
271  return ::StartsWithASCII(path, "cros.session.proxy", true);
272}
273
274//----------------- ProxyCrosSettingsProvider: private methods -----------------
275
276chromeos::ProxyConfigServiceImpl*
277    ProxyCrosSettingsProvider::GetConfigService() const {
278  return g_browser_process->chromeos_proxy_config_service_impl();
279}
280
281net::ProxyServer ProxyCrosSettingsProvider::CreateProxyServerFromHost(
282    const std::string& host,
283    const ProxyConfigServiceImpl::ProxyConfig::ManualProxy& proxy,
284    net::ProxyServer::Scheme scheme) const {
285  uint16 port = 0;
286  if (proxy.server.is_valid())
287    port = proxy.server.host_port_pair().port();
288  if (host.length() == 0 && port == 0)
289    return net::ProxyServer();
290  if (port == 0)
291    port = net::ProxyServer::GetDefaultPortForScheme(scheme);
292  net::HostPortPair host_port_pair(host, port);
293  return net::ProxyServer(scheme, host_port_pair);
294}
295
296net::ProxyServer ProxyCrosSettingsProvider::CreateProxyServerFromPort(
297    uint16 port,
298    const ProxyConfigServiceImpl::ProxyConfig::ManualProxy& proxy,
299    net::ProxyServer::Scheme scheme) const {
300  std::string host;
301  if (proxy.server.is_valid())
302    host = proxy.server.host_port_pair().host();
303  if (host.length() == 0 && port == 0)
304    return net::ProxyServer();
305  net::HostPortPair host_port_pair(host, port);
306  return net::ProxyServer(scheme, host_port_pair);
307}
308
309Value* ProxyCrosSettingsProvider::CreateServerHostValue(
310    const ProxyConfigServiceImpl::ProxyConfig::ManualProxy& proxy) const {
311  return proxy.server.is_valid() ?
312         Value::CreateStringValue(proxy.server.host_port_pair().host()) :
313         NULL;
314}
315
316Value* ProxyCrosSettingsProvider::CreateServerPortValue(
317    const ProxyConfigServiceImpl::ProxyConfig::ManualProxy& proxy) const {
318  return proxy.server.is_valid() ?
319         Value::CreateIntegerValue(proxy.server.host_port_pair().port()) :
320         NULL;
321}
322
323}  // namespace chromeos
324