Home | History | Annotate | Download | only in browser
      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 "components/data_reduction_proxy/browser/data_reduction_proxy_params.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/command_line.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/metrics/field_trial.h"
     12 #include "base/time/time.h"
     13 #include "components/data_reduction_proxy/common/data_reduction_proxy_switches.h"
     14 #include "net/base/host_port_pair.h"
     15 #include "net/proxy/proxy_config.h"
     16 #include "net/proxy/proxy_info.h"
     17 #include "net/proxy/proxy_retry_info.h"
     18 #include "net/proxy/proxy_server.h"
     19 #include "net/proxy/proxy_service.h"
     20 #include "net/url_request/url_request.h"
     21 #include "net/url_request/url_request_context.h"
     22 #include "url/url_constants.h"
     23 
     24 using base::FieldTrialList;
     25 
     26 namespace {
     27 
     28 const char kEnabled[] = "Enabled";
     29 const char kDefaultOrigin[] = "https://proxy.googlezip.net:443/";
     30 const char kDevOrigin[] = "https://proxy-dev.googlezip.net:443/";
     31 const char kDevFallbackOrigin[] = "http://proxy-dev.googlezip.net:80/";
     32 const char kDefaultFallbackOrigin[] = "http://compress.googlezip.net:80/";
     33 // This is for a proxy that supports HTTP CONNECT to tunnel SSL traffic.
     34 // The proxy listens on port 443, but uses the HTTP protocol to set up
     35 // the tunnel, not HTTPS.
     36 const char kDefaultSslOrigin[] = "http://ssl.googlezip.net:443/";
     37 const char kDefaultAltOrigin[] = "http://ssl.googlezip.net:80/";
     38 const char kDefaultAltFallbackOrigin[] = "http://ssl.googlezip.net:80/";
     39 const char kDefaultProbeUrl[] = "http://check.googlezip.net/connect";
     40 const char kDefaultWarmupUrl[] = "http://www.gstatic.com/generate_204";
     41 
     42 }  // namespace
     43 
     44 namespace data_reduction_proxy {
     45 
     46 // static
     47 bool DataReductionProxyParams::IsIncludedInAlternativeFieldTrial() {
     48   const std::string group_name = base::FieldTrialList::FindFullName(
     49       "DataCompressionProxyAlternativeConfiguration");
     50   if (CommandLine::ForCurrentProcess()->HasSwitch(
     51           data_reduction_proxy::switches::kEnableDataReductionProxyAlt)) {
     52     return true;
     53   }
     54   return group_name == kEnabled;
     55 }
     56 
     57 // static
     58 bool DataReductionProxyParams::IsIncludedInPromoFieldTrial() {
     59   return FieldTrialList::FindFullName(
     60       "DataCompressionProxyPromoVisibility") == kEnabled;
     61 }
     62 
     63 // static
     64 bool DataReductionProxyParams::IsIncludedInPreconnectHintingFieldTrial() {
     65   return FieldTrialList::FindFullName(
     66           "DataCompressionProxyPreconnectHints") == kEnabled;
     67 }
     68 
     69 // static
     70 bool DataReductionProxyParams::IsIncludedInCriticalPathBypassFieldTrial() {
     71   return FieldTrialList::FindFullName(
     72           "DataCompressionProxyCriticalBypass") == kEnabled;
     73 }
     74 
     75 // static
     76 bool DataReductionProxyParams::IsIncludedInHoldbackFieldTrial() {
     77   return FieldTrialList::FindFullName(
     78       "DataCompressionProxyHoldback") == kEnabled;
     79 }
     80 
     81 // static
     82 bool DataReductionProxyParams::
     83     IsIncludedInRemoveMissingViaHeaderOtherBypassFieldTrial() {
     84   return FieldTrialList::FindFullName(
     85       "DataReductionProxyRemoveMissingViaHeaderOtherBypass") == kEnabled;
     86 }
     87 
     88 DataReductionProxyTypeInfo::DataReductionProxyTypeInfo()
     89     : proxy_servers(),
     90       is_fallback(false),
     91       is_alternative(false),
     92       is_ssl(false) {
     93 }
     94 
     95 DataReductionProxyTypeInfo::~DataReductionProxyTypeInfo(){
     96 }
     97 
     98 DataReductionProxyParams::DataReductionProxyParams(int flags)
     99     : allowed_((flags & kAllowed) == kAllowed),
    100       fallback_allowed_((flags & kFallbackAllowed) == kFallbackAllowed),
    101       alt_allowed_((flags & kAlternativeAllowed) == kAlternativeAllowed),
    102       alt_fallback_allowed_(
    103           (flags & kAlternativeFallbackAllowed) == kAlternativeFallbackAllowed),
    104       promo_allowed_((flags & kPromoAllowed) == kPromoAllowed),
    105       holdback_((flags & kHoldback) == kHoldback),
    106       configured_on_command_line_(false) {
    107   bool result = Init(
    108       allowed_, fallback_allowed_, alt_allowed_, alt_fallback_allowed_);
    109   DCHECK(result);
    110 }
    111 
    112 scoped_ptr<DataReductionProxyParams> DataReductionProxyParams::Clone() {
    113   return scoped_ptr<DataReductionProxyParams>(
    114       new DataReductionProxyParams(*this));
    115 }
    116 
    117 DataReductionProxyParams::DataReductionProxyParams(
    118     const DataReductionProxyParams& other)
    119     : origin_(other.origin_),
    120       fallback_origin_(other.fallback_origin_),
    121       ssl_origin_(other.ssl_origin_),
    122       alt_origin_(other.alt_origin_),
    123       alt_fallback_origin_(other.alt_fallback_origin_),
    124       probe_url_(other.probe_url_),
    125       warmup_url_(other.warmup_url_),
    126       allowed_(other.allowed_),
    127       fallback_allowed_(other.fallback_allowed_),
    128       alt_allowed_(other.alt_allowed_),
    129       alt_fallback_allowed_(other.alt_fallback_allowed_),
    130       promo_allowed_(other.promo_allowed_),
    131       holdback_(other.holdback_),
    132       configured_on_command_line_(other.configured_on_command_line_) {
    133 }
    134 
    135 DataReductionProxyParams::~DataReductionProxyParams() {
    136 }
    137 
    138 DataReductionProxyParams::DataReductionProxyList
    139 DataReductionProxyParams::GetAllowedProxies() const {
    140   DataReductionProxyList list;
    141   if (allowed_) {
    142     list.push_back(origin_);
    143   }
    144   if (allowed_ && fallback_allowed_)
    145     list.push_back(fallback_origin_);
    146   if (alt_allowed_) {
    147     list.push_back(alt_origin_);
    148     list.push_back(ssl_origin_);
    149   }
    150   if (alt_allowed_ && alt_fallback_allowed_)
    151     list.push_back(alt_fallback_origin_);
    152   return list;
    153 }
    154 
    155 DataReductionProxyParams::DataReductionProxyParams(int flags,
    156                                                    bool should_call_init)
    157     : allowed_((flags & kAllowed) == kAllowed),
    158       fallback_allowed_((flags & kFallbackAllowed) == kFallbackAllowed),
    159       alt_allowed_((flags & kAlternativeAllowed) == kAlternativeAllowed),
    160       alt_fallback_allowed_(
    161           (flags & kAlternativeFallbackAllowed) == kAlternativeFallbackAllowed),
    162       promo_allowed_((flags & kPromoAllowed) == kPromoAllowed),
    163       holdback_((flags & kHoldback) == kHoldback),
    164       configured_on_command_line_(false) {
    165   if (should_call_init) {
    166     bool result = Init(
    167         allowed_, fallback_allowed_, alt_allowed_, alt_fallback_allowed_);
    168     DCHECK(result);
    169   }
    170 }
    171 
    172 bool DataReductionProxyParams::Init(bool allowed,
    173                                     bool fallback_allowed,
    174                                     bool alt_allowed,
    175                                     bool alt_fallback_allowed) {
    176   InitWithoutChecks();
    177   // Verify that all necessary params are set.
    178   if (allowed) {
    179     if (!origin_.is_valid()) {
    180       DVLOG(1) << "Invalid data reduction proxy origin: " << origin_.spec();
    181       return false;
    182     }
    183   }
    184 
    185   if (allowed && fallback_allowed) {
    186     if (!fallback_origin_.is_valid()) {
    187       DVLOG(1) << "Invalid data reduction proxy fallback origin: "
    188           << fallback_origin_.spec();
    189       return false;
    190     }
    191   }
    192 
    193   if (alt_allowed) {
    194     if (!allowed) {
    195       DVLOG(1) << "Alternative data reduction proxy configuration cannot "
    196           << "be allowed if the regular configuration is not allowed";
    197       return false;
    198     }
    199     if (!alt_origin_.is_valid()) {
    200       DVLOG(1) << "Invalid alternative origin:" << alt_origin_.spec();
    201       return false;
    202     }
    203     if (!ssl_origin_.is_valid()) {
    204       DVLOG(1) << "Invalid ssl origin: " << ssl_origin_.spec();
    205       return false;
    206     }
    207   }
    208 
    209   if (alt_allowed && alt_fallback_allowed) {
    210     if (!alt_fallback_origin_.is_valid()) {
    211       DVLOG(1) << "Invalid alternative fallback origin:"
    212           << alt_fallback_origin_.spec();
    213       return false;
    214     }
    215   }
    216 
    217   if (allowed && !probe_url_.is_valid()) {
    218     DVLOG(1) << "Invalid probe url: <null>";
    219     return false;
    220   }
    221 
    222   if (fallback_allowed_ && !allowed_) {
    223     DVLOG(1) << "The data reduction proxy fallback cannot be allowed if "
    224         << "the data reduction proxy is not allowed";
    225     return false;
    226   }
    227   if (alt_fallback_allowed_ && !alt_allowed_) {
    228     DVLOG(1) << "The data reduction proxy alternative fallback cannot be "
    229         << "allowed if the alternative data reduction proxy is not allowed";
    230     return false;
    231   }
    232   if (promo_allowed_ && !allowed_) {
    233     DVLOG(1) << "The data reduction proxy promo cannot be allowed if the "
    234         << "data reduction proxy is not allowed";
    235     return false;
    236   }
    237   return true;
    238 
    239 }
    240 
    241 void DataReductionProxyParams::InitWithoutChecks() {
    242   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    243   std::string origin;
    244   if (!command_line.HasSwitch(switches::kDisableDataReductionProxyDev)) {
    245       origin = command_line.GetSwitchValueASCII(
    246           switches::kDataReductionProxyDev);
    247   }
    248   if (origin.empty())
    249     origin = command_line.GetSwitchValueASCII(switches::kDataReductionProxy);
    250   std::string fallback_origin =
    251       command_line.GetSwitchValueASCII(switches::kDataReductionProxyFallback);
    252   std::string ssl_origin =
    253       command_line.GetSwitchValueASCII(switches::kDataReductionSSLProxy);
    254   std::string alt_origin =
    255       command_line.GetSwitchValueASCII(switches::kDataReductionProxyAlt);
    256   std::string alt_fallback_origin = command_line.GetSwitchValueASCII(
    257       switches::kDataReductionProxyAltFallback);
    258 
    259   configured_on_command_line_ =
    260       !(origin.empty() && fallback_origin.empty() && ssl_origin.empty() &&
    261           alt_origin.empty() && alt_fallback_origin.empty());
    262 
    263 
    264   // Configuring the proxy on the command line overrides the values of
    265   // |allowed_| and |alt_allowed_|.
    266   if (configured_on_command_line_)
    267     allowed_ = true;
    268   if (!(ssl_origin.empty() &&
    269         alt_origin.empty()))
    270     alt_allowed_ = true;
    271 
    272   std::string probe_url = command_line.GetSwitchValueASCII(
    273       switches::kDataReductionProxyProbeURL);
    274   std::string warmup_url = command_line.GetSwitchValueASCII(
    275       switches::kDataReductionProxyWarmupURL);
    276 
    277   // Set from preprocessor constants those params that are not specified on the
    278   // command line.
    279   if (origin.empty())
    280     origin = GetDefaultDevOrigin();
    281   if (origin.empty())
    282     origin = GetDefaultOrigin();
    283   if (fallback_origin.empty())
    284     fallback_origin = GetDefaultDevFallbackOrigin();
    285   if (fallback_origin.empty())
    286     fallback_origin = GetDefaultFallbackOrigin();
    287   if (ssl_origin.empty())
    288     ssl_origin = GetDefaultSSLOrigin();
    289   if (alt_origin.empty())
    290     alt_origin = GetDefaultAltOrigin();
    291   if (alt_fallback_origin.empty())
    292     alt_fallback_origin = GetDefaultAltFallbackOrigin();
    293   if (probe_url.empty())
    294     probe_url = GetDefaultProbeURL();
    295   if (warmup_url.empty())
    296     warmup_url = GetDefaultWarmupURL();
    297 
    298   origin_ = GURL(origin);
    299   fallback_origin_ = GURL(fallback_origin);
    300   ssl_origin_ = GURL(ssl_origin);
    301   alt_origin_ = GURL(alt_origin);
    302   alt_fallback_origin_ = GURL(alt_fallback_origin);
    303   probe_url_ = GURL(probe_url);
    304   warmup_url_ = GURL(warmup_url);
    305 
    306 }
    307 
    308 bool DataReductionProxyParams::WasDataReductionProxyUsed(
    309     const net::URLRequest* request,
    310     DataReductionProxyTypeInfo* proxy_info) const {
    311   DCHECK(request);
    312   return IsDataReductionProxy(request->proxy_server(), proxy_info);
    313 }
    314 
    315 bool DataReductionProxyParams::IsDataReductionProxy(
    316     const net::HostPortPair& host_port_pair,
    317     DataReductionProxyTypeInfo* proxy_info) const {
    318   if (net::HostPortPair::FromURL(origin()).Equals(host_port_pair)) {
    319     if (proxy_info) {
    320       proxy_info->proxy_servers.first = origin();
    321       if (fallback_allowed())
    322         proxy_info->proxy_servers.second = fallback_origin();
    323     }
    324     return true;
    325   }
    326 
    327   if (fallback_allowed() &&
    328       net::HostPortPair::FromURL(fallback_origin()).Equals(host_port_pair)) {
    329     if (proxy_info) {
    330       proxy_info->proxy_servers.first = fallback_origin();
    331       proxy_info->proxy_servers.second = GURL();
    332       proxy_info->is_fallback = true;
    333     }
    334     return true;
    335   }
    336   if (net::HostPortPair::FromURL(alt_origin()).Equals(host_port_pair)) {
    337     if (proxy_info) {
    338       proxy_info->proxy_servers.first = alt_origin();
    339       proxy_info->is_alternative = true;
    340       if (alternative_fallback_allowed())
    341         proxy_info->proxy_servers.second = alt_fallback_origin();
    342     }
    343     return true;
    344   }
    345   if (alternative_fallback_allowed() &&
    346       net::HostPortPair::FromURL(alt_fallback_origin()).Equals(
    347       host_port_pair)) {
    348     if (proxy_info) {
    349       proxy_info->proxy_servers.first = alt_fallback_origin();
    350       proxy_info->proxy_servers.second = GURL();
    351       proxy_info->is_fallback = true;
    352       proxy_info->is_alternative = true;
    353     }
    354     return true;
    355   }
    356   if (net::HostPortPair::FromURL(ssl_origin()).Equals(host_port_pair)) {
    357     if (proxy_info) {
    358       proxy_info->proxy_servers.first = ssl_origin();
    359       proxy_info->proxy_servers.second = GURL();
    360       proxy_info->is_ssl = true;
    361     }
    362     return true;
    363   }
    364   return false;
    365 }
    366 
    367 bool DataReductionProxyParams::IsBypassedByDataReductionProxyLocalRules(
    368     const net::URLRequest& request,
    369     const net::ProxyConfig& data_reduction_proxy_config) const {
    370   DCHECK(request.context());
    371   DCHECK(request.context()->proxy_service());
    372   net::ProxyInfo result;
    373   data_reduction_proxy_config.proxy_rules().Apply(
    374       request.url(), &result);
    375   if (!result.proxy_server().is_valid())
    376     return true;
    377   if (result.proxy_server().is_direct())
    378     return true;
    379   return !IsDataReductionProxy(result.proxy_server().host_port_pair(), NULL);
    380 }
    381 
    382 std::string DataReductionProxyParams::GetDefaultDevOrigin() const {
    383   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    384   if (command_line.HasSwitch(switches::kDisableDataReductionProxyDev))
    385     return std::string();
    386   if (command_line.HasSwitch(switches::kEnableDataReductionProxyDev) ||
    387       (FieldTrialList::FindFullName("DataCompressionProxyDevRollout") ==
    388          kEnabled)) {
    389     return kDevOrigin;
    390   }
    391   return std::string();
    392 }
    393 
    394 std::string DataReductionProxyParams::GetDefaultDevFallbackOrigin() const {
    395   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    396   if (command_line.HasSwitch(switches::kDisableDataReductionProxyDev))
    397     return std::string();
    398   if (command_line.HasSwitch(switches::kEnableDataReductionProxyDev) ||
    399       (FieldTrialList::FindFullName("DataCompressionProxyDevRollout") ==
    400            kEnabled)) {
    401     return kDevFallbackOrigin;
    402   }
    403   return std::string();
    404 }
    405 
    406 bool DataReductionProxyParams::AreDataReductionProxiesBypassed(
    407     const net::URLRequest& request, base::TimeDelta* min_retry_delay) const {
    408   if (request.context() != NULL &&
    409       request.context()->proxy_service() != NULL) {
    410     return AreProxiesBypassed(
    411         request.context()->proxy_service()->proxy_retry_info(),
    412         request.url().SchemeIs(url::kHttpsScheme),
    413         min_retry_delay);
    414   }
    415 
    416   return false;
    417 }
    418 
    419 bool DataReductionProxyParams::AreProxiesBypassed(
    420     const net::ProxyRetryInfoMap& retry_map,
    421     bool is_https,
    422     base::TimeDelta* min_retry_delay) const {
    423   if (retry_map.size() == 0)
    424     return false;
    425 
    426   // If the request is https, consider only the ssl proxy.
    427   if (is_https) {
    428     if (alt_allowed_) {
    429       return ArePrimaryAndFallbackBypassed(
    430           retry_map, ssl_origin_, GURL(), min_retry_delay);
    431     }
    432     NOTREACHED();
    433     return false;
    434   }
    435 
    436   if (allowed_ && ArePrimaryAndFallbackBypassed(
    437       retry_map, origin_, fallback_origin_, min_retry_delay)) {
    438     return true;
    439   }
    440 
    441   if (alt_allowed_ && ArePrimaryAndFallbackBypassed(
    442       retry_map, alt_origin_, alt_fallback_origin_, min_retry_delay)) {
    443     return true;
    444   }
    445 
    446   return false;
    447 }
    448 
    449 bool DataReductionProxyParams::ArePrimaryAndFallbackBypassed(
    450     const net::ProxyRetryInfoMap& retry_map,
    451     const GURL& primary,
    452     const GURL& fallback,
    453     base::TimeDelta* min_retry_delay) const {
    454   net::ProxyRetryInfoMap::const_iterator found = retry_map.end();
    455   if (min_retry_delay)
    456     *min_retry_delay = base::TimeDelta::Max();
    457 
    458   // Look for the primary proxy in the retry map. This must be done before
    459   // looking for the fallback in order to assign |min_retry_delay| if the
    460   // primary proxy has a shorter delay.
    461   if (!fallback_allowed_ || !fallback.is_valid() || min_retry_delay) {
    462     found = retry_map.find(
    463         net::ProxyServer(primary.SchemeIs(url::kHttpsScheme) ?
    464             net::ProxyServer::SCHEME_HTTPS :
    465             net::ProxyServer::SCHEME_HTTP,
    466         net::HostPortPair::FromURL(primary)).ToURI());
    467     if (found != retry_map.end() && min_retry_delay) {
    468       *min_retry_delay = found->second.current_delay;
    469     }
    470   }
    471 
    472   if (fallback_allowed_ && fallback.is_valid()) {
    473     // If fallback is allowed, only the fallback proxy needs to be on the retry
    474     // map to know if there was a bypass. We can reset found and forget if the
    475     // primary was on the retry map.
    476     found = retry_map.find(
    477         net::ProxyServer(fallback.SchemeIs(url::kHttpsScheme) ?
    478                              net::ProxyServer::SCHEME_HTTPS :
    479                              net::ProxyServer::SCHEME_HTTP,
    480                          net::HostPortPair::FromURL(fallback)).ToURI());
    481     if (found != retry_map.end() &&
    482         min_retry_delay &&
    483         *min_retry_delay > found->second.current_delay) {
    484       *min_retry_delay = found->second.current_delay;
    485     }
    486   }
    487 
    488   return found != retry_map.end();
    489 }
    490 
    491 // TODO(kundaji): Remove tests for macro definitions.
    492 std::string DataReductionProxyParams::GetDefaultOrigin() const {
    493   return kDefaultOrigin;
    494 }
    495 
    496 std::string DataReductionProxyParams::GetDefaultFallbackOrigin() const {
    497   return kDefaultFallbackOrigin;
    498 }
    499 
    500 std::string DataReductionProxyParams::GetDefaultSSLOrigin() const {
    501   return kDefaultSslOrigin;
    502 }
    503 
    504 std::string DataReductionProxyParams::GetDefaultAltOrigin() const {
    505   return kDefaultAltOrigin;
    506 }
    507 
    508 std::string DataReductionProxyParams::GetDefaultAltFallbackOrigin() const {
    509   return kDefaultAltFallbackOrigin;
    510 }
    511 
    512 std::string DataReductionProxyParams::GetDefaultProbeURL() const {
    513   return kDefaultProbeUrl;
    514 }
    515 
    516 std::string DataReductionProxyParams::GetDefaultWarmupURL() const {
    517   return kDefaultWarmupUrl;
    518 }
    519 
    520 }  // namespace data_reduction_proxy
    521