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
25namespace net {
26
27class DhcpProxyScriptFetcher;
28class NetLogParameter;
29class ProxyResolver;
30class 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//
51class 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