OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/proxy/proxy_script_decider.h" | 5 #include "net/proxy/proxy_script_decider.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
9 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
10 #include "base/format_macros.h" | 10 #include "base/format_macros.h" |
(...skipping 13 matching lines...) Expand all Loading... |
24 namespace { | 24 namespace { |
25 | 25 |
26 bool LooksLikePacScript(const base::string16& script) { | 26 bool LooksLikePacScript(const base::string16& script) { |
27 // Note: this is only an approximation! It may not always work correctly, | 27 // Note: this is only an approximation! It may not always work correctly, |
28 // however it is very likely that legitimate scripts have this exact string, | 28 // however it is very likely that legitimate scripts have this exact string, |
29 // since they must minimally define a function of this name. Conversely, a | 29 // since they must minimally define a function of this name. Conversely, a |
30 // file not containing the string is not likely to be a PAC script. | 30 // file not containing the string is not likely to be a PAC script. |
31 // | 31 // |
32 // An exact test would have to load the script in a javascript evaluator. | 32 // An exact test would have to load the script in a javascript evaluator. |
33 return script.find(base::ASCIIToUTF16("FindProxyForURL")) != | 33 return script.find(base::ASCIIToUTF16("FindProxyForURL")) != |
34 base::string16::npos; | 34 base::string16::npos; |
35 } | 35 } |
36 | |
37 } | 36 } |
38 | 37 |
39 // This is the hard-coded location used by the DNS portion of web proxy | 38 // This is the hard-coded location used by the DNS portion of web proxy |
40 // auto-discovery. | 39 // auto-discovery. |
41 // | 40 // |
42 // Note that we not use DNS devolution to find the WPAD host, since that could | 41 // Note that we not use DNS devolution to find the WPAD host, since that could |
43 // be dangerous should our top level domain registry become out of date. | 42 // be dangerous should our top level domain registry become out of date. |
44 // | 43 // |
45 // Instead we directly resolve "wpad", and let the operating system apply the | 44 // Instead we directly resolve "wpad", and let the operating system apply the |
46 // DNS suffix search paths. This is the same approach taken by Firefox, and | 45 // DNS suffix search paths. This is the same approach taken by Firefox, and |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 ProxyScriptDecider::ProxyScriptDecider( | 77 ProxyScriptDecider::ProxyScriptDecider( |
79 ProxyScriptFetcher* proxy_script_fetcher, | 78 ProxyScriptFetcher* proxy_script_fetcher, |
80 DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher, | 79 DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher, |
81 NetLog* net_log) | 80 NetLog* net_log) |
82 : resolver_(NULL), | 81 : resolver_(NULL), |
83 proxy_script_fetcher_(proxy_script_fetcher), | 82 proxy_script_fetcher_(proxy_script_fetcher), |
84 dhcp_proxy_script_fetcher_(dhcp_proxy_script_fetcher), | 83 dhcp_proxy_script_fetcher_(dhcp_proxy_script_fetcher), |
85 current_pac_source_index_(0u), | 84 current_pac_source_index_(0u), |
86 pac_mandatory_(false), | 85 pac_mandatory_(false), |
87 next_state_(STATE_NONE), | 86 next_state_(STATE_NONE), |
88 net_log_(BoundNetLog::Make( | 87 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_PROXY_SCRIPT_DECIDER)), |
89 net_log, NetLog::SOURCE_PROXY_SCRIPT_DECIDER)), | |
90 fetch_pac_bytes_(false), | 88 fetch_pac_bytes_(false), |
91 quick_check_enabled_(true) { | 89 quick_check_enabled_(true) { |
92 if (proxy_script_fetcher && | 90 if (proxy_script_fetcher && proxy_script_fetcher->GetRequestContext() && |
93 proxy_script_fetcher->GetRequestContext() && | |
94 proxy_script_fetcher->GetRequestContext()->host_resolver()) { | 91 proxy_script_fetcher->GetRequestContext()->host_resolver()) { |
95 host_resolver_.reset(new SingleRequestHostResolver( | 92 host_resolver_.reset(new SingleRequestHostResolver( |
96 proxy_script_fetcher->GetRequestContext()->host_resolver())); | 93 proxy_script_fetcher->GetRequestContext()->host_resolver())); |
97 } | 94 } |
98 } | 95 } |
99 | 96 |
100 ProxyScriptDecider::~ProxyScriptDecider() { | 97 ProxyScriptDecider::~ProxyScriptDecider() { |
101 if (next_state_ != STATE_NONE) | 98 if (next_state_ != STATE_NONE) |
102 Cancel(); | 99 Cancel(); |
103 } | 100 } |
104 | 101 |
105 int ProxyScriptDecider::Start( | 102 int ProxyScriptDecider::Start(const ProxyConfig& config, |
106 const ProxyConfig& config, const base::TimeDelta wait_delay, | 103 const base::TimeDelta wait_delay, |
107 bool fetch_pac_bytes, const CompletionCallback& callback) { | 104 bool fetch_pac_bytes, |
| 105 const CompletionCallback& callback) { |
108 DCHECK_EQ(STATE_NONE, next_state_); | 106 DCHECK_EQ(STATE_NONE, next_state_); |
109 DCHECK(!callback.is_null()); | 107 DCHECK(!callback.is_null()); |
110 DCHECK(config.HasAutomaticSettings()); | 108 DCHECK(config.HasAutomaticSettings()); |
111 | 109 |
112 net_log_.BeginEvent(NetLog::TYPE_PROXY_SCRIPT_DECIDER); | 110 net_log_.BeginEvent(NetLog::TYPE_PROXY_SCRIPT_DECIDER); |
113 | 111 |
114 fetch_pac_bytes_ = fetch_pac_bytes; | 112 fetch_pac_bytes_ = fetch_pac_bytes; |
115 | 113 |
116 // Save the |wait_delay| as a non-negative value. | 114 // Save the |wait_delay| as a non-negative value. |
117 wait_delay_ = wait_delay; | 115 wait_delay_ = wait_delay; |
(...skipping 25 matching lines...) Expand all Loading... |
143 // TODO(eroman): Return a const-pointer. | 141 // TODO(eroman): Return a const-pointer. |
144 ProxyResolverScriptData* ProxyScriptDecider::script_data() const { | 142 ProxyResolverScriptData* ProxyScriptDecider::script_data() const { |
145 DCHECK_EQ(STATE_NONE, next_state_); | 143 DCHECK_EQ(STATE_NONE, next_state_); |
146 return script_data_.get(); | 144 return script_data_.get(); |
147 } | 145 } |
148 | 146 |
149 // Initialize the fallback rules. | 147 // Initialize the fallback rules. |
150 // (1) WPAD (DHCP). | 148 // (1) WPAD (DHCP). |
151 // (2) WPAD (DNS). | 149 // (2) WPAD (DNS). |
152 // (3) Custom PAC URL. | 150 // (3) Custom PAC URL. |
153 ProxyScriptDecider::PacSourceList ProxyScriptDecider:: | 151 ProxyScriptDecider::PacSourceList |
154 BuildPacSourcesFallbackList( | 152 ProxyScriptDecider::BuildPacSourcesFallbackList( |
155 const ProxyConfig& config) const { | 153 const ProxyConfig& config) const { |
156 PacSourceList pac_sources; | 154 PacSourceList pac_sources; |
157 if (config.auto_detect()) { | 155 if (config.auto_detect()) { |
158 pac_sources.push_back(PacSource(PacSource::WPAD_DHCP, GURL(kWpadUrl))); | 156 pac_sources.push_back(PacSource(PacSource::WPAD_DHCP, GURL(kWpadUrl))); |
159 pac_sources.push_back(PacSource(PacSource::WPAD_DNS, GURL(kWpadUrl))); | 157 pac_sources.push_back(PacSource(PacSource::WPAD_DNS, GURL(kWpadUrl))); |
160 } | 158 } |
161 if (config.has_pac_url()) | 159 if (config.has_pac_url()) |
162 pac_sources.push_back(PacSource(PacSource::CUSTOM, config.pac_url())); | 160 pac_sources.push_back(PacSource(PacSource::CUSTOM, config.pac_url())); |
163 return pac_sources; | 161 return pac_sources; |
164 } | 162 } |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 } | 221 } |
224 | 222 |
225 int ProxyScriptDecider::DoWait() { | 223 int ProxyScriptDecider::DoWait() { |
226 next_state_ = STATE_WAIT_COMPLETE; | 224 next_state_ = STATE_WAIT_COMPLETE; |
227 | 225 |
228 // If no waiting is required, continue on to the next state. | 226 // If no waiting is required, continue on to the next state. |
229 if (wait_delay_.ToInternalValue() == 0) | 227 if (wait_delay_.ToInternalValue() == 0) |
230 return OK; | 228 return OK; |
231 | 229 |
232 // Otherwise wait the specified amount of time. | 230 // Otherwise wait the specified amount of time. |
233 wait_timer_.Start(FROM_HERE, wait_delay_, this, | 231 wait_timer_.Start( |
234 &ProxyScriptDecider::OnWaitTimerFired); | 232 FROM_HERE, wait_delay_, this, &ProxyScriptDecider::OnWaitTimerFired); |
235 net_log_.BeginEvent(NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT); | 233 net_log_.BeginEvent(NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT); |
236 return ERR_IO_PENDING; | 234 return ERR_IO_PENDING; |
237 } | 235 } |
238 | 236 |
239 int ProxyScriptDecider::DoWaitComplete(int result) { | 237 int ProxyScriptDecider::DoWaitComplete(int result) { |
240 DCHECK_EQ(OK, result); | 238 DCHECK_EQ(OK, result); |
241 if (wait_delay_.ToInternalValue() != 0) { | 239 if (wait_delay_.ToInternalValue() != 0) { |
242 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT, | 240 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT, |
243 result); | 241 result); |
244 } | 242 } |
245 if (quick_check_enabled_ && current_pac_source().type == PacSource::WPAD_DNS) | 243 if (quick_check_enabled_ && current_pac_source().type == PacSource::WPAD_DNS) |
246 next_state_ = STATE_QUICK_CHECK; | 244 next_state_ = STATE_QUICK_CHECK; |
247 else | 245 else |
248 next_state_ = GetStartState(); | 246 next_state_ = GetStartState(); |
249 return OK; | 247 return OK; |
250 } | 248 } |
251 | 249 |
252 int ProxyScriptDecider::DoQuickCheck() { | 250 int ProxyScriptDecider::DoQuickCheck() { |
253 DCHECK(quick_check_enabled_); | 251 DCHECK(quick_check_enabled_); |
254 if (host_resolver_.get() == NULL) { | 252 if (host_resolver_.get() == NULL) { |
255 // If we have no resolver, skip QuickCheck altogether. | 253 // If we have no resolver, skip QuickCheck altogether. |
256 next_state_ = GetStartState(); | 254 next_state_ = GetStartState(); |
257 return OK; | 255 return OK; |
258 } | 256 } |
259 | 257 |
260 quick_check_start_time_ = base::Time::Now(); | 258 quick_check_start_time_ = base::Time::Now(); |
261 std::string host = current_pac_source().url.host(); | 259 std::string host = current_pac_source().url.host(); |
262 HostResolver::RequestInfo reqinfo(HostPortPair(host, 80)); | 260 HostResolver::RequestInfo reqinfo(HostPortPair(host, 80)); |
263 reqinfo.set_host_resolver_flags(HOST_RESOLVER_SYSTEM_ONLY); | 261 reqinfo.set_host_resolver_flags(HOST_RESOLVER_SYSTEM_ONLY); |
264 CompletionCallback callback = base::Bind( | 262 CompletionCallback callback = |
265 &ProxyScriptDecider::OnIOCompletion, | 263 base::Bind(&ProxyScriptDecider::OnIOCompletion, base::Unretained(this)); |
266 base::Unretained(this)); | |
267 | 264 |
268 next_state_ = STATE_QUICK_CHECK_COMPLETE; | 265 next_state_ = STATE_QUICK_CHECK_COMPLETE; |
269 quick_check_timer_.Start(FROM_HERE, | 266 quick_check_timer_.Start( |
270 base::TimeDelta::FromMilliseconds( | 267 FROM_HERE, |
271 kQuickCheckDelayMs), | 268 base::TimeDelta::FromMilliseconds(kQuickCheckDelayMs), |
272 base::Bind(callback, ERR_NAME_NOT_RESOLVED)); | 269 base::Bind(callback, ERR_NAME_NOT_RESOLVED)); |
273 | 270 |
274 // We use HIGHEST here because proxy decision blocks doing any other requests. | 271 // We use HIGHEST here because proxy decision blocks doing any other requests. |
275 return host_resolver_->Resolve(reqinfo, HIGHEST, &wpad_addresses_, | 272 return host_resolver_->Resolve( |
276 callback, net_log_); | 273 reqinfo, HIGHEST, &wpad_addresses_, callback, net_log_); |
277 } | 274 } |
278 | 275 |
279 int ProxyScriptDecider::DoQuickCheckComplete(int result) { | 276 int ProxyScriptDecider::DoQuickCheckComplete(int result) { |
280 DCHECK(quick_check_enabled_); | 277 DCHECK(quick_check_enabled_); |
281 base::TimeDelta delta = base::Time::Now() - quick_check_start_time_; | 278 base::TimeDelta delta = base::Time::Now() - quick_check_start_time_; |
282 if (result == OK) | 279 if (result == OK) |
283 UMA_HISTOGRAM_TIMES("Net.WpadQuickCheckSuccess", delta); | 280 UMA_HISTOGRAM_TIMES("Net.WpadQuickCheckSuccess", delta); |
284 else | 281 else |
285 UMA_HISTOGRAM_TIMES("Net.WpadQuickCheckFailure", delta); | 282 UMA_HISTOGRAM_TIMES("Net.WpadQuickCheckFailure", delta); |
286 host_resolver_->Cancel(); | 283 host_resolver_->Cancel(); |
(...skipping 19 matching lines...) Expand all Loading... |
306 base::Unretained(&pac_source), | 303 base::Unretained(&pac_source), |
307 &effective_pac_url)); | 304 &effective_pac_url)); |
308 | 305 |
309 if (pac_source.type == PacSource::WPAD_DHCP) { | 306 if (pac_source.type == PacSource::WPAD_DHCP) { |
310 if (!dhcp_proxy_script_fetcher_) { | 307 if (!dhcp_proxy_script_fetcher_) { |
311 net_log_.AddEvent(NetLog::TYPE_PROXY_SCRIPT_DECIDER_HAS_NO_FETCHER); | 308 net_log_.AddEvent(NetLog::TYPE_PROXY_SCRIPT_DECIDER_HAS_NO_FETCHER); |
312 return ERR_UNEXPECTED; | 309 return ERR_UNEXPECTED; |
313 } | 310 } |
314 | 311 |
315 return dhcp_proxy_script_fetcher_->Fetch( | 312 return dhcp_proxy_script_fetcher_->Fetch( |
316 &pac_script_, base::Bind(&ProxyScriptDecider::OnIOCompletion, | 313 &pac_script_, |
317 base::Unretained(this))); | 314 base::Bind(&ProxyScriptDecider::OnIOCompletion, |
| 315 base::Unretained(this))); |
318 } | 316 } |
319 | 317 |
320 if (!proxy_script_fetcher_) { | 318 if (!proxy_script_fetcher_) { |
321 net_log_.AddEvent(NetLog::TYPE_PROXY_SCRIPT_DECIDER_HAS_NO_FETCHER); | 319 net_log_.AddEvent(NetLog::TYPE_PROXY_SCRIPT_DECIDER_HAS_NO_FETCHER); |
322 return ERR_UNEXPECTED; | 320 return ERR_UNEXPECTED; |
323 } | 321 } |
324 | 322 |
325 return proxy_script_fetcher_->Fetch( | 323 return proxy_script_fetcher_->Fetch( |
326 effective_pac_url, &pac_script_, | 324 effective_pac_url, |
| 325 &pac_script_, |
327 base::Bind(&ProxyScriptDecider::OnIOCompletion, base::Unretained(this))); | 326 base::Bind(&ProxyScriptDecider::OnIOCompletion, base::Unretained(this))); |
328 } | 327 } |
329 | 328 |
330 int ProxyScriptDecider::DoFetchPacScriptComplete(int result) { | 329 int ProxyScriptDecider::DoFetchPacScriptComplete(int result) { |
331 DCHECK(fetch_pac_bytes_); | 330 DCHECK(fetch_pac_bytes_); |
332 | 331 |
333 net_log_.EndEventWithNetErrorCode( | 332 net_log_.EndEventWithNetErrorCode( |
334 NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT, result); | 333 NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT, result); |
335 if (result != OK) | 334 if (result != OK) |
336 return TryToFallbackPacSource(result); | 335 return TryToFallbackPacSource(result); |
(...skipping 15 matching lines...) Expand all Loading... |
352 int ProxyScriptDecider::DoVerifyPacScriptComplete(int result) { | 351 int ProxyScriptDecider::DoVerifyPacScriptComplete(int result) { |
353 if (result != OK) | 352 if (result != OK) |
354 return TryToFallbackPacSource(result); | 353 return TryToFallbackPacSource(result); |
355 | 354 |
356 const PacSource& pac_source = current_pac_source(); | 355 const PacSource& pac_source = current_pac_source(); |
357 | 356 |
358 // Extract the current script data. | 357 // Extract the current script data. |
359 if (fetch_pac_bytes_) { | 358 if (fetch_pac_bytes_) { |
360 script_data_ = ProxyResolverScriptData::FromUTF16(pac_script_); | 359 script_data_ = ProxyResolverScriptData::FromUTF16(pac_script_); |
361 } else { | 360 } else { |
362 script_data_ = pac_source.type == PacSource::CUSTOM ? | 361 script_data_ = pac_source.type == PacSource::CUSTOM |
363 ProxyResolverScriptData::FromURL(pac_source.url) : | 362 ? ProxyResolverScriptData::FromURL(pac_source.url) |
364 ProxyResolverScriptData::ForAutoDetect(); | 363 : ProxyResolverScriptData::ForAutoDetect(); |
365 } | 364 } |
366 | 365 |
367 // Let the caller know which automatic setting we ended up initializing the | 366 // Let the caller know which automatic setting we ended up initializing the |
368 // resolver for (there may have been multiple fallbacks to choose from.) | 367 // resolver for (there may have been multiple fallbacks to choose from.) |
369 if (current_pac_source().type == PacSource::CUSTOM) { | 368 if (current_pac_source().type == PacSource::CUSTOM) { |
370 effective_config_ = | 369 effective_config_ = |
371 ProxyConfig::CreateFromCustomPacURL(current_pac_source().url); | 370 ProxyConfig::CreateFromCustomPacURL(current_pac_source().url); |
372 effective_config_.set_pac_mandatory(pac_mandatory_); | 371 effective_config_.set_pac_mandatory(pac_mandatory_); |
373 } else { | 372 } else { |
374 if (fetch_pac_bytes_) { | 373 if (fetch_pac_bytes_) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
415 NetLog::TYPE_PROXY_SCRIPT_DECIDER_FALLING_BACK_TO_NEXT_PAC_SOURCE); | 414 NetLog::TYPE_PROXY_SCRIPT_DECIDER_FALLING_BACK_TO_NEXT_PAC_SOURCE); |
416 if (quick_check_enabled_ && current_pac_source().type == PacSource::WPAD_DNS) | 415 if (quick_check_enabled_ && current_pac_source().type == PacSource::WPAD_DNS) |
417 next_state_ = STATE_QUICK_CHECK; | 416 next_state_ = STATE_QUICK_CHECK; |
418 else | 417 else |
419 next_state_ = GetStartState(); | 418 next_state_ = GetStartState(); |
420 | 419 |
421 return OK; | 420 return OK; |
422 } | 421 } |
423 | 422 |
424 ProxyScriptDecider::State ProxyScriptDecider::GetStartState() const { | 423 ProxyScriptDecider::State ProxyScriptDecider::GetStartState() const { |
425 return fetch_pac_bytes_ ? STATE_FETCH_PAC_SCRIPT : STATE_VERIFY_PAC_SCRIPT; | 424 return fetch_pac_bytes_ ? STATE_FETCH_PAC_SCRIPT : STATE_VERIFY_PAC_SCRIPT; |
426 } | 425 } |
427 | 426 |
428 void ProxyScriptDecider::DetermineURL(const PacSource& pac_source, | 427 void ProxyScriptDecider::DetermineURL(const PacSource& pac_source, |
429 GURL* effective_pac_url) { | 428 GURL* effective_pac_url) { |
430 DCHECK(effective_pac_url); | 429 DCHECK(effective_pac_url); |
431 | 430 |
432 switch (pac_source.type) { | 431 switch (pac_source.type) { |
433 case PacSource::WPAD_DHCP: | 432 case PacSource::WPAD_DHCP: |
434 break; | 433 break; |
435 case PacSource::WPAD_DNS: | 434 case PacSource::WPAD_DNS: |
436 *effective_pac_url = GURL(kWpadUrl); | 435 *effective_pac_url = GURL(kWpadUrl); |
437 break; | 436 break; |
438 case PacSource::CUSTOM: | 437 case PacSource::CUSTOM: |
439 *effective_pac_url = pac_source.url; | 438 *effective_pac_url = pac_source.url; |
440 break; | 439 break; |
441 } | 440 } |
442 } | 441 } |
443 | 442 |
444 const ProxyScriptDecider::PacSource& | 443 const ProxyScriptDecider::PacSource& ProxyScriptDecider::current_pac_source() |
445 ProxyScriptDecider::current_pac_source() const { | 444 const { |
446 DCHECK_LT(current_pac_source_index_, pac_sources_.size()); | 445 DCHECK_LT(current_pac_source_index_, pac_sources_.size()); |
447 return pac_sources_[current_pac_source_index_]; | 446 return pac_sources_[current_pac_source_index_]; |
448 } | 447 } |
449 | 448 |
450 void ProxyScriptDecider::OnWaitTimerFired() { | 449 void ProxyScriptDecider::OnWaitTimerFired() { |
451 OnIOCompletion(OK); | 450 OnIOCompletion(OK); |
452 } | 451 } |
453 | 452 |
454 void ProxyScriptDecider::DidComplete() { | 453 void ProxyScriptDecider::DidComplete() { |
455 net_log_.EndEvent(NetLog::TYPE_PROXY_SCRIPT_DECIDER); | 454 net_log_.EndEvent(NetLog::TYPE_PROXY_SCRIPT_DECIDER); |
(...skipping 17 matching lines...) Expand all Loading... |
473 } | 472 } |
474 | 473 |
475 // This is safe to call in any state. | 474 // This is safe to call in any state. |
476 if (dhcp_proxy_script_fetcher_) | 475 if (dhcp_proxy_script_fetcher_) |
477 dhcp_proxy_script_fetcher_->Cancel(); | 476 dhcp_proxy_script_fetcher_->Cancel(); |
478 | 477 |
479 DidComplete(); | 478 DidComplete(); |
480 } | 479 } |
481 | 480 |
482 } // namespace net | 481 } // namespace net |
OLD | NEW |