| 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 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/message_loop.h" | 11 #include "base/message_loop.h" |
| 12 #include "base/string_util.h" | 12 #include "base/string_util.h" |
| 13 #include "googleurl/src/gurl.h" | 13 #include "googleurl/src/gurl.h" |
| 14 #include "net/base/net_errors.h" | 14 #include "net/base/net_errors.h" |
| 15 #include "net/base/net_util.h" | 15 #include "net/base/net_util.h" |
| 16 #include "net/proxy/init_proxy_resolver.h" |
| 16 #include "net/proxy/proxy_config_service_fixed.h" | 17 #include "net/proxy/proxy_config_service_fixed.h" |
| 17 #include "net/proxy/proxy_script_fetcher.h" | 18 #include "net/proxy/proxy_script_fetcher.h" |
| 18 #if defined(OS_WIN) | 19 #if defined(OS_WIN) |
| 19 #include "net/proxy/proxy_config_service_win.h" | 20 #include "net/proxy/proxy_config_service_win.h" |
| 20 #include "net/proxy/proxy_resolver_winhttp.h" | 21 #include "net/proxy/proxy_resolver_winhttp.h" |
| 21 #elif defined(OS_MACOSX) | 22 #elif defined(OS_MACOSX) |
| 22 #include "net/proxy/proxy_resolver_mac.h" | 23 #include "net/proxy/proxy_resolver_mac.h" |
| 23 #elif defined(OS_LINUX) | 24 #elif defined(OS_LINUX) |
| 24 #include "net/proxy/proxy_config_service_linux.h" | 25 #include "net/proxy/proxy_config_service_linux.h" |
| 25 #endif | 26 #endif |
| (...skipping 28 matching lines...) Expand all Loading... |
| 54 CompletionCallback* callback, | 55 CompletionCallback* callback, |
| 55 RequestHandle* request) { | 56 RequestHandle* request) { |
| 56 return ERR_NOT_IMPLEMENTED; | 57 return ERR_NOT_IMPLEMENTED; |
| 57 } | 58 } |
| 58 | 59 |
| 59 virtual void CancelRequest(RequestHandle request) { | 60 virtual void CancelRequest(RequestHandle request) { |
| 60 NOTREACHED(); | 61 NOTREACHED(); |
| 61 } | 62 } |
| 62 | 63 |
| 63 private: | 64 private: |
| 64 virtual void SetPacScriptByUrlInternal(const GURL& pac_url) {} | 65 virtual int SetPacScript(const GURL& /*pac_url*/, |
| 66 const std::string& /*pac_bytes*/, |
| 67 CompletionCallback* /*callback*/) { |
| 68 return ERR_NOT_IMPLEMENTED; |
| 69 } |
| 65 }; | 70 }; |
| 66 | 71 |
| 67 // ProxyService::PacRequest --------------------------------------------------- | 72 // ProxyService::PacRequest --------------------------------------------------- |
| 68 | 73 |
| 69 class ProxyService::PacRequest | 74 class ProxyService::PacRequest |
| 70 : public base::RefCounted<ProxyService::PacRequest> { | 75 : public base::RefCounted<ProxyService::PacRequest> { |
| 71 public: | 76 public: |
| 72 PacRequest(ProxyService* service, | 77 PacRequest(ProxyService* service, |
| 73 const GURL& url, | 78 const GURL& url, |
| 74 ProxyInfo* results, | 79 ProxyInfo* results, |
| (...skipping 18 matching lines...) Expand all Loading... |
| 93 | 98 |
| 94 return resolver()->GetProxyForURL( | 99 return resolver()->GetProxyForURL( |
| 95 url_, results_, &io_callback_, &resolve_job_); | 100 url_, results_, &io_callback_, &resolve_job_); |
| 96 } | 101 } |
| 97 | 102 |
| 98 bool is_started() const { | 103 bool is_started() const { |
| 99 // Note that !! casts to bool. (VS gives a warning otherwise). | 104 // Note that !! casts to bool. (VS gives a warning otherwise). |
| 100 return !!resolve_job_; | 105 return !!resolve_job_; |
| 101 } | 106 } |
| 102 | 107 |
| 103 void StartAndComplete() { | 108 void StartAndCompleteCheckingForSynchronous() { |
| 104 int rv = Start(); | 109 int rv = service_->TryToCompleteSynchronously(url_, results_); |
| 110 if (rv == ERR_IO_PENDING) |
| 111 rv = Start(); |
| 105 if (rv != ERR_IO_PENDING) | 112 if (rv != ERR_IO_PENDING) |
| 106 QueryComplete(rv); | 113 QueryComplete(rv); |
| 107 } | 114 } |
| 108 | 115 |
| 109 void Cancel() { | 116 void CancelResolveJob() { |
| 110 // The request may already be running in the resolver. | 117 // The request may already be running in the resolver. |
| 111 if (is_started()) { | 118 if (is_started()) { |
| 112 resolver()->CancelRequest(resolve_job_); | 119 resolver()->CancelRequest(resolve_job_); |
| 113 resolve_job_ = NULL; | 120 resolve_job_ = NULL; |
| 114 } | 121 } |
| 122 DCHECK(!is_started()); |
| 123 } |
| 124 |
| 125 void Cancel() { |
| 126 CancelResolveJob(); |
| 115 | 127 |
| 116 // Mark as cancelled, to prevent accessing this again later. | 128 // Mark as cancelled, to prevent accessing this again later. |
| 117 service_ = NULL; | 129 service_ = NULL; |
| 118 user_callback_ = NULL; | 130 user_callback_ = NULL; |
| 119 results_ = NULL; | 131 results_ = NULL; |
| 120 } | 132 } |
| 121 | 133 |
| 122 // Returns true if Cancel() has been called. | 134 // Returns true if Cancel() has been called. |
| 123 bool was_cancelled() const { return user_callback_ == NULL; } | 135 bool was_cancelled() const { return user_callback_ == NULL; } |
| 124 | 136 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 }; | 182 }; |
| 171 | 183 |
| 172 // ProxyService --------------------------------------------------------------- | 184 // ProxyService --------------------------------------------------------------- |
| 173 | 185 |
| 174 ProxyService::ProxyService(ProxyConfigService* config_service, | 186 ProxyService::ProxyService(ProxyConfigService* config_service, |
| 175 ProxyResolver* resolver) | 187 ProxyResolver* resolver) |
| 176 : config_service_(config_service), | 188 : config_service_(config_service), |
| 177 resolver_(resolver), | 189 resolver_(resolver), |
| 178 next_config_id_(1), | 190 next_config_id_(1), |
| 179 config_is_bad_(false), | 191 config_is_bad_(false), |
| 180 ALLOW_THIS_IN_INITIALIZER_LIST(proxy_script_fetcher_callback_( | 192 ALLOW_THIS_IN_INITIALIZER_LIST(init_proxy_resolver_callback_( |
| 181 this, &ProxyService::OnScriptFetchCompletion)), | 193 this, &ProxyService::OnInitProxyResolverComplete)) { |
| 182 fetched_pac_config_id_(ProxyConfig::INVALID_ID), | |
| 183 fetched_pac_error_(OK), | |
| 184 in_progress_fetch_config_id_(ProxyConfig::INVALID_ID) { | |
| 185 } | 194 } |
| 186 | 195 |
| 187 // static | 196 // static |
| 188 ProxyService* ProxyService::Create( | 197 ProxyService* ProxyService::Create( |
| 189 const ProxyConfig* pc, | 198 const ProxyConfig* pc, |
| 190 bool use_v8_resolver, | 199 bool use_v8_resolver, |
| 191 URLRequestContext* url_request_context, | 200 URLRequestContext* url_request_context, |
| 192 MessageLoop* io_loop) { | 201 MessageLoop* io_loop) { |
| 193 // Choose the system configuration service appropriate for each platform. | 202 // Choose the system configuration service appropriate for each platform. |
| 194 ProxyConfigService* proxy_config_service = pc ? | 203 ProxyConfigService* proxy_config_service = pc ? |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 247 | 256 |
| 248 // Check if the request can be completed right away. This is the case when | 257 // Check if the request can be completed right away. This is the case when |
| 249 // using a direct connection, or when the config is bad. | 258 // using a direct connection, or when the config is bad. |
| 250 UpdateConfigIfOld(); | 259 UpdateConfigIfOld(); |
| 251 int rv = TryToCompleteSynchronously(url, result); | 260 int rv = TryToCompleteSynchronously(url, result); |
| 252 if (rv != ERR_IO_PENDING) | 261 if (rv != ERR_IO_PENDING) |
| 253 return rv; | 262 return rv; |
| 254 | 263 |
| 255 scoped_refptr<PacRequest> req = new PacRequest(this, url, result, callback); | 264 scoped_refptr<PacRequest> req = new PacRequest(this, url, result, callback); |
| 256 | 265 |
| 257 bool resolver_is_ready = PrepareResolverForRequests(); | 266 bool resolver_is_ready = !IsInitializingProxyResolver(); |
| 258 | 267 |
| 259 if (resolver_is_ready) { | 268 if (resolver_is_ready) { |
| 260 // Start the resolve request. | 269 // Start the resolve request. |
| 261 rv = req->Start(); | 270 rv = req->Start(); |
| 262 if (rv != ERR_IO_PENDING) | 271 if (rv != ERR_IO_PENDING) |
| 263 return req->QueryDidComplete(rv); | 272 return req->QueryDidComplete(rv); |
| 264 } | 273 } |
| 265 | 274 |
| 266 DCHECK_EQ(ERR_IO_PENDING, rv); | 275 DCHECK_EQ(ERR_IO_PENDING, rv); |
| 267 DCHECK(!ContainsPendingRequest(req)); | 276 DCHECK(!ContainsPendingRequest(req)); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 283 // Fallback to a "direct" (no proxy) connection if the current configuration | 292 // Fallback to a "direct" (no proxy) connection if the current configuration |
| 284 // is known to be bad. | 293 // is known to be bad. |
| 285 if (config_is_bad_) { | 294 if (config_is_bad_) { |
| 286 // Reset this flag to false in case the ProxyInfo object is being | 295 // Reset this flag to false in case the ProxyInfo object is being |
| 287 // re-used by the caller. | 296 // re-used by the caller. |
| 288 result->config_was_tried_ = false; | 297 result->config_was_tried_ = false; |
| 289 } else { | 298 } else { |
| 290 // Remember that we are trying to use the current proxy configuration. | 299 // Remember that we are trying to use the current proxy configuration. |
| 291 result->config_was_tried_ = true; | 300 result->config_was_tried_ = true; |
| 292 | 301 |
| 302 if (config_.MayRequirePACResolver()) { |
| 303 // Need to go through ProxyResolver for this. |
| 304 return ERR_IO_PENDING; |
| 305 } |
| 306 |
| 293 if (!config_.proxy_rules.empty()) { | 307 if (!config_.proxy_rules.empty()) { |
| 294 ApplyProxyRules(url, config_.proxy_rules, result); | 308 ApplyProxyRules(url, config_.proxy_rules, result); |
| 295 return OK; | 309 return OK; |
| 296 } | 310 } |
| 297 | |
| 298 if (config_.pac_url.is_valid() || config_.auto_detect) { | |
| 299 // If we failed to download the PAC script, return the network error | |
| 300 // from the failed download. This is only going to happen for the first | |
| 301 // request after the failed download -- after that |config_is_bad_| will | |
| 302 // be set to true, so we short-cuircuit sooner. | |
| 303 if (fetched_pac_error_ != OK && !IsFetchingPacScript()) { | |
| 304 DidCompletePacRequest(fetched_pac_config_id_, fetched_pac_error_); | |
| 305 return fetched_pac_error_; | |
| 306 } | |
| 307 return ERR_IO_PENDING; | |
| 308 } | |
| 309 } | 311 } |
| 310 | 312 |
| 311 // otherwise, we have no proxy config | 313 // otherwise, we have no proxy config |
| 312 result->UseDirect(); | 314 result->UseDirect(); |
| 313 return OK; | 315 return OK; |
| 314 } | 316 } |
| 315 | 317 |
| 316 void ProxyService::ApplyProxyRules(const GURL& url, | 318 void ProxyService::ApplyProxyRules(const GURL& url, |
| 317 const ProxyConfig::ProxyRules& proxy_rules, | 319 const ProxyConfig::ProxyRules& proxy_rules, |
| 318 ProxyInfo* result) { | 320 ProxyInfo* result) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 347 | 349 |
| 348 ProxyService::~ProxyService() { | 350 ProxyService::~ProxyService() { |
| 349 // Cancel any inprogress requests. | 351 // Cancel any inprogress requests. |
| 350 for (PendingRequests::iterator it = pending_requests_.begin(); | 352 for (PendingRequests::iterator it = pending_requests_.begin(); |
| 351 it != pending_requests_.end(); | 353 it != pending_requests_.end(); |
| 352 ++it) { | 354 ++it) { |
| 353 (*it)->Cancel(); | 355 (*it)->Cancel(); |
| 354 } | 356 } |
| 355 } | 357 } |
| 356 | 358 |
| 359 void ProxyService::SuspendAllPendingRequests() { |
| 360 for (PendingRequests::iterator it = pending_requests_.begin(); |
| 361 it != pending_requests_.end(); |
| 362 ++it) { |
| 363 it->get()->CancelResolveJob(); |
| 364 } |
| 365 } |
| 366 |
| 357 void ProxyService::ResumeAllPendingRequests() { | 367 void ProxyService::ResumeAllPendingRequests() { |
| 368 DCHECK(!IsInitializingProxyResolver()); |
| 369 |
| 358 // Make a copy in case |this| is deleted during the synchronous completion | 370 // Make a copy in case |this| is deleted during the synchronous completion |
| 359 // of one of the requests. If |this| is deleted then all of the PacRequest | 371 // of one of the requests. If |this| is deleted then all of the PacRequest |
| 360 // instances will be Cancel()-ed. | 372 // instances will be Cancel()-ed. |
| 361 PendingRequests pending_copy = pending_requests_; | 373 PendingRequests pending_copy = pending_requests_; |
| 362 | 374 |
| 363 for (PendingRequests::iterator it = pending_copy.begin(); | 375 for (PendingRequests::iterator it = pending_copy.begin(); |
| 364 it != pending_copy.end(); | 376 it != pending_copy.end(); |
| 365 ++it) { | 377 ++it) { |
| 366 PacRequest* req = it->get(); | 378 PacRequest* req = it->get(); |
| 367 if (!req->is_started() && !req->was_cancelled()) | 379 if (!req->is_started() && !req->was_cancelled()) { |
| 368 req->StartAndComplete(); | 380 // Note that we re-check for synchronous completion, in case we are |
| 381 // no longer using a ProxyResolver (can happen if we fell-back to manual). |
| 382 req->StartAndCompleteCheckingForSynchronous(); |
| 383 } |
| 369 } | 384 } |
| 370 } | 385 } |
| 371 | 386 |
| 372 bool ProxyService::PrepareResolverForRequests() { | 387 void ProxyService::OnInitProxyResolverComplete(int result) { |
| 373 // While the PAC script is being downloaded, block requests. | 388 DCHECK(init_proxy_resolver_.get()); |
| 374 if (IsFetchingPacScript()) | 389 DCHECK(config_.MayRequirePACResolver()); |
| 375 return false; | 390 init_proxy_resolver_.reset(); |
| 376 | 391 |
| 377 // Check if a new PAC script needs to be downloaded. | 392 if (result != OK) { |
| 378 DCHECK(config_.id() != ProxyConfig::INVALID_ID); | 393 LOG(INFO) << "Failed configuring with PAC script, falling-back to manual " |
| 379 if (resolver_->expects_pac_bytes() && | 394 "proxy servers."; |
| 380 config_.id() != fetched_pac_config_id_) { | 395 config_.auto_detect = false; |
| 381 // For auto-detect we use the well known WPAD url. | 396 config_.pac_url = GURL(); |
| 382 GURL pac_url = config_.auto_detect ? | 397 DCHECK(!config_.MayRequirePACResolver()); |
| 383 GURL("http://wpad/wpad.dat") : config_.pac_url; | |
| 384 | |
| 385 in_progress_fetch_config_id_ = config_.id(); | |
| 386 | |
| 387 LOG(INFO) << "Starting fetch of PAC script " << pac_url | |
| 388 << " for config_id=" << in_progress_fetch_config_id_; | |
| 389 | |
| 390 proxy_script_fetcher_->Fetch( | |
| 391 pac_url, &in_progress_fetch_bytes_, &proxy_script_fetcher_callback_); | |
| 392 return false; | |
| 393 } | 398 } |
| 394 | 399 |
| 395 // We are good to go. | |
| 396 return true; | |
| 397 } | |
| 398 | |
| 399 void ProxyService::OnScriptFetchCompletion(int result) { | |
| 400 DCHECK(IsFetchingPacScript()); | |
| 401 DCHECK(resolver_->expects_pac_bytes()); | |
| 402 | |
| 403 LOG(INFO) << "Completed PAC script fetch for config_id=" | |
| 404 << in_progress_fetch_config_id_ | |
| 405 << " with error " << ErrorToString(result) | |
| 406 << ". Fetched a total of " << in_progress_fetch_bytes_.size() | |
| 407 << " bytes"; | |
| 408 | |
| 409 // Notify the ProxyResolver of the new script data (will be empty string if | |
| 410 // result != OK). | |
| 411 resolver_->SetPacScriptByData(in_progress_fetch_bytes_); | |
| 412 | |
| 413 fetched_pac_config_id_ = in_progress_fetch_config_id_; | |
| 414 fetched_pac_error_ = result; | |
| 415 in_progress_fetch_config_id_ = ProxyConfig::INVALID_ID; | |
| 416 in_progress_fetch_bytes_.clear(); | |
| 417 | |
| 418 // Resume any requests which we had to defer until the PAC script was | 400 // Resume any requests which we had to defer until the PAC script was |
| 419 // downloaded. | 401 // downloaded. |
| 420 ResumeAllPendingRequests(); | 402 ResumeAllPendingRequests(); |
| 421 } | 403 } |
| 422 | 404 |
| 423 int ProxyService::ReconsiderProxyAfterError(const GURL& url, | 405 int ProxyService::ReconsiderProxyAfterError(const GURL& url, |
| 424 ProxyInfo* result, | 406 ProxyInfo* result, |
| 425 CompletionCallback* callback, | 407 CompletionCallback* callback, |
| 426 PacRequest** pac_request) { | 408 PacRequest** pac_request) { |
| 427 // Check to see if we have a new config since ResolveProxy was called. We | 409 // Check to see if we have a new config since ResolveProxy was called. We |
| (...skipping 20 matching lines...) Expand all Loading... |
| 448 proxy_retry_info_.clear(); | 430 proxy_retry_info_.clear(); |
| 449 return ResolveProxy(url, result, callback, pac_request); | 431 return ResolveProxy(url, result, callback, pac_request); |
| 450 } | 432 } |
| 451 | 433 |
| 452 // We don't have new proxy settings to try, fallback to the next proxy | 434 // We don't have new proxy settings to try, fallback to the next proxy |
| 453 // in the list. | 435 // in the list. |
| 454 bool was_direct = result->is_direct(); | 436 bool was_direct = result->is_direct(); |
| 455 if (!was_direct && result->Fallback(&proxy_retry_info_)) | 437 if (!was_direct && result->Fallback(&proxy_retry_info_)) |
| 456 return OK; | 438 return OK; |
| 457 | 439 |
| 440 // TODO(eroman): Hmm, this doesn't seem right. For starters just because |
| 441 // auto_detect is true doesn't mean we are actually using it. |
| 458 if (!config_.auto_detect && !config_.proxy_rules.empty()) { | 442 if (!config_.auto_detect && !config_.proxy_rules.empty()) { |
| 459 // If auto detect is on, then we should try a DIRECT connection | 443 // If auto detect is on, then we should try a DIRECT connection |
| 460 // as the attempt to reach the proxy failed. | 444 // as the attempt to reach the proxy failed. |
| 461 return ERR_FAILED; | 445 return ERR_FAILED; |
| 462 } | 446 } |
| 463 | 447 |
| 464 // If we already tried a direct connection, then just give up. | 448 // If we already tried a direct connection, then just give up. |
| 465 if (was_direct) | 449 if (was_direct) |
| 466 return ERR_FAILED; | 450 return ERR_FAILED; |
| 467 | 451 |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 580 | 564 |
| 581 // Increment the ID to reflect that the config has changed. | 565 // Increment the ID to reflect that the config has changed. |
| 582 config_.set_id(next_config_id_++); | 566 config_.set_id(next_config_id_++); |
| 583 | 567 |
| 584 LOG(INFO) << "New proxy configuration was loaded:\n" << config_; | 568 LOG(INFO) << "New proxy configuration was loaded:\n" << config_; |
| 585 | 569 |
| 586 // Reset state associated with latest config. | 570 // Reset state associated with latest config. |
| 587 config_is_bad_ = false; | 571 config_is_bad_ = false; |
| 588 proxy_retry_info_.clear(); | 572 proxy_retry_info_.clear(); |
| 589 | 573 |
| 590 // Tell the resolver to use the new PAC URL (for resolvers that fetch the | 574 // Cancel any PAC fetching / ProxyResolver::SetPacScript() which was |
| 591 // PAC script internally). | 575 // in progress for the previous configuration. |
| 592 // TODO(eroman): this isn't quite right. See http://crbug.com/9985 | 576 init_proxy_resolver_.reset(); |
| 593 if ((config_.pac_url.is_valid() || config_.auto_detect) && | 577 |
| 594 !resolver_->expects_pac_bytes()) { | 578 // Start downloading + testing the PAC scripts for this new configuration. |
| 595 const GURL pac_url = config_.auto_detect ? GURL() : config_.pac_url; | 579 if (config_.MayRequirePACResolver()) { |
| 596 resolver_->SetPacScriptByUrl(pac_url); | 580 // Since InitProxyResolver will be playing around with the proxy resolver |
| 581 // as it tests the parsing of various PAC scripts, make sure there is |
| 582 // nothing in-flight in |resolver_|. These paused requests are resumed by |
| 583 // OnInitProxyResolverComplete(). |
| 584 SuspendAllPendingRequests(); |
| 585 |
| 586 init_proxy_resolver_.reset( |
| 587 new InitProxyResolver(resolver_.get(), proxy_script_fetcher_.get())); |
| 588 int rv = init_proxy_resolver_->Init( |
| 589 config_, &init_proxy_resolver_callback_); |
| 590 if (rv != ERR_IO_PENDING) |
| 591 OnInitProxyResolverComplete(rv); |
| 597 } | 592 } |
| 598 } | 593 } |
| 599 | 594 |
| 600 void ProxyService::UpdateConfigIfOld() { | 595 void ProxyService::UpdateConfigIfOld() { |
| 601 // The overhead of calling ProxyConfigService::GetProxyConfig is very low. | 596 // The overhead of calling ProxyConfigService::GetProxyConfig is very low. |
| 602 const TimeDelta kProxyConfigMaxAge = TimeDelta::FromSeconds(5); | 597 const TimeDelta kProxyConfigMaxAge = TimeDelta::FromSeconds(5); |
| 603 | 598 |
| 604 // Periodically check for a new config. | 599 // Periodically check for a new config. |
| 605 if (!config_has_been_initialized() || | 600 if (!config_has_been_initialized() || |
| 606 (TimeTicks::Now() - config_last_update_time_) > kProxyConfigMaxAge) | 601 (TimeTicks::Now() - config_last_update_time_) > kProxyConfigMaxAge) |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 746 OnCompletion(result_); | 741 OnCompletion(result_); |
| 747 } | 742 } |
| 748 } | 743 } |
| 749 | 744 |
| 750 void SyncProxyServiceHelper::OnCompletion(int rv) { | 745 void SyncProxyServiceHelper::OnCompletion(int rv) { |
| 751 result_ = rv; | 746 result_ = rv; |
| 752 event_.Signal(); | 747 event_.Signal(); |
| 753 } | 748 } |
| 754 | 749 |
| 755 } // namespace net | 750 } // namespace net |
| OLD | NEW |