summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-23 06:02:40 +0000
committereroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-23 06:02:40 +0000
commit119655003d8f225282179043e990df879062e529 (patch)
tree4ee907ddfb8e308a00b5bb9b624e072b028623b6
parentdacc2c255ae3f823e4a39d975e97c067a76dacf9 (diff)
downloadchromium_src-119655003d8f225282179043e990df879062e529.zip
chromium_src-119655003d8f225282179043e990df879062e529.tar.gz
chromium_src-119655003d8f225282179043e990df879062e529.tar.bz2
Change the ProxyConfigService interface to be asynchronous, and support observers.
The Windows implementation is still using a polling mechanism under the hood, however that polling has been moved to the worker pool so it won't block the IO thread in case WinHttpGetIEProxyConfigForCurrentUser is slow (crbug.com/12189). BUG=12189 Review URL: http://codereview.chromium.org/3056011 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@53442 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/net/resolve_proxy_msg_helper_unittest.cc8
-rw-r--r--net/base/net_log_event_type_list.h3
-rw-r--r--net/net.gyp2
-rw-r--r--net/proxy/polling_proxy_config_service.cc166
-rw-r--r--net/proxy/polling_proxy_config_service.h49
-rw-r--r--net/proxy/proxy_config_service.h37
-rw-r--r--net/proxy/proxy_config_service_fixed.h6
-rw-r--r--net/proxy/proxy_config_service_linux.cc27
-rw-r--r--net/proxy/proxy_config_service_linux.h34
-rw-r--r--net/proxy/proxy_config_service_linux_unittest.cc37
-rw-r--r--net/proxy/proxy_config_service_mac.cc19
-rw-r--r--net/proxy/proxy_config_service_mac.h9
-rw-r--r--net/proxy/proxy_config_service_win.cc21
-rw-r--r--net/proxy/proxy_config_service_win.h11
-rw-r--r--net/proxy/proxy_service.cc224
-rw-r--r--net/proxy/proxy_service.h51
-rw-r--r--net/proxy/proxy_service_unittest.cc135
17 files changed, 534 insertions, 305 deletions
diff --git a/chrome/browser/net/resolve_proxy_msg_helper_unittest.cc b/chrome/browser/net/resolve_proxy_msg_helper_unittest.cc
index c84ad41..78a16d7 100644
--- a/chrome/browser/net/resolve_proxy_msg_helper_unittest.cc
+++ b/chrome/browser/net/resolve_proxy_msg_helper_unittest.cc
@@ -13,9 +13,11 @@
// This ProxyConfigService always returns "http://pac" as the PAC url to use.
class MockProxyConfigService : public net::ProxyConfigService {
public:
- virtual int GetProxyConfig(net::ProxyConfig* results) {
- results->set_pac_url(GURL("http://pac"));
- return net::OK;
+ virtual void AddObserver(Observer* observer) {}
+ virtual void RemoveObserver(Observer* observer) {}
+ virtual bool GetLatestProxyConfig(net::ProxyConfig* results) {
+ *results = net::ProxyConfig::CreateFromCustomPacURL(GURL("http://pac"));
+ return true;
}
};
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h
index 2fcd6fa..d9225f8 100644
--- a/net/base/net_log_event_type_list.h
+++ b/net/base/net_log_event_type_list.h
@@ -79,9 +79,6 @@ EVENT_TYPE(PROXY_SERVICE)
// are found from ProxyService::init_proxy_resolver_log().
EVENT_TYPE(PROXY_SERVICE_WAITING_FOR_INIT_PAC)
-// The time taken to fetch the system proxy configuration.
-EVENT_TYPE(PROXY_SERVICE_POLL_CONFIG_SERVICE_FOR_CHANGES)
-
// This event is emitted to show what the PAC script returned. It can contain
// extra parameters that are either:
// {
diff --git a/net/net.gyp b/net/net.gyp
index bb3149d..c89d8ed 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -413,6 +413,8 @@
'proxy/init_proxy_resolver.h',
'proxy/multi_threaded_proxy_resolver.cc',
'proxy/multi_threaded_proxy_resolver.h',
+ 'proxy/polling_proxy_config_service.cc',
+ 'proxy/polling_proxy_config_service.h',
'proxy/proxy_bypass_rules.cc',
'proxy/proxy_bypass_rules.h',
'proxy/proxy_config.cc',
diff --git a/net/proxy/polling_proxy_config_service.cc b/net/proxy/polling_proxy_config_service.cc
new file mode 100644
index 0000000..ac42d9c
--- /dev/null
+++ b/net/proxy/polling_proxy_config_service.cc
@@ -0,0 +1,166 @@
+// Copyright (c) 2010 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/polling_proxy_config_service.h"
+
+#include "base/lock.h"
+#include "base/message_loop_proxy.h"
+#include "base/observer_list.h"
+#include "base/scoped_ptr.h"
+#include "base/worker_pool.h"
+#include "net/proxy/proxy_config.h"
+
+namespace net {
+
+// Reference-counted wrapper that does all the work (needs to be
+// reference-counted since we post tasks between threads; may outlive
+// the parent PollingProxyConfigService).
+class PollingProxyConfigService::Core
+ : public base::RefCountedThreadSafe<PollingProxyConfigService::Core> {
+ public:
+ Core(base::TimeDelta poll_interval,
+ GetConfigFunction get_config_func)
+ : get_config_func_(get_config_func),
+ has_config_(false),
+ poll_task_outstanding_(false),
+ poll_interval_(poll_interval),
+ have_initialized_origin_loop_(false) {
+ }
+
+ // Called when the parent PollingProxyConfigService is destroyed
+ // (observers should not be called past this point).
+ void Orphan() {
+ AutoLock l(lock_);
+ origin_loop_proxy_ = NULL;
+ }
+
+ bool GetLatestProxyConfig(ProxyConfig* config) {
+ LazyInitializeOriginLoop();
+ DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
+
+ OnLazyPoll();
+
+ // If we have already retrieved the proxy settings (on worker thread)
+ // then return what we last saw.
+ if (has_config_) {
+ *config = last_config_;
+ return true;
+ }
+ return false;
+ }
+
+ void AddObserver(Observer* observer) {
+ LazyInitializeOriginLoop();
+ DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
+ observers_.AddObserver(observer);
+ }
+
+ void RemoveObserver(Observer* observer) {
+ DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
+ observers_.RemoveObserver(observer);
+ }
+
+ // Check for a new configuration if enough time has elapsed.
+ void OnLazyPoll() {
+ LazyInitializeOriginLoop();
+ DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
+
+ if (poll_task_outstanding_)
+ return; // Still waiting for earlier test to finish.
+
+ base::TimeTicks now = base::TimeTicks::Now();
+
+ if (last_poll_time_.is_null() ||
+ (now - last_poll_time_) > poll_interval_) {
+ last_poll_time_ = now;
+ poll_task_outstanding_ = true;
+ WorkerPool::PostTask(
+ FROM_HERE,
+ NewRunnableMethod(
+ this, &Core::PollOnWorkerThread, get_config_func_), true);
+ }
+ }
+
+ private:
+ void PollOnWorkerThread(GetConfigFunction func) {
+ ProxyConfig config;
+ func(&config);
+
+ AutoLock l(lock_);
+ if (origin_loop_proxy_) {
+ origin_loop_proxy_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &Core::GetConfigCompleted, config));
+ }
+ }
+
+ // Called after the worker thread has finished retrieving a configuration.
+ void GetConfigCompleted(const ProxyConfig& config) {
+ DCHECK(poll_task_outstanding_);
+ poll_task_outstanding_ = false;
+
+ if (!origin_loop_proxy_)
+ return; // Was orphaned (parent has already been destroyed).
+
+ DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
+
+ if (!has_config_ || !last_config_.Equals(config)) {
+ // If the configuration has changed, notify the observers.
+ has_config_ = true;
+ last_config_ = config;
+ FOR_EACH_OBSERVER(Observer, observers_, OnProxyConfigChanged(config));
+ }
+ }
+
+ void LazyInitializeOriginLoop() {
+ // TODO(eroman): Really this should be done in the constructor, but right
+ // now chrome is constructing the ProxyConfigService on the
+ // UI thread so we can't cache the IO thread for the purpose
+ // of DCHECKs until the first call is made.
+ if (!have_initialized_origin_loop_) {
+ origin_loop_proxy_ = base::MessageLoopProxy::CreateForCurrentThread();
+ have_initialized_origin_loop_ = true;
+ }
+ }
+
+ GetConfigFunction get_config_func_;
+ ObserverList<Observer> observers_;
+ bool has_config_;
+ bool poll_task_outstanding_;
+ ProxyConfig last_config_;
+ base::TimeTicks last_poll_time_;
+ base::TimeDelta poll_interval_;
+ bool have_initialized_origin_loop_;
+
+ Lock lock_;
+ scoped_refptr<base::MessageLoopProxy> origin_loop_proxy_;
+};
+
+PollingProxyConfigService::PollingProxyConfigService(
+ base::TimeDelta poll_interval,
+ GetConfigFunction get_config_func)
+ : core_(new Core(poll_interval, get_config_func)) {
+}
+
+PollingProxyConfigService::~PollingProxyConfigService() {
+ core_->Orphan();
+}
+
+void PollingProxyConfigService::AddObserver(Observer* observer) {
+ core_->AddObserver(observer);
+}
+
+void PollingProxyConfigService::RemoveObserver(Observer* observer) {
+ core_->RemoveObserver(observer);
+}
+
+bool PollingProxyConfigService::GetLatestProxyConfig(ProxyConfig* config) {
+ return core_->GetLatestProxyConfig(config);
+}
+
+void PollingProxyConfigService::OnLazyPoll() {
+ core_->OnLazyPoll();
+}
+
+} // namespace net
diff --git a/net/proxy/polling_proxy_config_service.h b/net/proxy/polling_proxy_config_service.h
new file mode 100644
index 0000000..1bf889b
--- /dev/null
+++ b/net/proxy/polling_proxy_config_service.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2010 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.
+
+#ifndef NET_PROXY_POLLING_PROXY_CONFIG_SERVICE_H_
+#define NET_PROXY_POLLING_PROXY_CONFIG_SERVICE_H_
+
+#include "base/time.h"
+#include "base/ref_counted.h"
+#include "net/proxy/proxy_config_service.h"
+
+namespace net {
+
+// PollingProxyConfigService is a base class for creating ProxyConfigService
+// implementations that use polling to notice when settings have change.
+//
+// It runs code to get the current proxy settings on a background worker
+// thread, and notifies registered observers when the value changes.
+class PollingProxyConfigService : public ProxyConfigService {
+ public:
+ // ProxyConfigService implementation:
+ virtual void AddObserver(Observer* observer);
+ virtual void RemoveObserver(Observer* observer);
+ virtual bool GetLatestProxyConfig(ProxyConfig* config);
+ virtual void OnLazyPoll();
+
+ protected:
+ // Function for retrieving the current proxy configuration.
+ // Implementors must be threadsafe as the function will be invoked from
+ // worker threads.
+ typedef void (*GetConfigFunction)(ProxyConfig*);
+
+ // Creates a polling-based ProxyConfigService which will test for new
+ // settings at most every |poll_interval| time by calling |get_config_func|
+ // on a worker thread.
+ PollingProxyConfigService(
+ base::TimeDelta poll_interval,
+ GetConfigFunction get_config_func);
+
+ virtual ~PollingProxyConfigService();
+
+ private:
+ class Core;
+ scoped_refptr<Core> core_;
+};
+
+} // namespace net
+
+#endif // NET_PROXY_POLLING_PROXY_CONFIG_SERVICE_H_
diff --git a/net/proxy/proxy_config_service.h b/net/proxy/proxy_config_service.h
index 9f6bb50..1c65e3a 100644
--- a/net/proxy/proxy_config_service.h
+++ b/net/proxy/proxy_config_service.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -9,16 +9,39 @@ namespace net {
class ProxyConfig;
-// Synchronously fetch the system's proxy configuration settings. Called on
-// the IO Thread.
+// Service for watching when the proxy settings have changed.
class ProxyConfigService {
public:
+ // Observer for being notified when the proxy settings have changed.
+ class Observer {
+ public:
+ virtual ~Observer() {}
+ virtual void OnProxyConfigChanged(const ProxyConfig& config) = 0;
+ };
+
virtual ~ProxyConfigService() {}
- // Get the proxy configuration. Returns OK if successful or an error code if
- // otherwise. |config| should be in its initial state when this method is
- // called.
- virtual int GetProxyConfig(ProxyConfig* config) = 0;
+ // Adds/Removes an observer that will be called whenever the proxy
+ // configuration has changed.
+ virtual void AddObserver(Observer* observer) = 0;
+ virtual void RemoveObserver(Observer* observer) = 0;
+
+ // Gets the most recent value of the proxy configuration. Returns false if
+ // it is not available yet. In the case where we returned false, it is
+ // guaranteed that subscribed observers will be notified of a change at
+ // some point in the future once the configuration is available.
+ // Note that to avoid re-entrancy problems, implementations should not
+ // dispatch any change notifications from within this function.
+ virtual bool GetLatestProxyConfig(ProxyConfig* config) = 0;
+
+ // ProxyService will call this periodically during periods of activity.
+ // It can be used as a signal for polling-based implementations.
+ //
+ // Note that this is purely used as an optimization -- polling
+ // implementations could simply set a global timer that goes off every
+ // X seconds at which point they check for changes. However that has
+ // the disadvantage of doing continuous work even during idle periods.
+ virtual void OnLazyPoll() {}
};
} // namespace net
diff --git a/net/proxy/proxy_config_service_fixed.h b/net/proxy/proxy_config_service_fixed.h
index b677eb4..c8641b8 100644
--- a/net/proxy/proxy_config_service_fixed.h
+++ b/net/proxy/proxy_config_service_fixed.h
@@ -17,9 +17,11 @@ class ProxyConfigServiceFixed : public ProxyConfigService {
explicit ProxyConfigServiceFixed(const ProxyConfig& pc) : pc_(pc) {}
// ProxyConfigService methods:
- virtual int GetProxyConfig(ProxyConfig* config) {
+ virtual void AddObserver(Observer* observer) {}
+ virtual void RemoveObserver(Observer* observer) {}
+ virtual bool GetLatestProxyConfig(ProxyConfig* config) {
*config = pc_;
- return OK;
+ return true;
}
private:
diff --git a/net/proxy/proxy_config_service_linux.cc b/net/proxy/proxy_config_service_linux.cc
index bd863bd..e33a487 100644
--- a/net/proxy/proxy_config_service_linux.cc
+++ b/net/proxy/proxy_config_service_linux.cc
@@ -1085,7 +1085,7 @@ void ProxyConfigServiceLinux::Delegate::SetupAndFetchInitialConfig(
LOG(INFO) << "Monitoring of proxy setting changes is disabled";
// Fetch and cache the current proxy config. The config is left in
- // cached_config_, where GetProxyConfig() running on the IO thread
+ // cached_config_, where GetLatestProxyConfig() running on the IO thread
// will expect to find it. This is safe to do because we return
// before this ProxyConfigServiceLinux is passed on to
// the ProxyService.
@@ -1133,14 +1133,30 @@ void ProxyConfigServiceLinux::Delegate::SetupAndFetchInitialConfig(
}
}
-int ProxyConfigServiceLinux::Delegate::GetProxyConfig(ProxyConfig* config) {
+void ProxyConfigServiceLinux::Delegate::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void ProxyConfigServiceLinux::Delegate::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+bool ProxyConfigServiceLinux::Delegate::GetLatestProxyConfig(
+ ProxyConfig* config) {
// This is called from the IO thread.
DCHECK(!io_loop_ || MessageLoop::current() == io_loop_);
// Simply return the last proxy configuration that glib_default_loop
// notified us of.
- *config = cached_config_;
- return cached_config_.is_valid() ? OK : ERR_FAILED;
+ *config = cached_config_.is_valid() ?
+ cached_config_ : ProxyConfig::CreateDirect();
+
+ // We return true to indicate that *config was filled in. It is always
+ // going to be available since we initialized eagerly on the UI thread.
+ // TODO(eroman): do lazy initialization instead, so we no longer need
+ // to construct ProxyConfigServiceLinux on the UI thread.
+ // In which case, we may return false here.
+ return true;
}
// Depending on the GConfSettingGetter in use, this method will be called
@@ -1153,7 +1169,7 @@ void ProxyConfigServiceLinux::Delegate::OnCheckProxyConfigSettings() {
if (valid)
new_config.set_id(1); // mark it as valid
- // See if it is different than what we had before.
+ // See if it is different from what we had before.
if (new_config.is_valid() != reference_config_.is_valid() ||
!new_config.Equals(reference_config_)) {
// Post a task to |io_loop| with the new configuration, so it can
@@ -1174,6 +1190,7 @@ void ProxyConfigServiceLinux::Delegate::SetNewProxyConfig(
DCHECK(MessageLoop::current() == io_loop_);
LOG(INFO) << "Proxy configuration changed";
cached_config_ = new_config;
+ FOR_EACH_OBSERVER(Observer, observers_, OnProxyConfigChanged(new_config));
}
void ProxyConfigServiceLinux::Delegate::PostDestroyTask() {
diff --git a/net/proxy/proxy_config_service_linux.h b/net/proxy/proxy_config_service_linux.h
index c6e9c90..600c5cc 100644
--- a/net/proxy/proxy_config_service_linux.h
+++ b/net/proxy/proxy_config_service_linux.h
@@ -11,6 +11,7 @@
#include "base/basictypes.h"
#include "base/env_var.h"
#include "base/message_loop.h"
+#include "base/observer_list.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "net/proxy/proxy_config.h"
@@ -90,16 +91,18 @@ class ProxyConfigServiceLinux : public ProxyConfigService {
// ProxyConfigServiceLinux is created on the UI thread, and
// SetupAndFetchInitialConfig() is immediately called to
- // synchronously fetch the original configuration and setup gconf
+ // synchronously fetch the original configuration and set up gconf
// notifications on the UI thread.
//
- // Passed that point, it is accessed periodically through
- // GetProxyConfig() from the IO thread.
+ // Past that point, it is accessed periodically through the
+ // ProxyConfigService interface (GetLatestProxyConfig, AddObserver,
+ // RemoveObserver) from the IO thread.
//
// gconf change notification callbacks can occur at any time and are
// run on the UI thread. The new gconf settings are fetched on the
// UI thread, and the new resulting proxy config is posted to the IO
- // thread through Delegate::SetNewProxyConfig().
+ // thread through Delegate::SetNewProxyConfig(). We then notify
+ // observers on the IO thread of the configuration change.
//
// ProxyConfigServiceLinux is deleted from the IO thread.
//
@@ -138,7 +141,9 @@ class ProxyConfigServiceLinux : public ProxyConfigService {
void OnCheckProxyConfigSettings();
// Called from IO thread.
- int GetProxyConfig(ProxyConfig* config);
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+ bool GetLatestProxyConfig(ProxyConfig* config);
// Posts a call to OnDestroy() to the UI thread. Called from
// ProxyConfigServiceLinux's destructor.
@@ -180,7 +185,7 @@ class ProxyConfigServiceLinux : public ProxyConfigService {
scoped_ptr<GConfSettingGetter> gconf_getter_;
// Cached proxy configuration, to be returned by
- // GetProxyConfig. Initially populated from the UI thread, but
+ // GetLatestProxyConfig. Initially populated from the UI thread, but
// afterwards only accessed from the IO thread.
ProxyConfig cached_config_;
@@ -199,10 +204,12 @@ class ProxyConfigServiceLinux : public ProxyConfigService {
// this thread. Since gconf is not thread safe, any use of gconf
// must be done on the thread running this loop.
MessageLoop* glib_default_loop_;
- // MessageLoop for the IO thread. GetProxyConfig() is called from
+ // MessageLoop for the IO thread. GetLatestProxyConfig() is called from
// the thread running this loop.
MessageLoop* io_loop_;
+ ObserverList<Observer> observers_;
+
DISALLOW_COPY_AND_ASSIGN(Delegate);
};
@@ -231,8 +238,17 @@ class ProxyConfigServiceLinux : public ProxyConfigService {
// ProxyConfigService methods:
// Called from IO thread.
- virtual int GetProxyConfig(ProxyConfig* config) {
- return delegate_->GetProxyConfig(config);
+
+ virtual void AddObserver(Observer* observer) {
+ delegate_->AddObserver(observer);
+ }
+
+ virtual void RemoveObserver(Observer* observer) {
+ delegate_->RemoveObserver(observer);
+ }
+
+ virtual bool GetLatestProxyConfig(ProxyConfig* config) {
+ return delegate_->GetLatestProxyConfig(config);
}
private:
diff --git a/net/proxy/proxy_config_service_linux_unittest.cc b/net/proxy/proxy_config_service_linux_unittest.cc
index 0a84548..c43e207 100644
--- a/net/proxy/proxy_config_service_linux_unittest.cc
+++ b/net/proxy/proxy_config_service_linux_unittest.cc
@@ -239,7 +239,7 @@ class MockGConfSettingGetter
} // namespace
} // namespace net
-// This helper class runs ProxyConfigServiceLinux::GetProxyConfig() on
+// This helper class runs ProxyConfigServiceLinux::GetLatestProxyConfig() on
// the IO thread and synchronously waits for the result.
// Some code duplicated from proxy_script_fetcher_unittest.cc.
class SynchConfigGetter {
@@ -282,12 +282,12 @@ class SynchConfigGetter {
static_cast<MessageLoopForIO*>(file_loop));
}
// Synchronously gets the proxy config.
- int SyncGetProxyConfig(net::ProxyConfig* config) {
+ bool SyncGetLatestProxyConfig(net::ProxyConfig* config) {
io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &SynchConfigGetter::GetConfigOnIOThread));
+ this, &SynchConfigGetter::GetLatestConfigOnIOThread));
Wait();
*config = proxy_config_;
- return get_config_result_;
+ return get_latest_config_result_;
}
private:
@@ -296,10 +296,11 @@ class SynchConfigGetter {
event_.Signal();
}
- // Calls GetProxyConfig, running on |io_thread_|] Signals |event_|
+ // Calls GetLatestProxyConfig, running on |io_thread_| Signals |event_|
// on completion.
- void GetConfigOnIOThread() {
- get_config_result_ = config_service_->GetProxyConfig(&proxy_config_);
+ void GetLatestConfigOnIOThread() {
+ get_latest_config_result_ =
+ config_service_->GetLatestProxyConfig(&proxy_config_);
event_.Signal();
}
@@ -322,7 +323,7 @@ class SynchConfigGetter {
// The config obtained by |io_thread_| and read back by the main
// thread.
net::ProxyConfig proxy_config_;
- int get_config_result_; // Return value from GetProxyConfig().
+ bool get_latest_config_result_; // Return value from GetLatestProxyConfig().
};
DISABLE_RUNNABLE_METHOD_REFCOUNT(SynchConfigGetter);
@@ -606,7 +607,7 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicGConfTest) {
ProxyConfig config;
gconf_getter->values = tests[i].values;
sync_config_getter.SetupAndInitialFetch();
- sync_config_getter.SyncGetProxyConfig(&config);
+ sync_config_getter.SyncGetLatestProxyConfig(&config);
EXPECT_EQ(tests[i].auto_detect, config.auto_detect());
EXPECT_EQ(tests[i].pac_url, config.pac_url());
@@ -896,7 +897,7 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) {
ProxyConfig config;
env_getter->values = tests[i].values;
sync_config_getter.SetupAndInitialFetch();
- sync_config_getter.SyncGetProxyConfig(&config);
+ sync_config_getter.SyncGetLatestProxyConfig(&config);
EXPECT_EQ(tests[i].auto_detect, config.auto_detect());
EXPECT_EQ(tests[i].pac_url, config.pac_url());
@@ -915,14 +916,14 @@ TEST_F(ProxyConfigServiceLinuxTest, GconfNotification) {
// Start with no proxy.
gconf_getter->values.mode = "none";
sync_config_getter.SetupAndInitialFetch();
- sync_config_getter.SyncGetProxyConfig(&config);
+ sync_config_getter.SyncGetLatestProxyConfig(&config);
EXPECT_FALSE(config.auto_detect());
// Now set to auto-detect.
gconf_getter->values.mode = "auto";
// Simulate gconf notification callback.
service->OnCheckProxyConfigSettings();
- sync_config_getter.SyncGetProxyConfig(&config);
+ sync_config_getter.SyncGetLatestProxyConfig(&config);
EXPECT_TRUE(config.auto_detect());
}
@@ -1298,7 +1299,7 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) {
file_util::WriteFile(kioslaverc_, tests[i].kioslaverc.c_str(),
tests[i].kioslaverc.length());
sync_config_getter.SetupAndInitialFetch();
- sync_config_getter.SyncGetProxyConfig(&config);
+ sync_config_getter.SyncGetLatestProxyConfig(&config);
EXPECT_EQ(tests[i].auto_detect, config.auto_detect());
EXPECT_EQ(tests[i].pac_url, config.pac_url());
@@ -1329,7 +1330,7 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEHomePicker) {
new ProxyConfigServiceLinux(env_getter));
ProxyConfig config;
sync_config_getter.SetupAndInitialFetch();
- sync_config_getter.SyncGetProxyConfig(&config);
+ sync_config_getter.SyncGetLatestProxyConfig(&config);
EXPECT_TRUE(config.auto_detect());
EXPECT_EQ(GURL(), config.pac_url());
}
@@ -1348,7 +1349,7 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEHomePicker) {
new ProxyConfigServiceLinux(env_getter));
ProxyConfig config;
sync_config_getter.SetupAndInitialFetch();
- sync_config_getter.SyncGetProxyConfig(&config);
+ sync_config_getter.SyncGetLatestProxyConfig(&config);
EXPECT_FALSE(config.auto_detect());
EXPECT_EQ(slaverc4_pac_url, config.pac_url());
}
@@ -1361,7 +1362,7 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEHomePicker) {
new ProxyConfigServiceLinux(env_getter));
ProxyConfig config;
sync_config_getter.SetupAndInitialFetch();
- sync_config_getter.SyncGetProxyConfig(&config);
+ sync_config_getter.SyncGetLatestProxyConfig(&config);
EXPECT_TRUE(config.auto_detect());
EXPECT_EQ(GURL(), config.pac_url());
}
@@ -1375,7 +1376,7 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEHomePicker) {
new ProxyConfigServiceLinux(env_getter));
ProxyConfig config;
sync_config_getter.SetupAndInitialFetch();
- sync_config_getter.SyncGetProxyConfig(&config);
+ sync_config_getter.SyncGetLatestProxyConfig(&config);
EXPECT_TRUE(config.auto_detect());
EXPECT_EQ(GURL(), config.pac_url());
}
@@ -1392,7 +1393,7 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEHomePicker) {
new ProxyConfigServiceLinux(env_getter));
ProxyConfig config;
sync_config_getter.SetupAndInitialFetch();
- sync_config_getter.SyncGetProxyConfig(&config);
+ sync_config_getter.SyncGetLatestProxyConfig(&config);
EXPECT_TRUE(config.auto_detect());
EXPECT_EQ(GURL(), config.pac_url());
}
diff --git a/net/proxy/proxy_config_service_mac.cc b/net/proxy/proxy_config_service_mac.cc
index 1e04ff0..27a0426 100644
--- a/net/proxy/proxy_config_service_mac.cc
+++ b/net/proxy/proxy_config_service_mac.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -16,8 +16,12 @@
#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_server.h"
+namespace net {
+
namespace {
+const int kPollIntervalSec = 5;
+
// Utility function to pull out a boolean value from a dictionary and return it,
// returning a default value if the key is not present.
bool GetBoolFromDictionary(CFDictionaryRef dict,
@@ -35,11 +39,7 @@ bool GetBoolFromDictionary(CFDictionaryRef dict,
return default_value;
}
-} // namespace
-
-namespace net {
-
-int ProxyConfigServiceMac::GetProxyConfig(ProxyConfig* config) {
+void GetCurrentProxyConfig(ProxyConfig* config) {
scoped_cftyperef<CFDictionaryRef> config_dict(
SCDynamicStoreCopyProxies(NULL));
DCHECK(config_dict);
@@ -157,8 +157,13 @@ int ProxyConfigServiceMac::GetProxyConfig(ProxyConfig* config) {
false)) {
config->proxy_rules().bypass_rules.AddRuleToBypassLocal();
}
+}
+
+} // namespace
- return OK;
+ProxyConfigServiceMac::ProxyConfigServiceMac()
+ : PollingProxyConfigService(base::TimeDelta::FromSeconds(kPollIntervalSec),
+ &GetCurrentProxyConfig) {
}
} // namespace net
diff --git a/net/proxy/proxy_config_service_mac.h b/net/proxy/proxy_config_service_mac.h
index 6a93228..4a62fa4 100644
--- a/net/proxy/proxy_config_service_mac.h
+++ b/net/proxy/proxy_config_service_mac.h
@@ -5,14 +5,15 @@
#ifndef NET_PROXY_PROXY_CONFIG_SERVICE_MAC_H_
#define NET_PROXY_PROXY_CONFIG_SERVICE_MAC_H_
-#include "net/proxy/proxy_config_service.h"
+#include "net/proxy/polling_proxy_config_service.h"
namespace net {
-class ProxyConfigServiceMac : public ProxyConfigService {
+// TODO(eroman): Use notification-based system APIs instead of polling for
+// changes.
+class ProxyConfigServiceMac : public PollingProxyConfigService {
public:
- // ProxyConfigService methods:
- virtual int GetProxyConfig(ProxyConfig* config);
+ ProxyConfigServiceMac();
};
} // namespace net
diff --git a/net/proxy/proxy_config_service_win.cc b/net/proxy/proxy_config_service_win.cc
index 38819de..403d149 100644
--- a/net/proxy/proxy_config_service_win.cc
+++ b/net/proxy/proxy_config_service_win.cc
@@ -17,7 +17,11 @@
namespace net {
-static void FreeIEConfig(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* ie_config) {
+namespace {
+
+const int kPollIntervalSec = 5;
+
+void FreeIEConfig(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* ie_config) {
if (ie_config->lpszAutoConfigUrl)
GlobalFree(ie_config->lpszAutoConfigUrl);
if (ie_config->lpszProxy)
@@ -26,16 +30,25 @@ static void FreeIEConfig(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* ie_config) {
GlobalFree(ie_config->lpszProxyBypass);
}
-int ProxyConfigServiceWin::GetProxyConfig(ProxyConfig* config) {
+} // namespace
+
+ProxyConfigServiceWin::ProxyConfigServiceWin()
+ : PollingProxyConfigService(
+ base::TimeDelta::FromSeconds(kPollIntervalSec),
+ &ProxyConfigServiceWin::GetCurrentProxyConfig) {
+}
+
+// static
+void ProxyConfigServiceWin::GetCurrentProxyConfig(ProxyConfig* config) {
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ie_config = {0};
if (!WinHttpGetIEProxyConfigForCurrentUser(&ie_config)) {
LOG(ERROR) << "WinHttpGetIEProxyConfigForCurrentUser failed: " <<
GetLastError();
- return ERR_FAILED; // TODO(darin): Bug 1189288: translate error code.
+ *config = ProxyConfig::CreateDirect();
+ return;
}
SetFromIEConfig(config, ie_config);
FreeIEConfig(&ie_config);
- return OK;
}
// static
diff --git a/net/proxy/proxy_config_service_win.h b/net/proxy/proxy_config_service_win.h
index 6217a9e..fee68cc 100644
--- a/net/proxy/proxy_config_service_win.h
+++ b/net/proxy/proxy_config_service_win.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -8,21 +8,22 @@
#include <windows.h>
#include <winhttp.h>
-#include "net/proxy/proxy_config_service.h"
+#include "net/proxy/polling_proxy_config_service.h"
#include "testing/gtest/include/gtest/gtest_prod.h"
namespace net {
// Implementation of ProxyConfigService that retrieves the system proxy
// settings.
-class ProxyConfigServiceWin : public ProxyConfigService {
+class ProxyConfigServiceWin : public PollingProxyConfigService {
public:
- // ProxyConfigService methods:
- virtual int GetProxyConfig(ProxyConfig* config);
+ ProxyConfigServiceWin();
private:
FRIEND_TEST(ProxyConfigServiceWinTest, SetFromIEConfig);
+ static void GetCurrentProxyConfig(ProxyConfig* config);
+
// Set |config| using the proxy configuration values of |ie_config|.
static void SetFromIEConfig(
ProxyConfig* config,
diff --git a/net/proxy/proxy_service.cc b/net/proxy/proxy_service.cc
index 8f9d28c..d13b1f1 100644
--- a/net/proxy/proxy_service.cc
+++ b/net/proxy/proxy_service.cc
@@ -43,12 +43,15 @@ namespace net {
static const size_t kMaxNumNetLogEntries = 100;
static const size_t kDefaultNumPacThreads = 4;
-// Config getter that fails every time.
-class ProxyConfigServiceNull : public ProxyConfigService {
+// Config getter that always returns direct settings.
+class ProxyConfigServiceDirect : public ProxyConfigService {
public:
// ProxyConfigService implementation:
- virtual int GetProxyConfig(ProxyConfig* config) {
- return ERR_NOT_IMPLEMENTED;
+ virtual void AddObserver(Observer* observer) {}
+ virtual void RemoveObserver(Observer* observer) {}
+ virtual bool GetLatestProxyConfig(ProxyConfig* config) {
+ *config = ProxyConfig::CreateDirect();
+ return true;
}
};
@@ -163,6 +166,8 @@ class ProxyService::PacRequest
DCHECK(!was_cancelled());
DCHECK(!is_started());
+ DCHECK(service_->config_.is_valid());
+
config_id_ = service_->config_.id();
return resolver()->GetProxyForURL(
@@ -262,14 +267,15 @@ class ProxyService::PacRequest
ProxyService::ProxyService(ProxyConfigService* config_service,
ProxyResolver* resolver,
NetLog* net_log)
- : config_service_(config_service),
- resolver_(resolver),
+ : resolver_(resolver),
next_config_id_(1),
should_use_proxy_resolver_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(init_proxy_resolver_callback_(
this, &ProxyService::OnInitProxyResolverComplete)),
+ current_state_(STATE_NONE) ,
net_log_(net_log) {
NetworkChangeNotifier::AddObserver(this);
+ ResetConfigService(config_service);
}
// static
@@ -319,8 +325,8 @@ ProxyService* ProxyService::CreateFixed(const ProxyConfig& pc) {
// static
ProxyService* ProxyService::CreateNull() {
- // Use a configuration fetcher and proxy resolver which always fail.
- return new ProxyService(new ProxyConfigServiceNull, new ProxyResolverNull,
+ // Use direct connections.
+ return new ProxyService(new ProxyConfigServiceDirect, new ProxyResolverNull,
NULL);
}
@@ -333,13 +339,16 @@ int ProxyService::ResolveProxy(const GURL& raw_url,
net_log.BeginEvent(NetLog::TYPE_PROXY_SERVICE, NULL);
+ config_service_->OnLazyPoll();
+ if (current_state_ == STATE_NONE)
+ ApplyProxyConfigIfAvailable();
+
// Strip away any reference fragments and the username/password, as they
// are not relevant to proxy resolution.
GURL url = SimplifyUrlForRequest(raw_url);
- // 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(net_log);
+ // Check if the request can be completed right away. (This is the case when
+ // using a direct connection for example).
int rv = TryToCompleteSynchronously(url, result);
if (rv != ERR_IO_PENDING)
return DidFinishResolvingProxy(result, rv, net_log);
@@ -347,9 +356,7 @@ int ProxyService::ResolveProxy(const GURL& raw_url,
scoped_refptr<PacRequest> req =
new PacRequest(this, url, result, callback, net_log);
- bool resolver_is_ready = !IsInitializingProxyResolver();
-
- if (resolver_is_ready) {
+ if (current_state_ == STATE_READY) {
// Start the resolve request.
rv = req->Start();
if (rv != ERR_IO_PENDING)
@@ -372,22 +379,24 @@ int ProxyService::ResolveProxy(const GURL& raw_url,
int ProxyService::TryToCompleteSynchronously(const GURL& url,
ProxyInfo* result) {
- result->config_id_ = config_.id();
+ DCHECK_NE(STATE_NONE, current_state_);
- DCHECK(config_.id() != ProxyConfig::INVALID_ID);
+ if (current_state_ != STATE_READY)
+ return ERR_IO_PENDING; // Still initializing.
- if (should_use_proxy_resolver_ || IsInitializingProxyResolver()) {
- // May need to go through ProxyResolver for this.
- return ERR_IO_PENDING;
- }
+ if (should_use_proxy_resolver_)
+ return ERR_IO_PENDING; // Must submit the request to the proxy resolver.
// Use the manual proxy settings.
+ DCHECK(config_.id() != ProxyConfig::INVALID_ID);
config_.proxy_rules().Apply(url, result);
+ result->config_id_ = config_.id();
return OK;
}
ProxyService::~ProxyService() {
NetworkChangeNotifier::RemoveObserver(this);
+ config_service_->RemoveObserver(this);
// Cancel any inprogress requests.
for (PendingRequests::iterator it = pending_requests_.begin();
@@ -395,10 +404,6 @@ ProxyService::~ProxyService() {
++it) {
(*it)->Cancel();
}
-
- // Make sure that InitProxyResolver gets destroyed BEFORE the
- // CapturingNetLog it is using is deleted.
- init_proxy_resolver_.reset();
}
void ProxyService::SuspendAllPendingRequests() {
@@ -415,8 +420,9 @@ void ProxyService::SuspendAllPendingRequests() {
}
}
-void ProxyService::ResumeAllPendingRequests() {
- DCHECK(!IsInitializingProxyResolver());
+void ProxyService::SetReady() {
+ DCHECK(!init_proxy_resolver_.get());
+ current_state_ = STATE_READY;
// Make a copy in case |this| is deleted during the synchronous completion
// of one of the requests. If |this| is deleted then all of the PacRequest
@@ -438,7 +444,24 @@ void ProxyService::ResumeAllPendingRequests() {
}
}
+void ProxyService::ApplyProxyConfigIfAvailable() {
+ DCHECK_EQ(STATE_NONE, current_state_);
+
+ current_state_ = STATE_WAITING_FOR_PROXY_CONFIG;
+
+ config_service_->OnLazyPoll();
+
+ // Retrieve the current proxy configuration from the ProxyConfigService.
+ // If a configuration is not available yet, we will get called back later
+ // by our ProxyConfigService::Observer once it changes.
+ ProxyConfig config;
+ bool has_config = config_service_->GetLatestProxyConfig(&config);
+ if (has_config)
+ OnProxyConfigChanged(config);
+}
+
void ProxyService::OnInitProxyResolverComplete(int result) {
+ DCHECK_EQ(STATE_WAITING_FOR_INIT_PROXY_RESOLVER, current_state_);
DCHECK(init_proxy_resolver_.get());
DCHECK(config_.MayRequirePACResolver());
DCHECK(!should_use_proxy_resolver_);
@@ -453,7 +476,7 @@ void ProxyService::OnInitProxyResolverComplete(int result) {
// Resume any requests which we had to defer until the PAC script was
// downloaded.
- ResumeAllPendingRequests();
+ SetReady();
}
int ProxyService::ReconsiderProxyAfterError(const GURL& url,
@@ -466,13 +489,7 @@ int ProxyService::ReconsiderProxyAfterError(const GURL& url,
// direct connection failed and we never tried the current config.
bool re_resolve = result->config_id_ != config_.id();
- if (!re_resolve) {
- UpdateConfig(net_log);
- if (result->config_id_ != config_.id()) {
- // A new configuration!
- 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.
@@ -542,29 +559,43 @@ int ProxyService::DidFinishResolvingProxy(ProxyInfo* result,
void ProxyService::SetProxyScriptFetcher(
ProxyScriptFetcher* proxy_script_fetcher) {
- if (init_proxy_resolver_.get()) {
- // We need to be careful to first cancel |init_proxy_resolver_|, since it
- // holds a pointer to the old proxy script fetcher we are about to delete.
-
- DCHECK(IsInitializingProxyResolver());
- init_proxy_resolver_.reset();
- proxy_script_fetcher_.reset(proxy_script_fetcher);
-
- // Restart the initialization, using the new proxy script fetcher.
- StartInitProxyResolver();
- } else {
- proxy_script_fetcher_.reset(proxy_script_fetcher);
- }
+ State previous_state = ResetProxyConfig();
+ proxy_script_fetcher_.reset(proxy_script_fetcher);
+ if (previous_state != STATE_NONE)
+ ApplyProxyConfigIfAvailable();
}
ProxyScriptFetcher* ProxyService::GetProxyScriptFetcher() const {
return proxy_script_fetcher_.get();
}
+ProxyService::State ProxyService::ResetProxyConfig() {
+ State previous_state = current_state_;
+
+ proxy_retry_info_.clear();
+ init_proxy_resolver_.reset();
+ should_use_proxy_resolver_ = false;
+ SuspendAllPendingRequests();
+ config_ = ProxyConfig();
+ current_state_ = STATE_NONE;
+
+ return previous_state;
+}
+
void ProxyService::ResetConfigService(
ProxyConfigService* new_proxy_config_service) {
+ State previous_state = ResetProxyConfig();
+
+ // Release the old configuration service.
+ if (config_service_.get())
+ config_service_->RemoveObserver(this);
+
+ // Set the new configuration service.
config_service_.reset(new_proxy_config_service);
- UpdateConfig(BoundNetLog());
+ config_service_->AddObserver(this);
+
+ if (previous_state != STATE_NONE)
+ ApplyProxyConfigIfAvailable();
}
void ProxyService::PurgeMemory() {
@@ -573,11 +604,8 @@ void ProxyService::PurgeMemory() {
}
void ProxyService::ForceReloadProxyConfig() {
- // Mark the current configuration as being un-initialized, then force it to
- // start updating (normally this would happen lazily during the next
- // call to ResolveProxy()).
- config_.set_id(ProxyConfig::INVALID_ID);
- UpdateConfig(BoundNetLog());
+ ResetProxyConfig();
+ ApplyProxyConfigIfAvailable();
}
// static
@@ -614,74 +642,20 @@ ProxyConfigService* ProxyService::CreateSystemProxyConfigService(
#endif
}
-void ProxyService::UpdateConfig(const BoundNetLog& net_log) {
- bool is_first_update = !config_has_been_initialized();
-
- ProxyConfig latest;
-
- // Fetch the proxy settings.
- TimeTicks start_time = TimeTicks::Now();
- net_log.BeginEvent(
- NetLog::TYPE_PROXY_SERVICE_POLL_CONFIG_SERVICE_FOR_CHANGES, NULL);
- int rv = config_service_->GetProxyConfig(&latest);
- net_log.EndEvent(NetLog::TYPE_PROXY_SERVICE_POLL_CONFIG_SERVICE_FOR_CHANGES,
- NULL);
- TimeTicks end_time = TimeTicks::Now();
-
- // Record how long the call to config_service_->GetConfig() above took.
- // On some setups of Windows, we have reports that querying the system
- // proxy settings can take multiple seconds (http://crbug.com/12189).
- UMA_HISTOGRAM_CUSTOM_TIMES("Net.ProxyPollConfigurationTime",
- end_time - start_time,
- TimeDelta::FromMilliseconds(1),
- TimeDelta::FromSeconds(30),
- 50);
-
- if (rv != OK) {
- if (is_first_update) {
- // Default to direct-connection if the first fetch fails.
- LOG(INFO) << "Failed initial proxy configuration fetch.";
- SetConfig(ProxyConfig());
- }
- return;
- }
- config_last_update_time_ = TimeTicks::Now();
-
- if (!is_first_update && latest.Equals(config_))
- return;
-
- SetConfig(latest);
-}
-
-void ProxyService::SetConfig(const ProxyConfig& config) {
- config_ = config;
+void ProxyService::OnProxyConfigChanged(const ProxyConfig& config) {
+ ResetProxyConfig();
// Increment the ID to reflect that the config has changed.
+ config_ = config;
config_.set_id(next_config_id_++);
- // Reset state associated with latest config.
- proxy_retry_info_.clear();
-
- // Cancel any PAC fetching / ProxyResolver::SetPacScript() which was
- // in progress for the previous configuration.
- init_proxy_resolver_.reset();
- should_use_proxy_resolver_ = false;
-
- // Start downloading + testing the PAC scripts for this new configuration.
- if (config_.MayRequirePACResolver()) {
- // Since InitProxyResolver will be playing around with the proxy resolver
- // as it tests the parsing of various PAC scripts, make sure there is
- // nothing in-flight in |resolver_|. These paused requests are resumed by
- // OnInitProxyResolverComplete().
- SuspendAllPendingRequests();
-
- // Calls OnInitProxyResolverComplete() on completion.
- StartInitProxyResolver();
+ if (!config_.MayRequirePACResolver()) {
+ SetReady();
+ return;
}
-}
-void ProxyService::StartInitProxyResolver() {
- DCHECK(!init_proxy_resolver_.get());
+ // Start downloading + testing the PAC scripts for this new configuration.
+ current_state_ = STATE_WAITING_FOR_INIT_PROXY_RESOLVER;
init_proxy_resolver_.reset(
new InitProxyResolver(resolver_.get(), proxy_script_fetcher_.get(),
@@ -694,24 +668,10 @@ void ProxyService::StartInitProxyResolver() {
OnInitProxyResolverComplete(rv);
}
-void ProxyService::UpdateConfigIfOld(const BoundNetLog& net_log) {
- // 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(net_log);
-}
-
-
void ProxyService::OnIPAddressChanged() {
- // Mark the current configuration as being un-initialized.
- //
- // This will force us to re-fetch the configuration (and re-run all of
- // the initialization steps) on the next ResolveProxy() request, as part
- // of UpdateConfigIfOld().
- config_.set_id(ProxyConfig::INVALID_ID);
+ State previous_state = ResetProxyConfig();
+ if (previous_state != STATE_NONE)
+ ApplyProxyConfigIfAvailable();
}
SyncProxyServiceHelper::SyncProxyServiceHelper(MessageLoop* io_message_loop,
diff --git a/net/proxy/proxy_service.h b/net/proxy/proxy_service.h
index a702b38..d3699cd 100644
--- a/net/proxy/proxy_service.h
+++ b/net/proxy/proxy_service.h
@@ -14,6 +14,7 @@
#include "net/base/completion_callback.h"
#include "net/base/network_change_notifier.h"
#include "net/base/net_log.h"
+#include "net/proxy/proxy_config_service.h"
#include "net/proxy/proxy_server.h"
#include "net/proxy/proxy_info.h"
#include "testing/gtest/include/gtest/gtest_prod.h"
@@ -25,7 +26,6 @@ class URLRequestContext;
namespace net {
class InitProxyResolver;
-class ProxyConfigService;
class ProxyResolver;
class ProxyScriptFetcher;
@@ -33,7 +33,8 @@ class ProxyScriptFetcher;
// HTTP(S) URL. It uses the given ProxyResolver to handle the actual proxy
// resolution. See ProxyResolverV8 for example.
class ProxyService : public base::RefCountedThreadSafe<ProxyService>,
- public NetworkChangeNotifier::Observer {
+ public NetworkChangeNotifier::Observer,
+ public ProxyConfigService::Observer {
public:
// The instance takes ownership of |config_service| and |resolver|.
// |net_log| is a possibly NULL destination to send log events to. It must
@@ -196,31 +197,23 @@ class ProxyService : public base::RefCountedThreadSafe<ProxyService>,
// which expects requests to finish in the order they were added.
typedef std::vector<scoped_refptr<PacRequest> > PendingRequests;
- ~ProxyService();
-
- // Identifies the proxy configuration.
- ProxyConfig::ID config_id() const { return config_.id(); }
-
- // Checks to see if the proxy configuration changed, and then updates config_
- // to reference the new configuration.
- void UpdateConfig(const BoundNetLog& net_log);
-
- // Assign |config| as the current configuration.
- void SetConfig(const ProxyConfig& config);
+ enum State {
+ STATE_NONE,
+ STATE_WAITING_FOR_PROXY_CONFIG,
+ STATE_WAITING_FOR_INIT_PROXY_RESOLVER,
+ STATE_READY,
+ };
- // Starts downloading and testing the various PAC choices.
- // Calls OnInitProxyResolverComplete() when completed.
- void StartInitProxyResolver();
+ ~ProxyService();
- // Tries to update the configuration if it hasn't been checked in a while.
- void UpdateConfigIfOld(const BoundNetLog& net_log);
+ // Resets all the variables associated with the current proxy configuration,
+ // and rewinds the current state to |STATE_NONE|. Returns the previous value
+ // of |current_state_|.
+ State ResetProxyConfig();
- // Returns true if the proxy resolver is being initialized for PAC
- // (downloading PAC script(s) + testing).
- // Resolve requests will be frozen until the initialization has completed.
- bool IsInitializingProxyResolver() const {
- return init_proxy_resolver_.get() != NULL;
- }
+ // Retrieves the current proxy configuration from the ProxyConfigService, and
+ // starts initializing for it.
+ void ApplyProxyConfigIfAvailable();
// Callback for when the proxy resolver has been initialized with a
// PAC script.
@@ -235,8 +228,9 @@ class ProxyService : public base::RefCountedThreadSafe<ProxyService>,
// restarted when calling ResumeAllPendingRequests().
void SuspendAllPendingRequests();
- // Sends all the unstarted pending requests off to the resolver.
- void ResumeAllPendingRequests();
+ // Advances the current state to |STATE_READY|, and resumes any pending
+ // requests which had been stalled waiting for initialization to complete.
+ void SetReady();
// Returns true if |pending_requests_| contains |req|.
bool ContainsPendingRequest(PacRequest* req);
@@ -255,6 +249,9 @@ class ProxyService : public base::RefCountedThreadSafe<ProxyService>,
// When this is called, we re-fetch PAC scripts and re-run WPAD.
virtual void OnIPAddressChanged();
+ // ProxyConfigService::Observer
+ virtual void OnProxyConfigChanged(const ProxyConfig& config);
+
scoped_ptr<ProxyConfigService> config_service_;
scoped_ptr<ProxyResolver> resolver_;
@@ -291,6 +288,8 @@ class ProxyService : public base::RefCountedThreadSafe<ProxyService>,
// |proxy_resolver_| must outlive |init_proxy_resolver_|.
scoped_ptr<InitProxyResolver> init_proxy_resolver_;
+ State current_state_;
+
// This is the log where any events generated by |init_proxy_resolver_| are
// sent to.
NetLog* net_log_;
diff --git a/net/proxy/proxy_service_unittest.cc b/net/proxy/proxy_service_unittest.cc
index a69b66e..bc5f74e 100644
--- a/net/proxy/proxy_service_unittest.cc
+++ b/net/proxy/proxy_service_unittest.cc
@@ -27,18 +27,41 @@ namespace {
class MockProxyConfigService: public ProxyConfigService {
public:
- MockProxyConfigService() {} // Direct connect.
- explicit MockProxyConfigService(const ProxyConfig& pc) : config(pc) {}
- explicit MockProxyConfigService(const std::string& pac_url) {
- config.set_pac_url(GURL(pac_url));
+ explicit MockProxyConfigService(const ProxyConfig& config)
+ : has_config_(true), config_(config) {
}
- virtual int GetProxyConfig(ProxyConfig* results) {
- *results = config;
- return OK;
+ explicit MockProxyConfigService(const std::string& pac_url)
+ : has_config_(true),
+ config_(ProxyConfig::CreateFromCustomPacURL(GURL(pac_url))) {
}
- ProxyConfig config;
+ virtual void AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+ }
+
+ virtual void RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+ }
+
+ virtual bool GetLatestProxyConfig(ProxyConfig* results) {
+ if (has_config_) {
+ *results = config_;
+ return true;
+ }
+ return false;
+ }
+
+ void SetConfig(const ProxyConfig& config) {
+ has_config_ = true;
+ config_ = config;
+ FOR_EACH_OBSERVER(Observer, observers_, OnProxyConfigChanged(config));
+ }
+
+ private:
+ bool has_config_;
+ ProxyConfig config_;
+ ObserverList<Observer, true> observers_;
};
} // namespace
@@ -91,7 +114,8 @@ class MockProxyScriptFetcher : public ProxyScriptFetcher {
TEST(ProxyServiceTest, Direct) {
MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
scoped_refptr<ProxyService> service(
- new ProxyService(new MockProxyConfigService, resolver, NULL));
+ new ProxyService(new MockProxyConfigService(
+ ProxyConfig::CreateDirect()), resolver, NULL));
GURL url("http://www.google.com/");
@@ -105,11 +129,14 @@ TEST(ProxyServiceTest, Direct) {
EXPECT_TRUE(info.is_direct());
// Check the NetLog was filled correctly.
- EXPECT_EQ(5u, log.entries().size());
+ EXPECT_EQ(3u, log.entries().size());
EXPECT_TRUE(LogContainsBeginEvent(
log.entries(), 0, NetLog::TYPE_PROXY_SERVICE));
+ EXPECT_TRUE(LogContainsEvent(
+ log.entries(), 1, NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST,
+ NetLog::PHASE_NONE));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 4, NetLog::TYPE_PROXY_SERVICE));
+ log.entries(), 2, NetLog::TYPE_PROXY_SERVICE));
}
TEST(ProxyServiceTest, PAC) {
@@ -146,15 +173,15 @@ TEST(ProxyServiceTest, PAC) {
EXPECT_EQ("foopy:80", info.proxy_server().ToURI());
// Check the NetLog was filled correctly.
- EXPECT_EQ(7u, log.entries().size());
+ EXPECT_EQ(5u, log.entries().size());
EXPECT_TRUE(LogContainsBeginEvent(
log.entries(), 0, NetLog::TYPE_PROXY_SERVICE));
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 3, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
+ log.entries(), 1, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 4, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
+ log.entries(), 2, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 6, NetLog::TYPE_PROXY_SERVICE));
+ log.entries(), 4, NetLog::TYPE_PROXY_SERVICE));
}
// Test that the proxy resolver does not see the URL's username/password
@@ -552,8 +579,8 @@ TEST(ProxyServiceTest, ProxyFallback_NewSettings) {
EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
// Fake an error on the proxy, and also a new configuration on the proxy.
- config_service->config = ProxyConfig();
- config_service->config.set_pac_url(GURL("http://foopy-new/proxy.pac"));
+ config_service->SetConfig(
+ ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy-new/proxy.pac")));
TestCompletionCallback callback2;
rv = service->ReconsiderProxyAfterError(url, &info, &callback2, NULL,
@@ -583,8 +610,9 @@ TEST(ProxyServiceTest, ProxyFallback_NewSettings) {
EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
// We simulate a new configuration.
- config_service->config = ProxyConfig();
- config_service->config.set_pac_url(GURL("http://foopy-new2/proxy.pac"));
+ config_service->SetConfig(
+ ProxyConfig::CreateFromCustomPacURL(
+ GURL("http://foopy-new2/proxy.pac")));
// We fake another error. It should go back to the first proxy.
TestCompletionCallback callback4;
@@ -1121,17 +1149,17 @@ TEST(ProxyServiceTest, CancelWhilePACFetching) {
EXPECT_FALSE(callback2.have_result()); // Cancelled.
// Check the NetLog for request 1 (which was cancelled) got filled properly.
- EXPECT_EQ(6u, log1.entries().size());
+ EXPECT_EQ(4u, log1.entries().size());
EXPECT_TRUE(LogContainsBeginEvent(
log1.entries(), 0, NetLog::TYPE_PROXY_SERVICE));
EXPECT_TRUE(LogContainsBeginEvent(
- log1.entries(), 3, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
+ log1.entries(), 1, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
// Note that TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC is never completed before
// the cancellation occured.
EXPECT_TRUE(LogContainsEvent(
- log1.entries(), 4, NetLog::TYPE_CANCELLED, NetLog::PHASE_NONE));
+ log1.entries(), 2, NetLog::TYPE_CANCELLED, NetLog::PHASE_NONE));
EXPECT_TRUE(LogContainsEndEvent(
- log1.entries(), 5, NetLog::TYPE_PROXY_SERVICE));
+ log1.entries(), 3, NetLog::TYPE_PROXY_SERVICE));
}
// Test that if auto-detect fails, we fall-back to the custom pac.
@@ -1411,8 +1439,8 @@ TEST(ProxyServiceTest, BypassDoesntApplyToPac) {
// have any memory errors (used to be that the ProxyScriptFetcher was
// being deleted prior to the InitProxyResolver).
TEST(ProxyServiceTest, DeleteWhileInitProxyResolverHasOutstandingFetch) {
- ProxyConfig config;
- config.set_pac_url(GURL("http://foopy/proxy.pac"));
+ ProxyConfig config =
+ ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac"));
MockProxyConfigService* config_service = new MockProxyConfigService(config);
MockAsyncProxyResolverExpectsBytes* resolver =
@@ -1496,61 +1524,10 @@ TEST(ProxyServiceTest, ResetProxyConfigService) {
EXPECT_EQ("foopy2:8080", info.proxy_server().ToURI());
}
-// Check that after we have done the auto-detect test, and the configuration
-// is updated (with no change), we don't re-try the autodetect test.
-// Regression test for http://crbug.com/18526 -- the configuration was being
-// mutated to cancel out the automatic settings, which meant UpdateConfig()
-// thought it had received a new configuration.
-TEST(ProxyServiceTest, UpdateConfigAfterFailedAutodetect) {
- ProxyConfig config;
- config.set_auto_detect(true);
-
- MockProxyConfigService* config_service = new MockProxyConfigService(config);
- MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
- scoped_refptr<ProxyService> service(
- new ProxyService(config_service, resolver, NULL));
-
- // Start 1 requests.
-
- ProxyInfo info1;
- TestCompletionCallback callback1;
- int rv = service->ResolveProxy(
- GURL("http://www.google.com"), &info1, &callback1, NULL, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- // Check that nothing has been sent to the proxy resolver yet.
- ASSERT_EQ(0u, resolver->pending_requests().size());
-
- // Fail the setting of autodetect script.
- EXPECT_EQ(ProxyResolverScriptData::TYPE_AUTO_DETECT,
- resolver->pending_set_pac_script_request()->script_data()->type());
- resolver->pending_set_pac_script_request()->CompleteNow(ERR_FAILED);
-
- // Verify that request ran as expected -- should have fallen back to direct.
- EXPECT_EQ(OK, callback1.WaitForResult());
- EXPECT_TRUE(info1.is_direct());
-
- // Force the ProxyService to pull down a new proxy configuration.
- // (Even though the configuration isn't old/bad).
- service->UpdateConfig(BoundNetLog());
-
- // Start another request -- the effective configuration has not
- // changed, so we shouldn't re-run the autodetect step.
- // Rather, it should complete synchronously as direct-connect.
- ProxyInfo info2;
- TestCompletionCallback callback2;
- rv = service->ResolveProxy(
- GURL("http://www.google.com"), &info2, &callback2, NULL, BoundNetLog());
- EXPECT_EQ(OK, rv);
-
- EXPECT_TRUE(info2.is_direct());
-}
-
// Test that when going from a configuration that required PAC to one
// that does NOT, we unset the variable |should_use_proxy_resolver_|.
TEST(ProxyServiceTest, UpdateConfigFromPACToDirect) {
- ProxyConfig config;
- config.set_auto_detect(true);
+ ProxyConfig config = ProxyConfig::CreateAutoDetect();
MockProxyConfigService* config_service = new MockProxyConfigService(config);
MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
@@ -1587,9 +1564,7 @@ TEST(ProxyServiceTest, UpdateConfigFromPACToDirect) {
//
// This new configuration no longer has auto_detect set, so
// requests should complete synchronously now as direct-connect.
- config.set_auto_detect(false);
- config_service->config = config;
- service->UpdateConfig(BoundNetLog());
+ config_service->SetConfig(ProxyConfig::CreateDirect());
// Start another request -- the effective configuration has changed.
ProxyInfo info2;