Home | History | Annotate | Download | only in proxy
      1 // Copyright (c) 2009 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/init_proxy_resolver.h"
      6 
      7 #include "base/compiler_specific.h"
      8 #include "base/format_macros.h"
      9 #include "base/logging.h"
     10 #include "base/string_util.h"
     11 #include "net/base/load_log.h"
     12 #include "net/base/net_errors.h"
     13 #include "net/proxy/proxy_config.h"
     14 #include "net/proxy/proxy_resolver.h"
     15 #include "net/proxy/proxy_script_fetcher.h"
     16 
     17 namespace net {
     18 
     19 InitProxyResolver::InitProxyResolver(ProxyResolver* resolver,
     20                                      ProxyScriptFetcher* proxy_script_fetcher)
     21     : resolver_(resolver),
     22       proxy_script_fetcher_(proxy_script_fetcher),
     23       ALLOW_THIS_IN_INITIALIZER_LIST(io_callback_(
     24           this, &InitProxyResolver::OnIOCompletion)),
     25       user_callback_(NULL),
     26       current_pac_url_index_(0u),
     27       next_state_(STATE_NONE) {
     28 }
     29 
     30 InitProxyResolver::~InitProxyResolver() {
     31   if (next_state_ != STATE_NONE)
     32     Cancel();
     33 }
     34 
     35 int InitProxyResolver::Init(const ProxyConfig& config,
     36                             CompletionCallback* callback,
     37                             LoadLog* load_log) {
     38   DCHECK_EQ(STATE_NONE, next_state_);
     39   DCHECK(callback);
     40   DCHECK(config.MayRequirePACResolver());
     41   DCHECK(!load_log_);
     42 
     43   load_log_ = load_log;
     44 
     45   LoadLog::BeginEvent(load_log_, LoadLog::TYPE_INIT_PROXY_RESOLVER);
     46 
     47   pac_urls_ = BuildPacUrlsFallbackList(config);
     48   DCHECK(!pac_urls_.empty());
     49 
     50   next_state_ = GetStartState();
     51 
     52   int rv = DoLoop(OK);
     53   if (rv == ERR_IO_PENDING)
     54     user_callback_ = callback;
     55   else
     56     DidCompleteInit();
     57 
     58   return rv;
     59 }
     60 
     61 // Initialize the fallback rules.
     62 // (1) WPAD
     63 // (2) Custom PAC URL.
     64 InitProxyResolver::UrlList InitProxyResolver::BuildPacUrlsFallbackList(
     65     const ProxyConfig& config) const {
     66   UrlList pac_urls;
     67   if (config.auto_detect) {
     68      GURL pac_url = resolver_->expects_pac_bytes() ?
     69         GURL("http://wpad/wpad.dat") : GURL();
     70      pac_urls.push_back(pac_url);
     71   }
     72   if (config.pac_url.is_valid())
     73     pac_urls.push_back(config.pac_url);
     74   return pac_urls;
     75 }
     76 
     77 void InitProxyResolver::OnIOCompletion(int result) {
     78   DCHECK_NE(STATE_NONE, next_state_);
     79   int rv = DoLoop(result);
     80   if (rv != ERR_IO_PENDING) {
     81     DidCompleteInit();
     82     DoCallback(rv);
     83   }
     84 }
     85 
     86 int InitProxyResolver::DoLoop(int result) {
     87   DCHECK_NE(next_state_, STATE_NONE);
     88   int rv = result;
     89   do {
     90     State state = next_state_;
     91     next_state_ = STATE_NONE;
     92     switch (state) {
     93       case STATE_FETCH_PAC_SCRIPT:
     94         DCHECK_EQ(OK, rv);
     95         rv = DoFetchPacScript();
     96         break;
     97       case STATE_FETCH_PAC_SCRIPT_COMPLETE:
     98         rv = DoFetchPacScriptComplete(rv);
     99         break;
    100       case STATE_SET_PAC_SCRIPT:
    101         DCHECK_EQ(OK, rv);
    102         rv = DoSetPacScript();
    103         break;
    104       case STATE_SET_PAC_SCRIPT_COMPLETE:
    105         rv = DoSetPacScriptComplete(rv);
    106         break;
    107       default:
    108         NOTREACHED() << "bad state";
    109         rv = ERR_UNEXPECTED;
    110         break;
    111     }
    112   } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
    113   return rv;
    114 }
    115 
    116 void InitProxyResolver::DoCallback(int result) {
    117   DCHECK_NE(ERR_IO_PENDING, result);
    118   DCHECK(user_callback_);
    119   user_callback_->Run(result);
    120 }
    121 
    122 int InitProxyResolver::DoFetchPacScript() {
    123   DCHECK(resolver_->expects_pac_bytes());
    124 
    125   LoadLog::BeginEvent(load_log_,
    126       LoadLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT);
    127 
    128   next_state_ = STATE_FETCH_PAC_SCRIPT_COMPLETE;
    129 
    130   const GURL& pac_url = current_pac_url();
    131 
    132   LoadLog::AddString(load_log_, pac_url.spec());
    133 
    134   if (!proxy_script_fetcher_) {
    135     LoadLog::AddStringLiteral(load_log_,
    136         "Can't download PAC script, because no fetcher was specified");
    137     return ERR_UNEXPECTED;
    138   }
    139 
    140   return proxy_script_fetcher_->Fetch(pac_url, &pac_bytes_, &io_callback_);
    141 }
    142 
    143 int InitProxyResolver::DoFetchPacScriptComplete(int result) {
    144   DCHECK(resolver_->expects_pac_bytes());
    145 
    146   LoadLog::AddString(load_log_,
    147       StringPrintf(
    148           "Completed fetch with result %s. Received %" PRIuS " bytes",
    149           ErrorToString(result),
    150           pac_bytes_.size()));
    151 
    152   LoadLog::EndEvent(load_log_,
    153       LoadLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT);
    154 
    155   if (result != OK)
    156     return TryToFallbackPacUrl(result);
    157 
    158   next_state_ = STATE_SET_PAC_SCRIPT;
    159   return result;
    160 }
    161 
    162 int InitProxyResolver::DoSetPacScript() {
    163   LoadLog::BeginEvent(load_log_,
    164       LoadLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT);
    165 
    166   const GURL& pac_url = current_pac_url();
    167 
    168   next_state_ = STATE_SET_PAC_SCRIPT_COMPLETE;
    169 
    170   return resolver_->expects_pac_bytes() ?
    171       resolver_->SetPacScriptByData(pac_bytes_, &io_callback_) :
    172       resolver_->SetPacScriptByUrl(pac_url, &io_callback_);
    173 }
    174 
    175 int InitProxyResolver::DoSetPacScriptComplete(int result) {
    176   if (result != OK) {
    177     LoadLog::AddString(load_log_,
    178         StringPrintf("Failed initializing the PAC script with error: %s",
    179                      ErrorToString(result)));
    180     LoadLog::EndEvent(load_log_,
    181         LoadLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT);
    182     return TryToFallbackPacUrl(result);
    183   }
    184 
    185   LoadLog::AddStringLiteral(load_log_, "Successfully initialized PAC script.");
    186 
    187   LoadLog::EndEvent(load_log_,
    188       LoadLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT);
    189   return result;
    190 }
    191 
    192 int InitProxyResolver::TryToFallbackPacUrl(int error) {
    193   DCHECK_LT(error, 0);
    194 
    195   if (current_pac_url_index_ + 1 >= pac_urls_.size()) {
    196     // Nothing left to fall back to.
    197     return error;
    198   }
    199 
    200   // Advance to next URL in our list.
    201   ++current_pac_url_index_;
    202 
    203   LoadLog::AddStringLiteral(load_log_, "Falling back to next PAC URL...");
    204 
    205   next_state_ = GetStartState();
    206 
    207   return OK;
    208 }
    209 
    210 InitProxyResolver::State InitProxyResolver::GetStartState() const {
    211   return resolver_->expects_pac_bytes() ?
    212       STATE_FETCH_PAC_SCRIPT : STATE_SET_PAC_SCRIPT;
    213 }
    214 
    215 const GURL& InitProxyResolver::current_pac_url() const {
    216   DCHECK_LT(current_pac_url_index_, pac_urls_.size());
    217   return pac_urls_[current_pac_url_index_];
    218 }
    219 
    220 void InitProxyResolver::DidCompleteInit() {
    221   LoadLog::EndEvent(load_log_, LoadLog::TYPE_INIT_PROXY_RESOLVER);
    222 }
    223 
    224 void InitProxyResolver::Cancel() {
    225   DCHECK_NE(STATE_NONE, next_state_);
    226 
    227   LoadLog::AddEvent(load_log_, LoadLog::TYPE_CANCELLED);
    228 
    229   switch (next_state_) {
    230     case STATE_FETCH_PAC_SCRIPT_COMPLETE:
    231       proxy_script_fetcher_->Cancel();
    232       break;
    233     case STATE_SET_PAC_SCRIPT_COMPLETE:
    234       resolver_->CancelSetPacScript();
    235       break;
    236     default:
    237       NOTREACHED();
    238       break;
    239   }
    240 
    241   DidCompleteInit();
    242 }
    243 
    244 }  // namespace net
    245