Home | History | Annotate | Download | only in proxy
      1 // Copyright (c) 2010 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 "net/proxy/proxy_config.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/string_tokenizer.h"
      9 #include "base/string_util.h"
     10 #include "base/values.h"
     11 #include "net/proxy/proxy_info.h"
     12 
     13 namespace net {
     14 
     15 namespace {
     16 
     17 // If |proxy| is valid, sets it in |dict| under the key |name|.
     18 void AddProxyToValue(const char* name,
     19                      const ProxyServer& proxy,
     20                      DictionaryValue* dict) {
     21   if (proxy.is_valid())
     22     dict->SetString(name, proxy.ToURI());
     23 }
     24 
     25 }  // namespace
     26 
     27 ProxyConfig::ProxyRules::ProxyRules()
     28     : reverse_bypass(false),
     29       type(TYPE_NO_RULES) {
     30 }
     31 
     32 ProxyConfig::ProxyRules::~ProxyRules() {
     33 }
     34 
     35 void ProxyConfig::ProxyRules::Apply(const GURL& url, ProxyInfo* result) {
     36   if (empty()) {
     37     result->UseDirect();
     38     return;
     39   }
     40 
     41   bool bypass_proxy = bypass_rules.Matches(url);
     42   if (reverse_bypass)
     43     bypass_proxy = !bypass_proxy;
     44   if (bypass_proxy) {
     45     result->UseDirect();
     46     return;
     47   }
     48 
     49   switch (type) {
     50     case ProxyRules::TYPE_SINGLE_PROXY: {
     51       result->UseProxyServer(single_proxy);
     52       return;
     53     }
     54     case ProxyRules::TYPE_PROXY_PER_SCHEME: {
     55       const ProxyServer* entry = MapUrlSchemeToProxy(url.scheme());
     56       if (entry) {
     57         result->UseProxyServer(*entry);
     58       } else {
     59         // We failed to find a matching proxy server for the current URL
     60         // scheme. Default to direct.
     61         result->UseDirect();
     62       }
     63       return;
     64     }
     65     default: {
     66       result->UseDirect();
     67       NOTREACHED();
     68       return;
     69     }
     70   }
     71 }
     72 
     73 void ProxyConfig::ProxyRules::ParseFromString(const std::string& proxy_rules) {
     74   // Reset.
     75   type = TYPE_NO_RULES;
     76   single_proxy = ProxyServer();
     77   proxy_for_http = ProxyServer();
     78   proxy_for_https = ProxyServer();
     79   proxy_for_ftp = ProxyServer();
     80   fallback_proxy = ProxyServer();
     81 
     82   StringTokenizer proxy_server_list(proxy_rules, ";");
     83   while (proxy_server_list.GetNext()) {
     84     StringTokenizer proxy_server_for_scheme(
     85         proxy_server_list.token_begin(), proxy_server_list.token_end(), "=");
     86 
     87     while (proxy_server_for_scheme.GetNext()) {
     88       std::string url_scheme = proxy_server_for_scheme.token();
     89 
     90       // If we fail to get the proxy server here, it means that
     91       // this is a regular proxy server configuration, i.e. proxies
     92       // are not configured per protocol.
     93       if (!proxy_server_for_scheme.GetNext()) {
     94         if (type == TYPE_PROXY_PER_SCHEME)
     95           continue;  // Unexpected.
     96         single_proxy = ProxyServer::FromURI(url_scheme,
     97                                             ProxyServer::SCHEME_HTTP);
     98         type = TYPE_SINGLE_PROXY;
     99         return;
    100       }
    101 
    102       // Trim whitespace off the url scheme.
    103       TrimWhitespaceASCII(url_scheme, TRIM_ALL, &url_scheme);
    104 
    105       // Add it to the per-scheme mappings (if supported scheme).
    106       type = TYPE_PROXY_PER_SCHEME;
    107       ProxyServer* entry = MapUrlSchemeToProxyNoFallback(url_scheme);
    108       ProxyServer::Scheme default_scheme = ProxyServer::SCHEME_HTTP;
    109 
    110       // socks=XXX is inconsistent with the other formats, since "socks"
    111       // is not a URL scheme. Rather this means "for everything else, send
    112       // it to the SOCKS proxy server XXX".
    113       if (url_scheme == "socks") {
    114         DCHECK(!entry);
    115         entry = &fallback_proxy;
    116         default_scheme = ProxyServer::SCHEME_SOCKS4;
    117       }
    118 
    119       if (entry) {
    120         *entry = ProxyServer::FromURI(proxy_server_for_scheme.token(),
    121                                       default_scheme);
    122       }
    123     }
    124   }
    125 }
    126 
    127 const ProxyServer* ProxyConfig::ProxyRules::MapUrlSchemeToProxy(
    128     const std::string& url_scheme) const {
    129   const ProxyServer* proxy_server =
    130       const_cast<ProxyRules*>(this)->MapUrlSchemeToProxyNoFallback(url_scheme);
    131   if (proxy_server && proxy_server->is_valid())
    132     return proxy_server;
    133   if (fallback_proxy.is_valid())
    134     return &fallback_proxy;
    135   return NULL;  // No mapping for this scheme. Use direct.
    136 }
    137 
    138 bool ProxyConfig::ProxyRules::Equals(const ProxyRules& other) const {
    139   return type == other.type &&
    140          single_proxy == other.single_proxy &&
    141          proxy_for_http == other.proxy_for_http &&
    142          proxy_for_https == other.proxy_for_https &&
    143          proxy_for_ftp == other.proxy_for_ftp &&
    144          fallback_proxy == other.fallback_proxy &&
    145          bypass_rules.Equals(other.bypass_rules) &&
    146          reverse_bypass == other.reverse_bypass;
    147 }
    148 
    149 ProxyServer* ProxyConfig::ProxyRules::MapUrlSchemeToProxyNoFallback(
    150     const std::string& scheme) {
    151   DCHECK_EQ(TYPE_PROXY_PER_SCHEME, type);
    152   if (scheme == "http")
    153     return &proxy_for_http;
    154   if (scheme == "https")
    155     return &proxy_for_https;
    156   if (scheme == "ftp")
    157     return &proxy_for_ftp;
    158   return NULL;  // No mapping for this scheme.
    159 }
    160 
    161 ProxyConfig::ProxyConfig() : auto_detect_(false), id_(INVALID_ID) {
    162 }
    163 
    164 ProxyConfig::ProxyConfig(const ProxyConfig& config)
    165     : auto_detect_(config.auto_detect_),
    166       pac_url_(config.pac_url_),
    167       proxy_rules_(config.proxy_rules_),
    168       id_(config.id_) {
    169 }
    170 
    171 ProxyConfig::~ProxyConfig() {
    172 }
    173 
    174 ProxyConfig& ProxyConfig::operator=(const ProxyConfig& config) {
    175   auto_detect_ = config.auto_detect_;
    176   pac_url_ = config.pac_url_;
    177   proxy_rules_ = config.proxy_rules_;
    178   id_ = config.id_;
    179   return *this;
    180 }
    181 
    182 bool ProxyConfig::Equals(const ProxyConfig& other) const {
    183   // The two configs can have different IDs.  We are just interested in if they
    184   // have the same settings.
    185   return auto_detect_ == other.auto_detect_ &&
    186          pac_url_ == other.pac_url_ &&
    187          proxy_rules_.Equals(other.proxy_rules());
    188 }
    189 
    190 bool ProxyConfig::HasAutomaticSettings() const {
    191   return auto_detect_ || has_pac_url();
    192 }
    193 
    194 void ProxyConfig::ClearAutomaticSettings() {
    195   auto_detect_ = false;
    196   pac_url_ = GURL();
    197 }
    198 
    199 Value* ProxyConfig::ToValue() const {
    200   DictionaryValue* dict = new DictionaryValue();
    201 
    202   // Output the automatic settings.
    203   if (auto_detect_)
    204     dict->SetBoolean("auto_detect", auto_detect_);
    205   if (has_pac_url())
    206     dict->SetString("pac_url", pac_url_.possibly_invalid_spec());
    207 
    208   // Output the manual settings.
    209   if (proxy_rules_.type != ProxyRules::TYPE_NO_RULES) {
    210     switch (proxy_rules_.type) {
    211       case ProxyRules::TYPE_SINGLE_PROXY:
    212         AddProxyToValue("single_proxy", proxy_rules_.single_proxy, dict);
    213         break;
    214       case ProxyRules::TYPE_PROXY_PER_SCHEME: {
    215         DictionaryValue* dict2 = new DictionaryValue();
    216         AddProxyToValue("http", proxy_rules_.proxy_for_http, dict2);
    217         AddProxyToValue("https", proxy_rules_.proxy_for_https, dict2);
    218         AddProxyToValue("ftp", proxy_rules_.proxy_for_ftp, dict2);
    219         AddProxyToValue("fallback", proxy_rules_.fallback_proxy, dict2);
    220         dict->Set("proxy_per_scheme", dict2);
    221         break;
    222       }
    223       default:
    224         NOTREACHED();
    225     }
    226 
    227     // Output the bypass rules.
    228     const ProxyBypassRules& bypass = proxy_rules_.bypass_rules;
    229     if (!bypass.rules().empty()) {
    230       if (proxy_rules_.reverse_bypass)
    231         dict->SetBoolean("reverse_bypass", true);
    232 
    233       ListValue* list = new ListValue();
    234 
    235       for (ProxyBypassRules::RuleList::const_iterator it =
    236               bypass.rules().begin();
    237            it != bypass.rules().end(); ++it) {
    238         list->Append(Value::CreateStringValue((*it)->ToString()));
    239       }
    240 
    241       dict->Set("bypass_list", list);
    242     }
    243   }
    244 
    245   return dict;
    246 }
    247 
    248 }  // namespace net
    249 
    250