| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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_service.h" | 5 #include "net/proxy/proxy_service.h" |
| 6 | 6 |
| 7 #if defined(OS_WIN) | 7 #if defined(OS_WIN) |
| 8 #include <windows.h> | 8 #include <windows.h> |
| 9 #include <winhttp.h> | 9 #include <winhttp.h> |
| 10 #endif | 10 #endif |
| 11 | 11 |
| 12 #include <algorithm> | 12 #include <algorithm> |
| 13 | 13 |
| 14 #include "base/compiler_specific.h" |
| 14 #include "base/logging.h" | 15 #include "base/logging.h" |
| 15 #include "base/message_loop.h" | 16 #include "base/message_loop.h" |
| 16 #include "base/string_tokenizer.h" | 17 #include "base/string_tokenizer.h" |
| 17 #include "base/string_util.h" | 18 #include "base/string_util.h" |
| 18 #include "googleurl/src/gurl.h" | 19 #include "googleurl/src/gurl.h" |
| 19 #include "net/base/net_errors.h" | 20 #include "net/base/net_errors.h" |
| 20 #include "net/proxy/proxy_config_service_fixed.h" | 21 #include "net/proxy/proxy_config_service_fixed.h" |
| 21 #if defined(OS_WIN) | 22 #if defined(OS_WIN) |
| 22 #include "net/proxy/proxy_config_service_win.h" | 23 #include "net/proxy/proxy_config_service_win.h" |
| 23 #include "net/proxy/proxy_resolver_winhttp.h" | 24 #include "net/proxy/proxy_resolver_winhttp.h" |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 158 } | 159 } |
| 159 | 160 |
| 160 void ProxyInfo::UseDirect() { | 161 void ProxyInfo::UseDirect() { |
| 161 proxy_list_.Set(std::string()); | 162 proxy_list_.Set(std::string()); |
| 162 } | 163 } |
| 163 | 164 |
| 164 void ProxyInfo::UseNamedProxy(const std::string& proxy_server) { | 165 void ProxyInfo::UseNamedProxy(const std::string& proxy_server) { |
| 165 proxy_list_.Set(proxy_server); | 166 proxy_list_.Set(proxy_server); |
| 166 } | 167 } |
| 167 | 168 |
| 168 #if defined(OS_WIN) | |
| 169 void ProxyInfo::Apply(HINTERNET request_handle) { | |
| 170 WINHTTP_PROXY_INFO pi; | |
| 171 std::wstring proxy; // We need to declare this variable here because | |
| 172 // lpszProxy needs to be valid in WinHttpSetOption. | |
| 173 if (is_direct()) { | |
| 174 pi.dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY; | |
| 175 pi.lpszProxy = WINHTTP_NO_PROXY_NAME; | |
| 176 pi.lpszProxyBypass = WINHTTP_NO_PROXY_BYPASS; | |
| 177 } else { | |
| 178 proxy = ASCIIToWide(proxy_list_.Get()); | |
| 179 pi.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; | |
| 180 pi.lpszProxy = const_cast<LPWSTR>(proxy.c_str()); | |
| 181 // NOTE: Specifying a bypass list here would serve no purpose. | |
| 182 pi.lpszProxyBypass = WINHTTP_NO_PROXY_BYPASS; | |
| 183 } | |
| 184 WinHttpSetOption(request_handle, WINHTTP_OPTION_PROXY, &pi, sizeof(pi)); | |
| 185 } | |
| 186 #endif | |
| 187 | |
| 188 std::string ProxyInfo::GetAnnotatedProxyList() { | 169 std::string ProxyInfo::GetAnnotatedProxyList() { |
| 189 return is_direct() ? "DIRECT" : proxy_list_.GetAnnotatedList(); | 170 return is_direct() ? "DIRECT" : proxy_list_.GetAnnotatedList(); |
| 190 } | 171 } |
| 191 | 172 |
| 192 // ProxyService::PacRequest --------------------------------------------------- | 173 // ProxyService::PacRequest --------------------------------------------------- |
| 193 | 174 |
| 194 // We rely on the fact that the origin thread (and its message loop) will not | 175 // We rely on the fact that the origin thread (and its message loop) will not |
| 195 // be destroyed until after the PAC thread is destroyed. | 176 // be destroyed until after the PAC thread is destroyed. |
| 196 | 177 |
| 197 class ProxyService::PacRequest : | 178 class ProxyService::PacRequest : |
| 198 public base::RefCountedThreadSafe<ProxyService::PacRequest> { | 179 public base::RefCountedThreadSafe<ProxyService::PacRequest> { |
| 199 public: | 180 public: |
| 200 PacRequest(ProxyService* service, | 181 PacRequest(ProxyService* service, |
| 201 const GURL& pac_url, | 182 const GURL& pac_url, |
| 202 CompletionCallback* callback) | 183 CompletionCallback* callback) |
| 203 : service_(service), | 184 : service_(service), |
| 204 callback_(callback), | 185 callback_(callback), |
| 205 results_(NULL), | 186 results_(NULL), |
| 206 config_id_(service->config_id()), | 187 config_id_(service->config_id()), |
| 207 pac_url_(pac_url), | 188 pac_url_(pac_url), |
| 208 origin_loop_(NULL) { | 189 origin_loop_(MessageLoop::current()) { |
| 209 // We need to remember original loop if only in case of asynchronous call | 190 DCHECK(callback); |
| 210 if (callback_) | |
| 211 origin_loop_ = MessageLoop::current(); | |
| 212 } | 191 } |
| 213 | 192 |
| 214 void Query(const GURL& url, ProxyInfo* results) { | 193 void Query(const GURL& url, ProxyInfo* results) { |
| 215 results_ = results; | 194 results_ = results; |
| 216 // If we have a valid callback then execute Query asynchronously | 195 // Execute Query asynchronously |
| 217 if (callback_) { | 196 AddRef(); // balanced in QueryComplete |
| 218 AddRef(); // balanced in QueryComplete | 197 service_->pac_thread()->message_loop()->PostTask(FROM_HERE, |
| 219 service_->pac_thread()->message_loop()->PostTask(FROM_HERE, | 198 NewRunnableMethod(this, &ProxyService::PacRequest::DoQuery, |
| 220 NewRunnableMethod(this, &ProxyService::PacRequest::DoQuery, | 199 service_->resolver(), url, pac_url_)); |
| 221 service_->resolver(), url, pac_url_)); | |
| 222 } else { | |
| 223 DoQuery(service_->resolver(), url, pac_url_); | |
| 224 } | |
| 225 } | 200 } |
| 226 | 201 |
| 227 void Cancel() { | 202 void Cancel() { |
| 228 // Clear these to inform QueryComplete that it should not try to | 203 // Clear these to inform QueryComplete that it should not try to |
| 229 // access them. | 204 // access them. |
| 230 service_ = NULL; | 205 service_ = NULL; |
| 231 callback_ = NULL; | 206 callback_ = NULL; |
| 232 results_ = NULL; | 207 results_ = NULL; |
| 233 } | 208 } |
| 234 | 209 |
| 235 private: | 210 private: |
| 236 // Runs on the PAC thread if a valid callback is provided. | 211 // Runs on the PAC thread. |
| 237 void DoQuery(ProxyResolver* resolver, | 212 void DoQuery(ProxyResolver* resolver, |
| 238 const GURL& query_url, | 213 const GURL& query_url, |
| 239 const GURL& pac_url) { | 214 const GURL& pac_url) { |
| 240 int rv = resolver->GetProxyForURL(query_url, pac_url, &results_buf_); | 215 int rv = resolver->GetProxyForURL(query_url, pac_url, &results_buf_); |
| 241 if (origin_loop_) { | 216 origin_loop_->PostTask(FROM_HERE, |
| 242 origin_loop_->PostTask(FROM_HERE, | 217 NewRunnableMethod(this, &PacRequest::QueryComplete, rv)); |
| 243 NewRunnableMethod(this, &PacRequest::QueryComplete, rv)); | |
| 244 } else { | |
| 245 QueryComplete(rv); | |
| 246 } | |
| 247 } | 218 } |
| 248 | 219 |
| 249 // If a valid callback is provided, this runs on the origin thread to | 220 // Runs the completion callback on the origin thread. |
| 250 // indicate that the completion callback should be run. | |
| 251 void QueryComplete(int result_code) { | 221 void QueryComplete(int result_code) { |
| 252 if (service_) | 222 // The PacRequest may have been cancelled after it was started. If it was |
| 223 // cancelled then |callback_|, |service_|, and |results_| will be NULL. |
| 224 bool was_cancelled = callback_ == NULL; |
| 225 |
| 226 if (!was_cancelled) { |
| 253 service_->DidCompletePacRequest(config_id_, result_code); | 227 service_->DidCompletePacRequest(config_id_, result_code); |
| 254 | 228 |
| 255 if (result_code == OK && results_) { | 229 if (result_code == OK) { |
| 256 results_->Use(results_buf_); | 230 results_->Use(results_buf_); |
| 257 results_->RemoveBadProxies(service_->proxy_retry_info_); | 231 results_->RemoveBadProxies(service_->proxy_retry_info_); |
| 232 } |
| 233 callback_->Run(result_code); |
| 258 } | 234 } |
| 259 | 235 |
| 260 if (callback_) | 236 Release(); // balances the AddRef in Query. we may get deleted after |
| 261 callback_->Run(result_code); | 237 // we return. |
| 262 | |
| 263 if (origin_loop_) { | |
| 264 Release(); // balances the AddRef in Query. we may get deleted after | |
| 265 // we return. | |
| 266 } | |
| 267 } | 238 } |
| 268 | 239 |
| 269 // Must only be used on the "origin" thread. | 240 // Must only be used on the "origin" thread. |
| 270 ProxyService* service_; | 241 ProxyService* service_; |
| 271 CompletionCallback* callback_; | 242 CompletionCallback* callback_; |
| 272 ProxyInfo* results_; | 243 ProxyInfo* results_; |
| 273 ProxyConfig::ID config_id_; | 244 ProxyConfig::ID config_id_; |
| 274 | 245 |
| 275 // Usable from within DoQuery on the PAC thread. | 246 // Usable from within DoQuery on the PAC thread. |
| 276 ProxyInfo results_buf_; | 247 ProxyInfo results_buf_; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 314 // static | 285 // static |
| 315 ProxyService* ProxyService::CreateNull() { | 286 ProxyService* ProxyService::CreateNull() { |
| 316 // The ProxyResolver is set to NULL, since it should never be called | 287 // The ProxyResolver is set to NULL, since it should never be called |
| 317 // (because the configuration will never require PAC). | 288 // (because the configuration will never require PAC). |
| 318 return new ProxyService(new ProxyConfigServiceNull, NULL); | 289 return new ProxyService(new ProxyConfigServiceNull, NULL); |
| 319 } | 290 } |
| 320 | 291 |
| 321 int ProxyService::ResolveProxy(const GURL& url, ProxyInfo* result, | 292 int ProxyService::ResolveProxy(const GURL& url, ProxyInfo* result, |
| 322 CompletionCallback* callback, | 293 CompletionCallback* callback, |
| 323 PacRequest** pac_request) { | 294 PacRequest** pac_request) { |
| 295 DCHECK(callback); |
| 324 // The overhead of calling ProxyConfigService::GetProxyConfig is very low. | 296 // The overhead of calling ProxyConfigService::GetProxyConfig is very low. |
| 325 const TimeDelta kProxyConfigMaxAge = TimeDelta::FromSeconds(5); | 297 const TimeDelta kProxyConfigMaxAge = TimeDelta::FromSeconds(5); |
| 326 | 298 |
| 327 // Periodically check for a new config. | 299 // Periodically check for a new config. |
| 328 if (!config_has_been_updated_ || | 300 if (!config_has_been_updated_ || |
| 329 (TimeTicks::Now() - config_last_update_time_) > kProxyConfigMaxAge) | 301 (TimeTicks::Now() - config_last_update_time_) > kProxyConfigMaxAge) |
| 330 UpdateConfig(); | 302 UpdateConfig(); |
| 331 result->config_id_ = config_.id(); | 303 result->config_id_ = config_.id(); |
| 332 | 304 |
| 333 // Fallback to a "direct" (no proxy) connection if the current configuration | 305 // Fallback to a "direct" (no proxy) connection if the current configuration |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 374 } | 346 } |
| 375 } | 347 } |
| 376 // We failed to find a matching proxy server for the current URL | 348 // We failed to find a matching proxy server for the current URL |
| 377 // scheme. Default to direct. | 349 // scheme. Default to direct. |
| 378 result->UseDirect(); | 350 result->UseDirect(); |
| 379 } | 351 } |
| 380 return OK; | 352 return OK; |
| 381 } | 353 } |
| 382 | 354 |
| 383 if (config_.pac_url.is_valid() || config_.auto_detect) { | 355 if (config_.pac_url.is_valid() || config_.auto_detect) { |
| 384 if (callback) { | 356 if (!pac_thread_.get()) { |
| 385 // Create PAC thread for asynchronous mode. | 357 pac_thread_.reset(new base::Thread("pac-thread")); |
| 386 if (!pac_thread_.get()) { | 358 pac_thread_->Start(); |
| 387 pac_thread_.reset(new base::Thread("pac-thread")); | |
| 388 pac_thread_->Start(); | |
| 389 } | |
| 390 } else { | |
| 391 // If this request is synchronous, then there's no point | |
| 392 // in returning PacRequest instance | |
| 393 DCHECK(!pac_request); | |
| 394 } | 359 } |
| 395 | 360 |
| 396 scoped_refptr<PacRequest> req = | 361 scoped_refptr<PacRequest> req = |
| 397 new PacRequest(this, config_.pac_url, callback); | 362 new PacRequest(this, config_.pac_url, callback); |
| 398 | 363 |
| 399 // Strip away any reference fragments and the username/password, as they | 364 // Strip away any reference fragments and the username/password, as they |
| 400 // are not relevant to proxy resolution. | 365 // are not relevant to proxy resolution. |
| 401 GURL sanitized_url; | 366 GURL sanitized_url; |
| 402 { // TODO(eroman): The following duplicates logic from | 367 { // TODO(eroman): The following duplicates logic from |
| 403 // HttpUtil::SpecForRequest. Should probably live in net_util.h | 368 // HttpUtil::SpecForRequest. Should probably live in net_util.h |
| 404 GURL::Replacements replacements; | 369 GURL::Replacements replacements; |
| 405 replacements.ClearUsername(); | 370 replacements.ClearUsername(); |
| 406 replacements.ClearPassword(); | 371 replacements.ClearPassword(); |
| 407 replacements.ClearRef(); | 372 replacements.ClearRef(); |
| 408 sanitized_url = url.ReplaceComponents(replacements); | 373 sanitized_url = url.ReplaceComponents(replacements); |
| 409 } | 374 } |
| 410 | 375 |
| 411 req->Query(sanitized_url, result); | 376 req->Query(sanitized_url, result); |
| 412 | 377 |
| 413 if (callback) { | 378 if (pac_request) |
| 414 if (pac_request) | 379 *pac_request = req; |
| 415 *pac_request = req; | 380 |
| 416 return ERR_IO_PENDING; // Wait for callback. | 381 return ERR_IO_PENDING; // Wait for callback. |
| 417 } | |
| 418 return OK; | |
| 419 } | 382 } |
| 420 } | 383 } |
| 421 | 384 |
| 422 // otherwise, we have no proxy config | 385 // otherwise, we have no proxy config |
| 423 result->UseDirect(); | 386 result->UseDirect(); |
| 424 return OK; | 387 return OK; |
| 425 } | 388 } |
| 426 | 389 |
| 427 int ProxyService::ReconsiderProxyAfterError(const GURL& url, | 390 int ProxyService::ReconsiderProxyAfterError(const GURL& url, |
| 428 ProxyInfo* result, | 391 ProxyInfo* result, |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 547 // Some systems (the Mac, for example) allow CIDR-style specification of | 510 // Some systems (the Mac, for example) allow CIDR-style specification of |
| 548 // proxy bypass for IP-specified hosts (e.g. "10.0.0.0/8"; see | 511 // proxy bypass for IP-specified hosts (e.g. "10.0.0.0/8"; see |
| 549 // http://www.tcd.ie/iss/internet/osx_proxy.php for a real-world example). | 512 // http://www.tcd.ie/iss/internet/osx_proxy.php for a real-world example). |
| 550 // That's kinda cool so we'll provide that for everyone. | 513 // That's kinda cool so we'll provide that for everyone. |
| 551 // TODO(avi): implement here | 514 // TODO(avi): implement here |
| 552 } | 515 } |
| 553 | 516 |
| 554 return false; | 517 return false; |
| 555 } | 518 } |
| 556 | 519 |
| 520 SyncProxyServiceHelper::SyncProxyServiceHelper(MessageLoop* io_message_loop, |
| 521 ProxyService* proxy_service) |
| 522 : io_message_loop_(io_message_loop), |
| 523 proxy_service_(proxy_service), |
| 524 event_(false, false), |
| 525 ALLOW_THIS_IN_INITIALIZER_LIST(callback_( |
| 526 this, &SyncProxyServiceHelper::OnCompletion)) { |
| 527 DCHECK(io_message_loop_ != MessageLoop::current()); |
| 528 } |
| 529 |
| 530 int SyncProxyServiceHelper::ResolveProxy(const GURL& url, |
| 531 ProxyInfo* proxy_info) { |
| 532 DCHECK(io_message_loop_ != MessageLoop::current()); |
| 533 |
| 534 io_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( |
| 535 this, &SyncProxyServiceHelper::StartAsyncResolve, url)); |
| 536 |
| 537 event_.Wait(); |
| 538 |
| 539 if (result_ == net::OK) { |
| 540 *proxy_info = proxy_info_; |
| 541 } |
| 542 return result_; |
| 543 } |
| 544 |
| 545 int SyncProxyServiceHelper::ReconsiderProxyAfterError(const GURL& url, |
| 546 ProxyInfo* proxy_info) { |
| 547 DCHECK(io_message_loop_ != MessageLoop::current()); |
| 548 |
| 549 io_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( |
| 550 this, &SyncProxyServiceHelper::StartAsyncReconsider, url)); |
| 551 |
| 552 event_.Wait(); |
| 553 |
| 554 if (result_ == net::OK) { |
| 555 *proxy_info = proxy_info_; |
| 556 } |
| 557 return result_; |
| 558 } |
| 559 |
| 560 void SyncProxyServiceHelper::StartAsyncResolve(const GURL& url) { |
| 561 result_ = proxy_service_->ResolveProxy(url, &proxy_info_, &callback_, NULL); |
| 562 if (result_ != net::ERR_IO_PENDING) { |
| 563 OnCompletion(result_); |
| 564 } |
| 565 } |
| 566 |
| 567 void SyncProxyServiceHelper::StartAsyncReconsider(const GURL& url) { |
| 568 result_ = proxy_service_->ReconsiderProxyAfterError( |
| 569 url, &proxy_info_, &callback_, NULL); |
| 570 if (result_ != net::ERR_IO_PENDING) { |
| 571 OnCompletion(result_); |
| 572 } |
| 573 } |
| 574 |
| 575 void SyncProxyServiceHelper::OnCompletion(int rv) { |
| 576 result_ = rv; |
| 577 event_.Signal(); |
| 578 } |
| 579 |
| 557 } // namespace net | 580 } // namespace net |
| 558 | 581 |
| OLD | NEW |