Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(786)

Unified Diff: net/proxy/single_threaded_proxy_resolver.cc

Issue 149525: Remove the concept of threading from ProxyService, and move it into the Proxy... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Add missing header for mac Created 11 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/proxy/single_threaded_proxy_resolver.h ('k') | net/proxy/single_threaded_proxy_resolver_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/proxy/single_threaded_proxy_resolver.cc
===================================================================
--- net/proxy/single_threaded_proxy_resolver.cc (revision 20322)
+++ net/proxy/single_threaded_proxy_resolver.cc (working copy)
@@ -1,136 +1,76 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "net/proxy/proxy_service.h"
+#include "net/proxy/single_threaded_proxy_resolver.h"
-#include <algorithm>
-
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "base/string_util.h"
-#include "googleurl/src/gurl.h"
+#include "base/thread.h"
#include "net/base/net_errors.h"
-#include "net/proxy/proxy_config_service_fixed.h"
-#include "net/proxy/proxy_script_fetcher.h"
-#if defined(OS_WIN)
-#include "net/proxy/proxy_config_service_win.h"
-#include "net/proxy/proxy_resolver_winhttp.h"
-#elif defined(OS_MACOSX)
-#include "net/proxy/proxy_resolver_mac.h"
-#elif defined(OS_LINUX)
-#include "net/proxy/proxy_config_service_linux.h"
-#endif
-#include "net/proxy/proxy_resolver.h"
-#include "net/proxy/proxy_resolver_v8.h"
-#include "net/url_request/url_request_context.h"
+#include "net/proxy/proxy_info.h"
-using base::TimeDelta;
-using base::TimeTicks;
-
namespace net {
-// Config getter that fails every time.
-class ProxyConfigServiceNull : public ProxyConfigService {
+// Runs on the worker thread to call ProxyResolver::SetPacScriptByUrl or
+// ProxyResolver::SetPacScriptByData.
+// TODO(eroman): the lifetime of this task is ill-defined; |resolver_| must
+// be valid when the task eventually is run. Make this task cancellable.
+class SetPacScriptTask : public Task {
public:
- // ProxyConfigService implementation:
- virtual int GetProxyConfig(ProxyConfig* config) {
- return ERR_NOT_IMPLEMENTED;
- }
-};
+ SetPacScriptTask(ProxyResolver* resolver,
+ const GURL& pac_url,
+ const std::string& bytes)
+ : resolver_(resolver), pac_url_(pac_url), bytes_(bytes) {}
-// Proxy resolver that fails every time.
-class ProxyResolverNull : public ProxyResolver {
- public:
- ProxyResolverNull() : ProxyResolver(true /*does_fetch*/) {}
-
- // ProxyResolver implementation:
- virtual int GetProxyForURL(const GURL& /*query_url*/,
- const GURL& /*pac_url*/,
- ProxyInfo* /*results*/) {
- return ERR_NOT_IMPLEMENTED;
- }
-};
-
-// Strip away any reference fragments and the username/password, as they
-// are not relevant to proxy resolution.
-static GURL SanitizeURLForProxyResolver(const GURL& url) {
- // TODO(eroman): The following duplicates logic from
- // HttpUtil::SpecForRequest. Should probably live in net_util.h
- GURL::Replacements replacements;
- replacements.ClearUsername();
- replacements.ClearPassword();
- replacements.ClearRef();
- return url.ReplaceComponents(replacements);
-}
-
-// Runs on the PAC thread to notify the proxy resolver of the fetched PAC
-// script contents. This task shouldn't outlive ProxyService, since
-// |resolver| is owned by ProxyService.
-class NotifyFetchCompletionTask : public Task {
- public:
- NotifyFetchCompletionTask(ProxyResolver* resolver, const std::string& bytes)
- : resolver_(resolver), bytes_(bytes) {}
-
virtual void Run() {
- resolver_->SetPacScript(bytes_);
+ if (resolver_->expects_pac_bytes())
+ resolver_->SetPacScriptByData(bytes_);
+ else
+ resolver_->SetPacScriptByUrl(pac_url_);
}
private:
ProxyResolver* resolver_;
+ GURL pac_url_;
std::string bytes_;
};
-// ProxyService::PacRequest ---------------------------------------------------
+// SingleThreadedProxyResolver::Job -------------------------------------------
-// We rely on the fact that the origin thread (and its message loop) will not
-// be destroyed until after the PAC thread is destroyed.
-
-class ProxyService::PacRequest
- : public base::RefCountedThreadSafe<ProxyService::PacRequest> {
+class SingleThreadedProxyResolver::Job
+ : public base::RefCountedThreadSafe<SingleThreadedProxyResolver::Job> {
public:
- // |service| -- the ProxyService that owns this request.
- // |url| -- the url of the query.
- // |results| -- the structure to fill with proxy resolve results.
- PacRequest(ProxyService* service,
- const GURL& url,
- ProxyInfo* results,
- CompletionCallback* callback)
- : service_(service),
- callback_(callback),
- results_(results),
- url_(url),
- is_started_(false),
- origin_loop_(MessageLoop::current()) {
+ // |coordinator| -- the SingleThreadedProxyResolver that owns this job.
+ // |url| -- the URL of the query.
+ // |results| -- the structure to fill with proxy resolve results.
+ Job(SingleThreadedProxyResolver* coordinator,
+ const GURL& url,
+ ProxyInfo* results,
+ CompletionCallback* callback)
+ : coordinator_(coordinator),
+ callback_(callback),
+ results_(results),
+ url_(url),
+ is_started_(false),
+ origin_loop_(MessageLoop::current()) {
DCHECK(callback);
}
- // Start the resolve proxy request on the PAC thread.
- void Query() {
+ // Start the resolve proxy request on the worker thread.
+ void Start() {
is_started_ = true;
AddRef(); // balanced in QueryComplete
- GURL query_url = SanitizeURLForProxyResolver(url_);
- const GURL& pac_url = service_->config_.pac_url;
- results_->config_id_ = service_->config_.id();
-
- service_->pac_thread()->message_loop()->PostTask(FROM_HERE,
- NewRunnableMethod(this, &ProxyService::PacRequest::DoQuery,
- service_->resolver(), query_url, pac_url));
+ coordinator_->thread()->message_loop()->PostTask(
+ FROM_HERE, NewRunnableMethod(this, &Job::DoQuery,
+ coordinator_->resolver_.get()));
}
- // Run the request's callback on the current message loop.
- void PostCallback(int result_code) {
- AddRef(); // balanced in DoCallback
- MessageLoop::current()->PostTask(FROM_HERE,
- NewRunnableMethod(this, &ProxyService::PacRequest::DoCallback,
- result_code));
- }
+ bool is_started() const { return is_started_; }
void Cancel() {
// Clear these to inform QueryComplete that it should not try to
// access them.
- service_ = NULL;
+ coordinator_ = NULL;
callback_ = NULL;
results_ = NULL;
}
@@ -139,632 +79,153 @@
bool was_cancelled() const { return callback_ == NULL; }
private:
- friend class ProxyService;
-
- // Runs on the PAC thread.
- void DoQuery(ProxyResolver* resolver,
- const GURL& query_url,
- const GURL& pac_url) {
- int rv = resolver->GetProxyForURL(query_url, pac_url, &results_buf_);
+ // Runs on the worker thread.
+ void DoQuery(ProxyResolver* resolver) {
+ int rv = resolver->GetProxyForURL(url_, &results_buf_, NULL, NULL);
+ DCHECK_NE(rv, ERR_IO_PENDING);
origin_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this, &PacRequest::QueryComplete, rv));
+ NewRunnableMethod(this, &Job::QueryComplete, rv));
}
// Runs the completion callback on the origin thread.
void QueryComplete(int result_code) {
- // The PacRequest may have been cancelled after it was started.
+ // The Job may have been cancelled after it was started.
if (!was_cancelled()) {
- service_->DidCompletePacRequest(results_->config_id_, result_code);
-
- if (result_code == OK) {
+ if (result_code >= OK) { // Note: unit-tests use values > 0.
results_->Use(results_buf_);
- results_->RemoveBadProxies(service_->proxy_retry_info_);
}
callback_->Run(result_code);
// We check for cancellation once again, in case the callback deleted
// the owning ProxyService (whose destructor will in turn cancel us).
if (!was_cancelled())
- service_->RemoveFrontOfRequestQueue(this);
+ coordinator_->RemoveFrontOfJobsQueueAndStartNext(this);
}
Release(); // balances the AddRef in Query. we may get deleted after
// we return.
}
- // Runs the completion callback on the origin thread.
- void DoCallback(int result_code) {
- if (!was_cancelled()) {
- callback_->Run(result_code);
- }
- Release(); // balances the AddRef in PostCallback.
- }
-
// Must only be used on the "origin" thread.
- ProxyService* service_;
+ SingleThreadedProxyResolver* coordinator_;
CompletionCallback* callback_;
ProxyInfo* results_;
GURL url_;
bool is_started_;
- // Usable from within DoQuery on the PAC thread.
+ // Usable from within DoQuery on the worker thread.
ProxyInfo results_buf_;
MessageLoop* origin_loop_;
};
-// ProxyService ---------------------------------------------------------------
+// SingleThreadedProxyResolver ------------------------------------------------
-ProxyService::ProxyService(ProxyConfigService* config_service,
- ProxyResolver* resolver)
- : config_service_(config_service),
- resolver_(resolver),
- next_config_id_(1),
- config_is_bad_(false),
- ALLOW_THIS_IN_INITIALIZER_LIST(proxy_script_fetcher_callback_(
- this, &ProxyService::OnScriptFetchCompletion)),
- fetched_pac_config_id_(ProxyConfig::INVALID_ID),
- fetched_pac_error_(OK),
- in_progress_fetch_config_id_(ProxyConfig::INVALID_ID) {
+SingleThreadedProxyResolver::SingleThreadedProxyResolver(
+ ProxyResolver* resolver)
+ : ProxyResolver(resolver->expects_pac_bytes()),
+ resolver_(resolver) {
}
-// static
-ProxyService* ProxyService::Create(
- const ProxyConfig* pc,
- bool use_v8_resolver,
- URLRequestContext* url_request_context,
- MessageLoop* io_loop) {
- // Choose the system configuration service appropriate for each platform.
- ProxyConfigService* proxy_config_service = pc ?
- new ProxyConfigServiceFixed(*pc) :
- CreateSystemProxyConfigService(io_loop);
-
- ProxyResolver* proxy_resolver;
-
- if (use_v8_resolver) {
- // Send javascript errors and alerts to LOG(INFO).
- HostResolver* host_resolver = url_request_context->host_resolver();
- ProxyResolverV8::JSBindings* js_bindings =
- ProxyResolverV8::CreateDefaultBindings(host_resolver, io_loop);
-
- proxy_resolver = new ProxyResolverV8(js_bindings);
- } else {
- proxy_resolver = CreateNonV8ProxyResolver();
- }
-
- ProxyService* proxy_service = new ProxyService(
- proxy_config_service, proxy_resolver);
-
- if (!proxy_resolver->does_fetch()) {
- // Configure PAC script downloads to be issued using |url_request_context|.
- DCHECK(url_request_context);
- proxy_service->SetProxyScriptFetcher(
- ProxyScriptFetcher::Create(url_request_context));
- }
-
- return proxy_service;
-}
-
-// static
-ProxyService* ProxyService::CreateFixed(const ProxyConfig& pc) {
- return Create(&pc, false, NULL, NULL);
-}
-
-// static
-ProxyService* ProxyService::CreateNull() {
- // Use a configuration fetcher and proxy resolver which always fail.
- return new ProxyService(new ProxyConfigServiceNull, new ProxyResolverNull);
-}
-
-int ProxyService::ResolveProxy(const GURL& url, ProxyInfo* result,
- CompletionCallback* callback,
- PacRequest** pac_request) {
- DCHECK(callback);
-
- // Check if the request can be completed right away. This is the case when
- // using a direct connection, or when the config is bad.
- UpdateConfigIfOld();
- int rv = TryToCompleteSynchronously(url, result);
- if (rv != ERR_IO_PENDING)
- return rv;
-
- // Otherwise, push the request into the work queue.
- scoped_refptr<PacRequest> req = new PacRequest(this, url, result, callback);
- pending_requests_.push_back(req);
- ProcessPendingRequests(req.get());
-
- // Completion will be notifed through |callback|, unless the caller cancels
- // the request using |pac_request|.
- if (pac_request)
- *pac_request = req.get();
- return rv; // ERR_IO_PENDING
-}
-
-int ProxyService::TryToCompleteSynchronously(const GURL& url,
- ProxyInfo* result) {
- result->config_id_ = config_.id();
-
- DCHECK(config_.id() != ProxyConfig::INVALID_ID);
-
- // Fallback to a "direct" (no proxy) connection if the current configuration
- // is known to be bad.
- if (config_is_bad_) {
- // Reset this flag to false in case the ProxyInfo object is being
- // re-used by the caller.
- result->config_was_tried_ = false;
- } else {
- // Remember that we are trying to use the current proxy configuration.
- result->config_was_tried_ = true;
-
- if (!config_.proxy_rules.empty()) {
- ApplyProxyRules(url, config_.proxy_rules, result);
- return OK;
- }
-
- if (config_.pac_url.is_valid() || config_.auto_detect) {
- // If we failed to download the PAC script, return the network error
- // from the failed download. This is only going to happen for the first
- // request after the failed download -- after that |config_is_bad_| will
- // be set to true, so we short-cuircuit sooner.
- if (fetched_pac_error_ != OK && !IsFetchingPacScript()) {
- DidCompletePacRequest(fetched_pac_config_id_, fetched_pac_error_);
- return fetched_pac_error_;
- }
- return ERR_IO_PENDING;
- }
- }
-
- // otherwise, we have no proxy config
- result->UseDirect();
- return OK;
-}
-
-void ProxyService::ApplyProxyRules(const GURL& url,
- const ProxyConfig::ProxyRules& proxy_rules,
- ProxyInfo* result) {
- DCHECK(!proxy_rules.empty());
-
- if (ShouldBypassProxyForURL(url)) {
- result->UseDirect();
- return;
- }
-
- switch (proxy_rules.type) {
- case ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY:
- result->UseProxyServer(proxy_rules.single_proxy);
- break;
- case ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME: {
- const ProxyServer* entry = proxy_rules.MapSchemeToProxy(url.scheme());
- if (entry) {
- result->UseProxyServer(*entry);
- } else {
- // We failed to find a matching proxy server for the current URL
- // scheme. Default to direct.
- result->UseDirect();
- }
- break;
- }
- default:
- result->UseDirect();
- NOTREACHED();
- break;
- }
-}
-
-void ProxyService::InitPacThread() {
- if (!pac_thread_.get()) {
- pac_thread_.reset(new base::Thread("pac-thread"));
- pac_thread_->Start();
- }
-}
-
-ProxyService::~ProxyService() {
- // Cancel the inprogress request (if any), and free the rest.
- for (PendingRequestsQueue::iterator it = pending_requests_.begin();
- it != pending_requests_.end();
+SingleThreadedProxyResolver::~SingleThreadedProxyResolver() {
+ // Cancel the inprogress job (if any), and free the rest.
+ for (PendingJobsQueue::iterator it = pending_jobs_.begin();
+ it != pending_jobs_.end();
++it) {
(*it)->Cancel();
}
-}
-void ProxyService::ProcessPendingRequests(PacRequest* recent_req) {
- if (pending_requests_.empty())
- return;
-
- // While the PAC script is being downloaded, requests are blocked.
- if (IsFetchingPacScript())
- return;
-
- // Get the next request to process (FIFO).
- PacRequest* req = pending_requests_.front().get();
- if (req->is_started_)
- return;
-
- // The configuration may have changed since |req| was added to the
- // queue. It could be this request now completes synchronously.
- if (req != recent_req) {
- UpdateConfigIfOld();
- int rv = TryToCompleteSynchronously(req->url_, req->results_);
- if (rv != ERR_IO_PENDING) {
- req->PostCallback(rv);
- RemoveFrontOfRequestQueue(req);
- return;
- }
- }
-
- // Check if a new PAC script needs to be downloaded.
- DCHECK(config_.id() != ProxyConfig::INVALID_ID);
- if (!resolver_->does_fetch() && config_.id() != fetched_pac_config_id_) {
- // For auto-detect we use the well known WPAD url.
- GURL pac_url = config_.auto_detect ?
- GURL("http://wpad/wpad.dat") : config_.pac_url;
-
- in_progress_fetch_config_id_ = config_.id();
-
- LOG(INFO) << "Starting fetch of PAC script " << pac_url
- << " for config_id=" << in_progress_fetch_config_id_;
-
- proxy_script_fetcher_->Fetch(
- pac_url, &in_progress_fetch_bytes_, &proxy_script_fetcher_callback_);
- return;
- }
-
- // The only choice left now is to actually run the ProxyResolver on
- // the PAC thread.
- InitPacThread();
- req->Query();
+ // Note that |thread_| is destroyed before |resolver_|. This is important
+ // since |resolver_| could be running on |thread_|.
}
-void ProxyService::RemoveFrontOfRequestQueue(PacRequest* expected_req) {
- DCHECK(pending_requests_.front().get() == expected_req);
- pending_requests_.pop_front();
+int SingleThreadedProxyResolver::GetProxyForURL(const GURL& url,
+ ProxyInfo* results,
+ CompletionCallback* callback,
+ RequestHandle* request) {
+ DCHECK(callback);
- // Start next work item.
- ProcessPendingRequests(NULL);
-}
+ scoped_refptr<Job> job = new Job(this, url, results, callback);
+ pending_jobs_.push_back(job);
+ ProcessPendingJobs(); // Jobs can never finish synchronously.
-void ProxyService::OnScriptFetchCompletion(int result) {
- DCHECK(IsFetchingPacScript());
- DCHECK(!resolver_->does_fetch());
+ // Completion will be notified through |callback|, unless the caller cancels
+ // the request using |request|.
+ if (request)
+ *request = reinterpret_cast<RequestHandle>(job.get());
- LOG(INFO) << "Completed PAC script fetch for config_id="
- << in_progress_fetch_config_id_
- << " with error " << ErrorToString(result)
- << ". Fetched a total of " << in_progress_fetch_bytes_.size()
- << " bytes";
-
- // Notify the ProxyResolver of the new script data (will be empty string if
- // result != OK).
- InitPacThread();
- pac_thread()->message_loop()->PostTask(FROM_HERE,
- new NotifyFetchCompletionTask(
- resolver_.get(), in_progress_fetch_bytes_));
-
- fetched_pac_config_id_ = in_progress_fetch_config_id_;
- fetched_pac_error_ = result;
- in_progress_fetch_config_id_ = ProxyConfig::INVALID_ID;
- in_progress_fetch_bytes_.clear();
-
- // Start a pending request if any.
- ProcessPendingRequests(NULL);
+ return ERR_IO_PENDING;
}
-int ProxyService::ReconsiderProxyAfterError(const GURL& url,
- ProxyInfo* result,
- CompletionCallback* callback,
- PacRequest** pac_request) {
- // Check to see if we have a new config since ResolveProxy was called. We
- // want to re-run ResolveProxy in two cases: 1) we have a new config, or 2) a
- // direct connection failed and we never tried the current config.
-
- bool re_resolve = result->config_id_ != config_.id();
- if (!re_resolve) {
- UpdateConfig();
- if (result->config_id_ != config_.id()) {
- // A new configuration!
- re_resolve = true;
- } else if (!result->config_was_tried_) {
- // We never tried the proxy configuration since we thought it was bad,
- // but because we failed to establish a connection, let's try the proxy
- // configuration again to see if it will work now.
- config_is_bad_ = false;
- re_resolve = true;
- }
- }
- if (re_resolve) {
- // If we have a new config or the config was never tried, we delete the
- // list of bad proxies and we try again.
- proxy_retry_info_.clear();
- return ResolveProxy(url, result, callback, pac_request);
- }
-
- // We don't have new proxy settings to try, fallback to the next proxy
- // in the list.
- bool was_direct = result->is_direct();
- if (!was_direct && result->Fallback(&proxy_retry_info_))
- return OK;
-
- if (!config_.auto_detect && !config_.proxy_rules.empty()) {
- // If auto detect is on, then we should try a DIRECT connection
- // as the attempt to reach the proxy failed.
- return ERR_FAILED;
- }
-
- // If we already tried a direct connection, then just give up.
- if (was_direct)
- return ERR_FAILED;
-
- // Try going direct.
- result->UseDirect();
- return OK;
-}
-
-// There are four states of the request we need to handle:
+// There are three states of the request we need to handle:
// (1) Not started (just sitting in the queue).
-// (2) Executing PacRequest::DoQuery in the PAC thread.
-// (3) Waiting for PacRequest::QueryComplete to be run on the origin thread.
-// (4) Waiting for PacRequest::DoCallback to be run on the origin thread.
-void ProxyService::CancelPacRequest(PacRequest* req) {
+// (2) Executing Job::DoQuery in the worker thread.
+// (3) Waiting for Job::QueryComplete to be run on the origin thread.
+void SingleThreadedProxyResolver::CancelRequest(RequestHandle req) {
DCHECK(req);
- bool is_active_request = req->is_started_ && !pending_requests_.empty() &&
- pending_requests_.front().get() == req;
+ Job* job = reinterpret_cast<Job*>(req);
- req->Cancel();
+ bool is_active_job = job->is_started() && !pending_jobs_.empty() &&
+ pending_jobs_.front().get() == job;
- if (is_active_request) {
- RemoveFrontOfRequestQueue(req);
+ job->Cancel();
+
+ if (is_active_job) {
+ RemoveFrontOfJobsQueueAndStartNext(job);
return;
}
- // Otherwise just delete the request from the queue.
- PendingRequestsQueue::iterator it = std::find(
- pending_requests_.begin(), pending_requests_.end(), req);
- if (it != pending_requests_.end()) {
- pending_requests_.erase(it);
- }
+ // Otherwise just delete the job from the queue.
+ PendingJobsQueue::iterator it = std::find(
+ pending_jobs_.begin(), pending_jobs_.end(), job);
+ DCHECK(it != pending_jobs_.end());
+ pending_jobs_.erase(it);
}
-void ProxyService::SetProxyScriptFetcher(
- ProxyScriptFetcher* proxy_script_fetcher) {
- proxy_script_fetcher_.reset(proxy_script_fetcher);
+void SingleThreadedProxyResolver::SetPacScriptByUrlInternal(
+ const GURL& pac_url) {
+ SetPacScriptHelper(pac_url, std::string());
}
-void ProxyService::ResetConfigService(
- ProxyConfigService* new_proxy_config_service) {
- config_service_.reset(new_proxy_config_service);
- UpdateConfig();
+void SingleThreadedProxyResolver::SetPacScriptByDataInternal(
+ const std::string& bytes) {
+ SetPacScriptHelper(GURL(), bytes);
}
-void ProxyService::DidCompletePacRequest(int config_id, int result_code) {
- // If we get an error that indicates a bad PAC config, then we should
- // remember that, and not try the PAC config again for a while.
-
- // Our config may have already changed.
- if (result_code == OK || config_id != config_.id())
- return;
-
- // Remember that this configuration doesn't work.
- config_is_bad_ = true;
+void SingleThreadedProxyResolver::SetPacScriptHelper(const GURL& pac_url,
+ const std::string& bytes) {
+ EnsureThreadStarted();
+ thread()->message_loop()->PostTask(
+ FROM_HERE, new SetPacScriptTask(resolver(), pac_url, bytes));
}
-// static
-ProxyConfigService* ProxyService::CreateSystemProxyConfigService(
- MessageLoop* io_loop) {
-#if defined(OS_WIN)
- return new ProxyConfigServiceWin();
-#elif defined(OS_MACOSX)
- return new ProxyConfigServiceMac();
-#elif defined(OS_LINUX)
- ProxyConfigServiceLinux* linux_config_service
- = new ProxyConfigServiceLinux();
-
- // Assume we got called from the UI loop, which runs the default
- // glib main loop, so the current thread is where we should be
- // running gconf calls from.
- MessageLoop* glib_default_loop = MessageLoopForUI::current();
-
- // Synchronously fetch the current proxy config (since we are
- // running on glib_default_loop). Additionally register for gconf
- // notifications (delivered in |glib_default_loop|) to keep us
- // updated on when the proxy config has changed.
- linux_config_service->SetupAndFetchInitialConfig(glib_default_loop, io_loop);
-
- return linux_config_service;
-#else
- LOG(WARNING) << "Failed to choose a system proxy settings fetcher "
- "for this platform.";
- return new ProxyConfigServiceNull();
-#endif
+void SingleThreadedProxyResolver::EnsureThreadStarted() {
+ if (!thread_.get()) {
+ thread_.reset(new base::Thread("pac-thread"));
+ thread_->Start();
+ }
}
-// static
-ProxyResolver* ProxyService::CreateNonV8ProxyResolver() {
-#if defined(OS_WIN)
- return new ProxyResolverWinHttp();
-#elif defined(OS_MACOSX)
- return new ProxyResolverMac();
-#else
- LOG(WARNING) << "PAC support disabled because there is no fallback "
- "non-V8 implementation";
- return new ProxyResolverNull();
-#endif
-}
-
-void ProxyService::UpdateConfig() {
- bool is_first_update = !config_has_been_initialized();
-
- ProxyConfig latest;
- if (config_service_->GetProxyConfig(&latest) != OK) {
- if (is_first_update) {
- // Default to direct-connection if the first fetch fails.
- LOG(INFO) << "Failed initial proxy configuration fetch.";
- SetConfig(ProxyConfig());
- }
+void SingleThreadedProxyResolver::ProcessPendingJobs() {
+ if (pending_jobs_.empty())
return;
- }
- config_last_update_time_ = TimeTicks::Now();
- if (!is_first_update && latest.Equals(config_))
+ // Get the next job to process (FIFO).
+ Job* job = pending_jobs_.front().get();
+ if (job->is_started())
return;
- SetConfig(latest);
+ EnsureThreadStarted();
+ job->Start();
}
-void ProxyService::SetConfig(const ProxyConfig& config) {
- config_ = config;
+void SingleThreadedProxyResolver::RemoveFrontOfJobsQueueAndStartNext(
+ Job* expected_job) {
+ DCHECK_EQ(expected_job, pending_jobs_.front().get());
+ pending_jobs_.pop_front();
- // Increment the ID to reflect that the config has changed.
- config_.set_id(next_config_id_++);
-
- LOG(INFO) << "New proxy configuration was loaded:\n" << config_;
-
- // Reset state associated with latest config.
- config_is_bad_ = false;
- proxy_retry_info_.clear();
+ // Start next work item.
+ ProcessPendingJobs();
}
-void ProxyService::UpdateConfigIfOld() {
- // The overhead of calling ProxyConfigService::GetProxyConfig is very low.
- const TimeDelta kProxyConfigMaxAge = TimeDelta::FromSeconds(5);
-
- // Periodically check for a new config.
- if (!config_has_been_initialized() ||
- (TimeTicks::Now() - config_last_update_time_) > kProxyConfigMaxAge)
- UpdateConfig();
-}
-
-bool ProxyService::ShouldBypassProxyForURL(const GURL& url) {
- std::string url_domain = url.scheme();
- if (!url_domain.empty())
- url_domain += "://";
-
- url_domain += url.host();
- // This isn't superfluous; GURL case canonicalization doesn't hit the embedded
- // percent-encoded characters.
- StringToLowerASCII(&url_domain);
-
- // TODO(eroman): use GetHostAndPort().
- std::string url_domain_and_port = url_domain + ":"
- + IntToString(url.EffectiveIntPort());
-
- if (config_.proxy_bypass_local_names) {
- if (url.host().find('.') == std::string::npos)
- return true;
- }
-
- for(std::vector<std::string>::const_iterator i = config_.proxy_bypass.begin();
- i != config_.proxy_bypass.end(); ++i) {
- std::string bypass_url_domain = *i;
-
- // The proxy server bypass list can contain entities with http/https
- // If no scheme is specified then it indicates that all schemes are
- // allowed for the current entry. For matching this we just use
- // the protocol scheme of the url passed in.
- size_t scheme_colon = bypass_url_domain.find("://");
- if (scheme_colon == std::string::npos) {
- std::string bypass_url_domain_with_scheme = url.scheme();
- scheme_colon = bypass_url_domain_with_scheme.length();
- bypass_url_domain_with_scheme += "://";
- bypass_url_domain_with_scheme += bypass_url_domain;
-
- bypass_url_domain = bypass_url_domain_with_scheme;
- }
- std::string* url_compare_reference = &url_domain;
- size_t port_colon = bypass_url_domain.rfind(":");
- if (port_colon > scheme_colon) {
- // If our match pattern includes a colon followed by a digit,
- // and either it's preceded by ']' (IPv6 with port)
- // or has no other colon (IPv4),
- // then match against <domain>:<port>.
- // TODO(sdoyon): straighten this out, in particular the IPv6 brackets,
- // and do the parsing in ProxyConfig when we do the CIDR matching
- // mentioned below.
- std::string::const_iterator domain_begin =
- bypass_url_domain.begin() + scheme_colon + 3; // after ://
- std::string::const_iterator port_iter =
- bypass_url_domain.begin() + port_colon;
- std::string::const_iterator end = bypass_url_domain.end();
- if ((port_iter + 1) < end && IsAsciiDigit(*(port_iter + 1)) &&
- (*(port_iter - 1) == ']' ||
- std::find(domain_begin, port_iter, ':') == port_iter))
- url_compare_reference = &url_domain_and_port;
- }
-
- StringToLowerASCII(&bypass_url_domain);
-
- if (MatchPattern(*url_compare_reference, bypass_url_domain))
- return true;
-
- // Some systems (the Mac, for example) allow CIDR-style specification of
- // proxy bypass for IP-specified hosts (e.g. "10.0.0.0/8"; see
- // http://www.tcd.ie/iss/internet/osx_proxy.php for a real-world example).
- // That's kinda cool so we'll provide that for everyone.
- // TODO(avi): implement here. See: http://crbug.com/9835.
- // IP addresses ought to be canonicalized for comparison (whether
- // with CIDR, port, or IP address alone).
- }
-
- return false;
-}
-
-SyncProxyServiceHelper::SyncProxyServiceHelper(MessageLoop* io_message_loop,
- ProxyService* proxy_service)
- : io_message_loop_(io_message_loop),
- proxy_service_(proxy_service),
- event_(false, false),
- ALLOW_THIS_IN_INITIALIZER_LIST(callback_(
- this, &SyncProxyServiceHelper::OnCompletion)) {
- DCHECK(io_message_loop_ != MessageLoop::current());
-}
-
-int SyncProxyServiceHelper::ResolveProxy(const GURL& url,
- ProxyInfo* proxy_info) {
- DCHECK(io_message_loop_ != MessageLoop::current());
-
- io_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
- this, &SyncProxyServiceHelper::StartAsyncResolve, url));
-
- event_.Wait();
-
- if (result_ == net::OK) {
- *proxy_info = proxy_info_;
- }
- return result_;
-}
-
-int SyncProxyServiceHelper::ReconsiderProxyAfterError(const GURL& url,
- ProxyInfo* proxy_info) {
- DCHECK(io_message_loop_ != MessageLoop::current());
-
- io_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
- this, &SyncProxyServiceHelper::StartAsyncReconsider, url));
-
- event_.Wait();
-
- if (result_ == net::OK) {
- *proxy_info = proxy_info_;
- }
- return result_;
-}
-
-void SyncProxyServiceHelper::StartAsyncResolve(const GURL& url) {
- result_ = proxy_service_->ResolveProxy(url, &proxy_info_, &callback_, NULL);
- if (result_ != net::ERR_IO_PENDING) {
- OnCompletion(result_);
- }
-}
-
-void SyncProxyServiceHelper::StartAsyncReconsider(const GURL& url) {
- result_ = proxy_service_->ReconsiderProxyAfterError(
- url, &proxy_info_, &callback_, NULL);
- if (result_ != net::ERR_IO_PENDING) {
- OnCompletion(result_);
- }
-}
-
-void SyncProxyServiceHelper::OnCompletion(int rv) {
- result_ = rv;
- event_.Signal();
-}
-
} // namespace net
« no previous file with comments | « net/proxy/single_threaded_proxy_resolver.h ('k') | net/proxy/single_threaded_proxy_resolver_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698