1// Copyright 2013 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/ui_proxy_config.h"
6
7#include "base/logging.h"
8#include "base/values.h"
9#include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
10#include "chrome/browser/prefs/proxy_config_dictionary.h"
11#include "net/proxy/proxy_config.h"
12
13namespace chromeos {
14
15UIProxyConfig::UIProxyConfig()
16    : mode(MODE_DIRECT),
17      state(ProxyPrefs::CONFIG_UNSET),
18      user_modifiable(true) {
19}
20
21UIProxyConfig::~UIProxyConfig() {
22}
23
24void UIProxyConfig::SetPacUrl(const GURL& pac_url) {
25  mode = UIProxyConfig::MODE_PAC_SCRIPT;
26  automatic_proxy.pac_url = pac_url;
27}
28
29void UIProxyConfig::SetSingleProxy(const net::ProxyServer& server) {
30  mode = UIProxyConfig::MODE_SINGLE_PROXY;
31  single_proxy.server = server;
32}
33
34void UIProxyConfig::SetProxyForScheme(const std::string& scheme,
35                                      const net::ProxyServer& server) {
36  ManualProxy* proxy = MapSchemeToProxy(scheme);
37  if (!proxy) {
38    NOTREACHED() << "Cannot set proxy: invalid scheme [" << scheme << "]";
39    return;
40  }
41  mode = UIProxyConfig::MODE_PROXY_PER_SCHEME;
42  proxy->server = server;
43}
44
45void UIProxyConfig::SetBypassRules(const net::ProxyBypassRules& rules) {
46  if (mode != UIProxyConfig::MODE_SINGLE_PROXY &&
47      mode != UIProxyConfig::MODE_PROXY_PER_SCHEME) {
48    NOTREACHED() << "Cannot set bypass rules for proxy mode [" << mode << "]";
49    return;
50  }
51  bypass_rules = rules;
52}
53
54bool UIProxyConfig::FromNetProxyConfig(const net::ProxyConfig& net_config) {
55  *this = UIProxyConfig();  // Reset to default.
56  const net::ProxyConfig::ProxyRules& rules = net_config.proxy_rules();
57  switch (rules.type) {
58    case net::ProxyConfig::ProxyRules::TYPE_NO_RULES:
59      if (!net_config.HasAutomaticSettings()) {
60        mode = UIProxyConfig::MODE_DIRECT;
61      } else if (net_config.auto_detect()) {
62        mode = UIProxyConfig::MODE_AUTO_DETECT;
63      } else if (net_config.has_pac_url()) {
64        mode = UIProxyConfig::MODE_PAC_SCRIPT;
65        automatic_proxy.pac_url = net_config.pac_url();
66      } else {
67        return false;
68      }
69      return true;
70    case net::ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY:
71      if (rules.single_proxies.IsEmpty())
72        return false;
73      mode = MODE_SINGLE_PROXY;
74      single_proxy.server = rules.single_proxies.Get();
75      bypass_rules = rules.bypass_rules;
76      return true;
77    case net::ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME:
78      // Make sure we have valid server for at least one of the protocols.
79      if (rules.proxies_for_http.IsEmpty() &&
80          rules.proxies_for_https.IsEmpty() &&
81          rules.proxies_for_ftp.IsEmpty() &&
82          rules.fallback_proxies.IsEmpty()) {
83        return false;
84      }
85      mode = MODE_PROXY_PER_SCHEME;
86      if (!rules.proxies_for_http.IsEmpty())
87        http_proxy.server = rules.proxies_for_http.Get();
88      if (!rules.proxies_for_https.IsEmpty())
89        https_proxy.server = rules.proxies_for_https.Get();
90      if (!rules.proxies_for_ftp.IsEmpty())
91        ftp_proxy.server = rules.proxies_for_ftp.Get();
92      if (!rules.fallback_proxies.IsEmpty())
93        socks_proxy.server = rules.fallback_proxies.Get();
94      bypass_rules = rules.bypass_rules;
95      return true;
96    default:
97      NOTREACHED() << "Unrecognized proxy config mode";
98      break;
99  }
100  return false;
101}
102
103base::DictionaryValue* UIProxyConfig::ToPrefProxyConfig() const {
104  switch (mode) {
105    case MODE_DIRECT: {
106      return ProxyConfigDictionary::CreateDirect();
107    }
108    case MODE_AUTO_DETECT: {
109      return ProxyConfigDictionary::CreateAutoDetect();
110    }
111    case MODE_PAC_SCRIPT: {
112      return ProxyConfigDictionary::CreatePacScript(
113          automatic_proxy.pac_url.spec(), false);
114    }
115    case MODE_SINGLE_PROXY: {
116      std::string spec;
117      if (single_proxy.server.is_valid())
118        spec = single_proxy.server.ToURI();
119      return ProxyConfigDictionary::CreateFixedServers(
120          spec, bypass_rules.ToString());
121    }
122    case MODE_PROXY_PER_SCHEME: {
123      std::string spec;
124      EncodeAndAppendProxyServer("http", http_proxy.server, &spec);
125      EncodeAndAppendProxyServer("https", https_proxy.server, &spec);
126      EncodeAndAppendProxyServer("ftp", ftp_proxy.server, &spec);
127      EncodeAndAppendProxyServer("socks", socks_proxy.server, &spec);
128      return ProxyConfigDictionary::CreateFixedServers(
129          spec, bypass_rules.ToString());
130    }
131    default:
132      break;
133  }
134  NOTREACHED() << "Unrecognized proxy config mode for preference";
135  return NULL;
136}
137
138UIProxyConfig::ManualProxy* UIProxyConfig::MapSchemeToProxy(
139    const std::string& scheme) {
140  if (scheme == "http")
141    return &http_proxy;
142  if (scheme == "https")
143    return &https_proxy;
144  if (scheme == "ftp")
145    return &ftp_proxy;
146  if (scheme == "socks")
147    return &socks_proxy;
148  NOTREACHED() << "Invalid scheme: " << scheme;
149  return NULL;
150}
151
152// static
153void UIProxyConfig::EncodeAndAppendProxyServer(const std::string& url_scheme,
154                                               const net::ProxyServer& server,
155                                               std::string* spec) {
156  if (!server.is_valid())
157    return;
158
159  if (!spec->empty())
160    *spec += ';';
161
162  if (!url_scheme.empty()) {
163    *spec += url_scheme;
164    *spec += "=";
165  }
166  *spec += server.ToURI();
167}
168
169}  // namespace chromeos
170