| 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" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/metrics/histogram.h" |
| 12 #include "base/strings/string_util.h" | 13 #include "base/strings/string_util.h" |
| 13 #include "base/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
| 14 #include "base/values.h" | 15 #include "base/values.h" |
| 15 #include "net/base/net_errors.h" | 16 #include "net/base/net_errors.h" |
| 16 #include "net/proxy/dhcp_proxy_script_fetcher.h" | 17 #include "net/proxy/dhcp_proxy_script_fetcher.h" |
| 17 #include "net/proxy/dhcp_proxy_script_fetcher_factory.h" | 18 #include "net/proxy/dhcp_proxy_script_fetcher_factory.h" |
| 18 #include "net/proxy/proxy_script_fetcher.h" | 19 #include "net/proxy/proxy_script_fetcher.h" |
| 20 #include "net/url_request/url_request_context.h" |
| 19 | 21 |
| 20 namespace net { | 22 namespace net { |
| 21 | 23 |
| 22 namespace { | 24 namespace { |
| 23 | 25 |
| 24 bool LooksLikePacScript(const base::string16& script) { | 26 bool LooksLikePacScript(const base::string16& script) { |
| 25 // 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, |
| 26 // 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, |
| 27 // 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 |
| 28 // 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. |
| 29 // | 31 // |
| 30 // 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. |
| 31 return script.find(ASCIIToUTF16("FindProxyForURL")) != base::string16::npos; | 33 return script.find(ASCIIToUTF16("FindProxyForURL")) != base::string16::npos; |
| 32 } | 34 } |
| 33 | 35 |
| 34 } | 36 } |
| 35 | 37 |
| 36 // 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 |
| 37 // auto-discovery. | 39 // auto-discovery. |
| 38 // | 40 // |
| 39 // 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 |
| 40 // 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. |
| 41 // | 43 // |
| 42 // 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 |
| 43 // 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 |
| 44 // compatibility hasn't been an issue. | 46 // compatibility hasn't been an issue. |
| 45 // | 47 // |
| 46 // For more details, also check out this comment: | 48 // For more details, also check out this comment: |
| 47 // http://code.google.com/p/chromium/issues/detail?id=18575#c20 | 49 // http://code.google.com/p/chromium/issues/detail?id=18575#c20 |
| 48 static const char kWpadUrl[] = "http://wpad/wpad.dat"; | 50 namespace { |
| 51 const char kWpadUrl[] = "http://wpad/wpad.dat"; |
| 52 const int kQuickCheckDelayMs = 1000; |
| 53 }; |
| 49 | 54 |
| 50 base::Value* ProxyScriptDecider::PacSource::NetLogCallback( | 55 base::Value* ProxyScriptDecider::PacSource::NetLogCallback( |
| 51 const GURL* effective_pac_url, | 56 const GURL* effective_pac_url, |
| 52 NetLog::LogLevel /* log_level */) const { | 57 NetLog::LogLevel /* log_level */) const { |
| 53 base::DictionaryValue* dict = new base::DictionaryValue(); | 58 base::DictionaryValue* dict = new base::DictionaryValue(); |
| 54 std::string source; | 59 std::string source; |
| 55 switch (type) { | 60 switch (type) { |
| 56 case PacSource::WPAD_DHCP: | 61 case PacSource::WPAD_DHCP: |
| 57 source = "WPAD DHCP"; | 62 source = "WPAD DHCP"; |
| 58 break; | 63 break; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 75 NetLog* net_log) | 80 NetLog* net_log) |
| 76 : resolver_(NULL), | 81 : resolver_(NULL), |
| 77 proxy_script_fetcher_(proxy_script_fetcher), | 82 proxy_script_fetcher_(proxy_script_fetcher), |
| 78 dhcp_proxy_script_fetcher_(dhcp_proxy_script_fetcher), | 83 dhcp_proxy_script_fetcher_(dhcp_proxy_script_fetcher), |
| 79 current_pac_source_index_(0u), | 84 current_pac_source_index_(0u), |
| 80 pac_mandatory_(false), | 85 pac_mandatory_(false), |
| 81 next_state_(STATE_NONE), | 86 next_state_(STATE_NONE), |
| 82 net_log_(BoundNetLog::Make( | 87 net_log_(BoundNetLog::Make( |
| 83 net_log, NetLog::SOURCE_PROXY_SCRIPT_DECIDER)), | 88 net_log, NetLog::SOURCE_PROXY_SCRIPT_DECIDER)), |
| 84 fetch_pac_bytes_(false) { | 89 fetch_pac_bytes_(false) { |
| 90 if (proxy_script_fetcher && |
| 91 proxy_script_fetcher->GetRequestContext() && |
| 92 proxy_script_fetcher->GetRequestContext()->host_resolver()) { |
| 93 host_resolver_.reset(new SingleRequestHostResolver( |
| 94 proxy_script_fetcher->GetRequestContext()->host_resolver())); |
| 95 } |
| 85 } | 96 } |
| 86 | 97 |
| 87 ProxyScriptDecider::~ProxyScriptDecider() { | 98 ProxyScriptDecider::~ProxyScriptDecider() { |
| 88 if (next_state_ != STATE_NONE) | 99 if (next_state_ != STATE_NONE) |
| 89 Cancel(); | 100 Cancel(); |
| 90 } | 101 } |
| 91 | 102 |
| 92 int ProxyScriptDecider::Start( | 103 int ProxyScriptDecider::Start( |
| 93 const ProxyConfig& config, const base::TimeDelta wait_delay, | 104 const ProxyConfig& config, const base::TimeDelta wait_delay, |
| 94 bool fetch_pac_bytes, const CompletionCallback& callback) { | 105 bool fetch_pac_bytes, const CompletionCallback& callback) { |
| 95 DCHECK_EQ(STATE_NONE, next_state_); | 106 DCHECK_EQ(STATE_NONE, next_state_); |
| 96 DCHECK(!callback.is_null()); | 107 DCHECK(!callback.is_null()); |
| 97 DCHECK(config.HasAutomaticSettings()); | 108 DCHECK(config.HasAutomaticSettings()); |
| 98 | 109 |
| 99 net_log_.BeginEvent(NetLog::TYPE_PROXY_SCRIPT_DECIDER); | 110 net_log_.BeginEvent(NetLog::TYPE_PROXY_SCRIPT_DECIDER); |
| 100 | 111 |
| 101 fetch_pac_bytes_ = fetch_pac_bytes; | 112 fetch_pac_bytes_ = fetch_pac_bytes; |
| 102 | 113 |
| 103 // Save the |wait_delay| as a non-negative value. | 114 // Save the |wait_delay| as a non-negative value. |
| 104 wait_delay_ = wait_delay; | 115 wait_delay_ = wait_delay; |
| 105 if (wait_delay_ < base::TimeDelta()) | 116 if (wait_delay_ < base::TimeDelta()) |
| 106 wait_delay_ = base::TimeDelta(); | 117 wait_delay_ = base::TimeDelta(); |
| 107 | 118 |
| 108 pac_mandatory_ = config.pac_mandatory(); | 119 pac_mandatory_ = config.pac_mandatory(); |
| 120 have_custom_pac_url_ = config.has_pac_url(); |
| 109 | 121 |
| 110 pac_sources_ = BuildPacSourcesFallbackList(config); | 122 pac_sources_ = BuildPacSourcesFallbackList(config); |
| 111 DCHECK(!pac_sources_.empty()); | 123 DCHECK(!pac_sources_.empty()); |
| 112 | 124 |
| 113 next_state_ = STATE_WAIT; | 125 next_state_ = STATE_WAIT; |
| 114 | 126 |
| 115 int rv = DoLoop(OK); | 127 int rv = DoLoop(OK); |
| 116 if (rv == ERR_IO_PENDING) | 128 if (rv == ERR_IO_PENDING) |
| 117 callback_ = callback; | 129 callback_ = callback; |
| 118 else | 130 else |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 State state = next_state_; | 177 State state = next_state_; |
| 166 next_state_ = STATE_NONE; | 178 next_state_ = STATE_NONE; |
| 167 switch (state) { | 179 switch (state) { |
| 168 case STATE_WAIT: | 180 case STATE_WAIT: |
| 169 DCHECK_EQ(OK, rv); | 181 DCHECK_EQ(OK, rv); |
| 170 rv = DoWait(); | 182 rv = DoWait(); |
| 171 break; | 183 break; |
| 172 case STATE_WAIT_COMPLETE: | 184 case STATE_WAIT_COMPLETE: |
| 173 rv = DoWaitComplete(rv); | 185 rv = DoWaitComplete(rv); |
| 174 break; | 186 break; |
| 187 case STATE_QUICK_CHECK: |
| 188 DCHECK_EQ(OK, rv); |
| 189 rv = DoQuickCheck(); |
| 190 break; |
| 191 case STATE_QUICK_CHECK_COMPLETE: |
| 192 rv = DoQuickCheckComplete(rv); |
| 193 break; |
| 175 case STATE_FETCH_PAC_SCRIPT: | 194 case STATE_FETCH_PAC_SCRIPT: |
| 176 DCHECK_EQ(OK, rv); | 195 DCHECK_EQ(OK, rv); |
| 177 rv = DoFetchPacScript(); | 196 rv = DoFetchPacScript(); |
| 178 break; | 197 break; |
| 179 case STATE_FETCH_PAC_SCRIPT_COMPLETE: | 198 case STATE_FETCH_PAC_SCRIPT_COMPLETE: |
| 180 rv = DoFetchPacScriptComplete(rv); | 199 rv = DoFetchPacScriptComplete(rv); |
| 181 break; | 200 break; |
| 182 case STATE_VERIFY_PAC_SCRIPT: | 201 case STATE_VERIFY_PAC_SCRIPT: |
| 183 DCHECK_EQ(OK, rv); | 202 DCHECK_EQ(OK, rv); |
| 184 rv = DoVerifyPacScript(); | 203 rv = DoVerifyPacScript(); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 214 net_log_.BeginEvent(NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT); | 233 net_log_.BeginEvent(NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT); |
| 215 return ERR_IO_PENDING; | 234 return ERR_IO_PENDING; |
| 216 } | 235 } |
| 217 | 236 |
| 218 int ProxyScriptDecider::DoWaitComplete(int result) { | 237 int ProxyScriptDecider::DoWaitComplete(int result) { |
| 219 DCHECK_EQ(OK, result); | 238 DCHECK_EQ(OK, result); |
| 220 if (wait_delay_.ToInternalValue() != 0) { | 239 if (wait_delay_.ToInternalValue() != 0) { |
| 221 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT, | 240 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT, |
| 222 result); | 241 result); |
| 223 } | 242 } |
| 224 next_state_ = GetStartState(); | 243 next_state_ = STATE_QUICK_CHECK; |
| 225 return OK; | 244 return OK; |
| 226 } | 245 } |
| 227 | 246 |
| 247 int ProxyScriptDecider::DoQuickCheck() { |
| 248 if (host_resolver_.get() == NULL) { |
| 249 // If we have no resolver, skip QuickCheck altogether. |
| 250 next_state_ = GetStartState(); |
| 251 return OK; |
| 252 } |
| 253 |
| 254 if (have_custom_pac_url_) { |
| 255 // If there's a custom URL, skip QuickCheck. |
| 256 next_state_ = GetStartState(); |
| 257 return OK; |
| 258 } |
| 259 |
| 260 quick_check_start_time_ = base::Time::Now(); |
| 261 HostResolver::RequestInfo reqinfo(HostPortPair("wpad", 80)); |
| 262 reqinfo.set_host_resolver_flags(HOST_RESOLVER_SYSTEM_ONLY); |
| 263 CompletionCallback callback = base::Bind( |
| 264 &ProxyScriptDecider::OnIOCompletion, |
| 265 base::Unretained(this)); |
| 266 |
| 267 |
| 268 // We use HIGHEST here because proxy decision blocks doing any other requests. |
| 269 int rv = host_resolver_->Resolve(reqinfo, HIGHEST, &wpad_addresses_, |
| 270 callback, net_log_); |
| 271 |
| 272 // We can't get an error response - the name is known to be valid, and we |
| 273 // don't cache negative dns responses. |
| 274 DCHECK(rv == OK || rv == ERR_IO_PENDING); |
| 275 |
| 276 if (rv == OK) { |
| 277 next_state_ = GetStartState(); |
| 278 } else { |
| 279 quick_check_timer_.Start(FROM_HERE, |
| 280 base::TimeDelta::FromMilliseconds( |
| 281 kQuickCheckDelayMs), |
| 282 base::Bind(callback, ERR_NAME_NOT_RESOLVED)); |
| 283 next_state_ = STATE_QUICK_CHECK_COMPLETE; |
| 284 } |
| 285 return rv; |
| 286 } |
| 287 |
| 288 int ProxyScriptDecider::DoQuickCheckComplete(int result) { |
| 289 base::TimeDelta delta = base::Time::Now() - quick_check_start_time_; |
| 290 if (result == OK) |
| 291 UMA_HISTOGRAM_TIMES("Net.WpadQuickCheckSuccess", delta); |
| 292 else |
| 293 UMA_HISTOGRAM_TIMES("Net.WpadQuickCheckFailure", delta); |
| 294 host_resolver_->Cancel(); |
| 295 quick_check_timer_.Stop(); |
| 296 if (result == OK) |
| 297 next_state_ = GetStartState(); |
| 298 return result; |
| 299 } |
| 300 |
| 228 int ProxyScriptDecider::DoFetchPacScript() { | 301 int ProxyScriptDecider::DoFetchPacScript() { |
| 229 DCHECK(fetch_pac_bytes_); | 302 DCHECK(fetch_pac_bytes_); |
| 230 | 303 |
| 231 next_state_ = STATE_FETCH_PAC_SCRIPT_COMPLETE; | 304 next_state_ = STATE_FETCH_PAC_SCRIPT_COMPLETE; |
| 232 | 305 |
| 233 const PacSource& pac_source = current_pac_source(); | 306 const PacSource& pac_source = current_pac_source(); |
| 234 | 307 |
| 235 GURL effective_pac_url; | 308 GURL effective_pac_url; |
| 236 DetermineURL(pac_source, &effective_pac_url); | 309 DetermineURL(pac_source, &effective_pac_url); |
| 237 | 310 |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 405 } | 478 } |
| 406 | 479 |
| 407 // This is safe to call in any state. | 480 // This is safe to call in any state. |
| 408 if (dhcp_proxy_script_fetcher_) | 481 if (dhcp_proxy_script_fetcher_) |
| 409 dhcp_proxy_script_fetcher_->Cancel(); | 482 dhcp_proxy_script_fetcher_->Cancel(); |
| 410 | 483 |
| 411 DidComplete(); | 484 DidComplete(); |
| 412 } | 485 } |
| 413 | 486 |
| 414 } // namespace net | 487 } // namespace net |
| OLD | NEW |