• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
InitProxyResolver(ProxyResolver * resolver,ProxyScriptFetcher * proxy_script_fetcher)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 
~InitProxyResolver()30 InitProxyResolver::~InitProxyResolver() {
31   if (next_state_ != STATE_NONE)
32     Cancel();
33 }
34 
Init(const ProxyConfig & config,CompletionCallback * callback,LoadLog * load_log)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.
BuildPacUrlsFallbackList(const ProxyConfig & config) const64 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 
OnIOCompletion(int result)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 
DoLoop(int result)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 
DoCallback(int result)116 void InitProxyResolver::DoCallback(int result) {
117   DCHECK_NE(ERR_IO_PENDING, result);
118   DCHECK(user_callback_);
119   user_callback_->Run(result);
120 }
121 
DoFetchPacScript()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 
DoFetchPacScriptComplete(int result)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 
DoSetPacScript()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 
DoSetPacScriptComplete(int result)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 
TryToFallbackPacUrl(int error)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 
GetStartState() const210 InitProxyResolver::State InitProxyResolver::GetStartState() const {
211   return resolver_->expects_pac_bytes() ?
212       STATE_FETCH_PAC_SCRIPT : STATE_SET_PAC_SCRIPT;
213 }
214 
current_pac_url() const215 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 
DidCompleteInit()220 void InitProxyResolver::DidCompleteInit() {
221   LoadLog::EndEvent(load_log_, LoadLog::TYPE_INIT_PROXY_RESOLVER);
222 }
223 
Cancel()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