Home | History | Annotate | Download | only in proxy
      1 // Copyright (c) 2012 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 #ifndef NET_PROXY_PROXY_SCRIPT_DECIDER_H_
      6 #define NET_PROXY_PROXY_SCRIPT_DECIDER_H_
      7 
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/memory/ref_counted.h"
     12 #include "base/strings/string16.h"
     13 #include "base/time/time.h"
     14 #include "base/timer/timer.h"
     15 #include "net/base/address_list.h"
     16 #include "net/base/completion_callback.h"
     17 #include "net/base/net_export.h"
     18 #include "net/base/net_log.h"
     19 #include "net/dns/host_resolver.h"
     20 #include "net/dns/single_request_host_resolver.h"
     21 #include "net/proxy/proxy_config.h"
     22 #include "net/proxy/proxy_resolver.h"
     23 #include "url/gurl.h"
     24 
     25 namespace net {
     26 
     27 class DhcpProxyScriptFetcher;
     28 class NetLogParameter;
     29 class ProxyResolver;
     30 class ProxyScriptFetcher;
     31 
     32 // ProxyScriptDecider is a helper class used by ProxyService to determine which
     33 // PAC script to use given our proxy configuration.
     34 //
     35 // This involves trying to use PAC scripts in this order:
     36 //
     37 //   (1) WPAD (DHCP) if auto-detect is on.
     38 //   (2) WPAD (DNS) if auto-detect is on.
     39 //   (3) Custom PAC script if a URL was given.
     40 //
     41 // If no PAC script was successfully selected, then it fails with either a
     42 // network error, or PAC_SCRIPT_FAILED (indicating it did not pass our
     43 // validation).
     44 //
     45 // On successful completion, the fetched PAC script data can be accessed using
     46 // script_data().
     47 //
     48 // Deleting ProxyScriptDecider while Init() is in progress, will
     49 // cancel the request.
     50 //
     51 class NET_EXPORT_PRIVATE ProxyScriptDecider {
     52  public:
     53   // |proxy_script_fetcher|, |dhcp_proxy_script_fetcher| and
     54   // |net_log| must remain valid for the lifespan of ProxyScriptDecider.
     55   ProxyScriptDecider(ProxyScriptFetcher* proxy_script_fetcher,
     56                      DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher,
     57                      NetLog* net_log);
     58 
     59   // Aborts any in-progress request.
     60   ~ProxyScriptDecider();
     61 
     62   // Evaluates the effective proxy settings for |config|, and downloads the
     63   // associated PAC script.
     64   // If |wait_delay| is positive, the initialization will pause for this
     65   // amount of time before getting started.
     66   // On successful completion, the "effective" proxy settings we ended up
     67   // deciding on will be available vial the effective_settings() accessor.
     68   // Note that this may differ from |config| since we will have stripped any
     69   // manual settings, and decided whether to use auto-detect or the custom PAC
     70   // URL. Finally, if auto-detect was used we may now have resolved that to a
     71   // specific script URL.
     72   int Start(const ProxyConfig& config,
     73             const base::TimeDelta wait_delay,
     74             bool fetch_pac_bytes,
     75             const net::CompletionCallback& callback);
     76 
     77   const ProxyConfig& effective_config() const;
     78 
     79   // TODO(eroman): Return a const-pointer.
     80   ProxyResolverScriptData* script_data() const;
     81 
     82   void set_quick_check_enabled(bool enabled) {
     83     quick_check_enabled_ = enabled;
     84   }
     85 
     86   bool quick_check_enabled() const { return quick_check_enabled_; }
     87 
     88  private:
     89   // Represents the sources from which we can get PAC files; two types of
     90   // auto-detect or a custom URL.
     91   struct PacSource {
     92     enum Type {
     93       WPAD_DHCP,
     94       WPAD_DNS,
     95       CUSTOM
     96     };
     97 
     98     PacSource(Type type, const GURL& url)
     99         : type(type), url(url) {}
    100 
    101     // Returns a Value representing the PacSource.  |effective_pac_url| must
    102     // be non-NULL and point to the URL derived from information contained in
    103     // |this|, if Type is not WPAD_DHCP.
    104     base::Value* NetLogCallback(const GURL* effective_pac_url,
    105                                 NetLog::LogLevel log_level) const;
    106 
    107     Type type;
    108     GURL url;  // Empty unless |type == PAC_SOURCE_CUSTOM|.
    109   };
    110 
    111   typedef std::vector<PacSource> PacSourceList;
    112 
    113   enum State {
    114     STATE_NONE,
    115     STATE_WAIT,
    116     STATE_WAIT_COMPLETE,
    117     STATE_QUICK_CHECK,
    118     STATE_QUICK_CHECK_COMPLETE,
    119     STATE_FETCH_PAC_SCRIPT,
    120     STATE_FETCH_PAC_SCRIPT_COMPLETE,
    121     STATE_VERIFY_PAC_SCRIPT,
    122     STATE_VERIFY_PAC_SCRIPT_COMPLETE,
    123   };
    124 
    125   // Returns ordered list of PAC urls to try for |config|.
    126   PacSourceList BuildPacSourcesFallbackList(const ProxyConfig& config) const;
    127 
    128   void OnIOCompletion(int result);
    129   int DoLoop(int result);
    130   void DoCallback(int result);
    131 
    132   int DoWait();
    133   int DoWaitComplete(int result);
    134 
    135   int DoQuickCheck();
    136   int DoQuickCheckComplete(int result);
    137 
    138   int DoFetchPacScript();
    139   int DoFetchPacScriptComplete(int result);
    140 
    141   int DoVerifyPacScript();
    142   int DoVerifyPacScriptComplete(int result);
    143 
    144   // Tries restarting using the next fallback PAC URL:
    145   // |pac_sources_[++current_pac_source_index]|.
    146   // Returns OK and rewinds the state machine when there
    147   // is something to try, otherwise returns |error|.
    148   int TryToFallbackPacSource(int error);
    149 
    150   // Gets the initial state (we skip fetching when the
    151   // ProxyResolver doesn't |expect_pac_bytes()|.
    152   State GetStartState() const;
    153 
    154   void DetermineURL(const PacSource& pac_source, GURL* effective_pac_url);
    155 
    156   // Returns the current PAC URL we are fetching/testing.
    157   const PacSource& current_pac_source() const;
    158 
    159   void OnWaitTimerFired();
    160   void DidComplete();
    161   void Cancel();
    162 
    163   ProxyResolver* resolver_;
    164   ProxyScriptFetcher* proxy_script_fetcher_;
    165   DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher_;
    166 
    167   net::CompletionCallback callback_;
    168 
    169   size_t current_pac_source_index_;
    170 
    171   // Filled when the PAC script fetch completes.
    172   base::string16 pac_script_;
    173 
    174   // Flag indicating whether the caller requested a mandatory pac script
    175   // (i.e. fallback to direct connections are prohibited).
    176   bool pac_mandatory_;
    177 
    178   // Whether we have an existing custom PAC URL.
    179   bool have_custom_pac_url_;
    180 
    181   PacSourceList pac_sources_;
    182   State next_state_;
    183 
    184   BoundNetLog net_log_;
    185 
    186   bool fetch_pac_bytes_;
    187 
    188   base::TimeDelta wait_delay_;
    189   base::OneShotTimer<ProxyScriptDecider> wait_timer_;
    190 
    191   // Whether to do DNS quick check
    192   bool quick_check_enabled_;
    193 
    194   // Results.
    195   ProxyConfig effective_config_;
    196   scoped_refptr<ProxyResolverScriptData> script_data_;
    197 
    198   AddressList wpad_addresses_;
    199   base::OneShotTimer<ProxyScriptDecider> quick_check_timer_;
    200   scoped_ptr<SingleRequestHostResolver> host_resolver_;
    201   base::Time quick_check_start_time_;
    202 
    203   DISALLOW_COPY_AND_ASSIGN(ProxyScriptDecider);
    204 };
    205 
    206 }  // namespace net
    207 
    208 #endif  // NET_PROXY_PROXY_SCRIPT_DECIDER_H_
    209