summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/android/pylib/gtest/test_runner.py1
-rw-r--r--chrome/browser/net/connection_tester.cc1
-rw-r--r--chrome/browser/net/proxy_service_factory.cc1
-rw-r--r--net/base/capturing_net_log.cc15
-rw-r--r--net/base/capturing_net_log.h4
-rw-r--r--net/base/mock_host_resolver.cc10
-rw-r--r--net/base/mock_host_resolver.h20
-rw-r--r--net/data/proxy_resolver_v8_tracing_unittest/dns.js31
-rw-r--r--net/data/proxy_resolver_v8_tracing_unittest/dns_during_init.js14
-rw-r--r--net/data/proxy_resolver_v8_tracing_unittest/error.js8
-rw-r--r--net/data/proxy_resolver_v8_tracing_unittest/global_sideffects1.js14
-rw-r--r--net/data/proxy_resolver_v8_tracing_unittest/global_sideffects2.js18
-rw-r--r--net/data/proxy_resolver_v8_tracing_unittest/global_sideffects3.js13
-rw-r--r--net/data/proxy_resolver_v8_tracing_unittest/global_sideffects4.js15
-rw-r--r--net/data/proxy_resolver_v8_tracing_unittest/simple.js3
-rw-r--r--net/data/proxy_resolver_v8_tracing_unittest/simple_dns.js8
-rw-r--r--net/data/proxy_resolver_v8_tracing_unittest/too_many_alerts.js13
-rw-r--r--net/data/proxy_resolver_v8_tracing_unittest/too_many_empty_alerts.js13
-rw-r--r--net/http/http_network_transaction_spdy2_unittest.cc6
-rw-r--r--net/http/http_network_transaction_spdy3_unittest.cc6
-rw-r--r--net/net.gyp12
-rw-r--r--net/net_unittests.isolate11
-rw-r--r--net/proxy/mock_proxy_resolver.cc6
-rw-r--r--net/proxy/mock_proxy_resolver.h2
-rw-r--r--net/proxy/multi_threaded_proxy_resolver.cc15
-rw-r--r--net/proxy/multi_threaded_proxy_resolver.h2
-rw-r--r--net/proxy/multi_threaded_proxy_resolver_unittest.cc12
-rw-r--r--net/proxy/proxy_resolver.h7
-rw-r--r--net/proxy/proxy_resolver_error_observer.h10
-rw-r--r--net/proxy/proxy_resolver_js_bindings.cc291
-rw-r--r--net/proxy/proxy_resolver_js_bindings.h92
-rw-r--r--net/proxy/proxy_resolver_js_bindings_unittest.cc365
-rw-r--r--net/proxy/proxy_resolver_mac.cc5
-rw-r--r--net/proxy/proxy_resolver_mac.h3
-rw-r--r--net/proxy/proxy_resolver_perftest.cc41
-rw-r--r--net/proxy/proxy_resolver_request_context.h31
-rw-r--r--net/proxy/proxy_resolver_v8.cc121
-rw-r--r--net/proxy/proxy_resolver_v8.h47
-rw-r--r--net/proxy/proxy_resolver_v8_tracing.cc984
-rw-r--r--net/proxy/proxy_resolver_v8_tracing.h85
-rw-r--r--net/proxy/proxy_resolver_v8_tracing_unittest.cc928
-rw-r--r--net/proxy/proxy_resolver_v8_unittest.cc64
-rw-r--r--net/proxy/proxy_resolver_winhttp.cc5
-rw-r--r--net/proxy/proxy_resolver_winhttp.h3
-rw-r--r--net/proxy/proxy_service.cc13
-rw-r--r--net/proxy/proxy_service_v8.cc72
-rw-r--r--net/proxy/proxy_service_v8.h16
-rw-r--r--net/proxy/sync_host_resolver.h31
-rw-r--r--net/proxy/sync_host_resolver_bridge.cc177
-rw-r--r--net/proxy/sync_host_resolver_bridge.h45
-rw-r--r--net/proxy/sync_host_resolver_bridge_unittest.cc244
51 files changed, 2342 insertions, 1612 deletions
diff --git a/build/android/pylib/gtest/test_runner.py b/build/android/pylib/gtest/test_runner.py
index 9947ab4..6799f5a 100644
--- a/build/android/pylib/gtest/test_runner.py
+++ b/build/android/pylib/gtest/test_runner.py
@@ -174,6 +174,7 @@ class SingleTestRunner(BaseTestRunner):
'net/data/cache_tests',
'net/data/filter_unittests',
'net/data/ftp',
+ 'net/data/proxy_resolver_v8_tracing_unittest',
'net/data/proxy_resolver_v8_unittest',
'net/data/ssl/certificates',
'net/data/url_request_unittest/',
diff --git a/chrome/browser/net/connection_tester.cc b/chrome/browser/net/connection_tester.cc
index f5e892b..5707a5d 100644
--- a/chrome/browser/net/connection_tester.cc
+++ b/chrome/browser/net/connection_tester.cc
@@ -206,7 +206,6 @@ class ExperimentURLRequestContext : public net::URLRequestContext {
experiment_proxy_service->reset(
net::CreateProxyServiceUsingV8ProxyResolver(
proxy_config_service->release(),
- 0u,
new net::ProxyScriptFetcherImpl(proxy_request_context_),
dhcp_factory.Create(proxy_request_context_),
host_resolver(),
diff --git a/chrome/browser/net/proxy_service_factory.cc b/chrome/browser/net/proxy_service_factory.cc
index cff40af..0dd312a 100644
--- a/chrome/browser/net/proxy_service_factory.cc
+++ b/chrome/browser/net/proxy_service_factory.cc
@@ -117,7 +117,6 @@ net::ProxyService* ProxyServiceFactory::CreateProxyService(
proxy_service = net::CreateProxyServiceUsingV8ProxyResolver(
proxy_config_service,
- num_pac_threads,
new net::ProxyScriptFetcherImpl(context),
dhcp_factory.Create(context),
context->host_resolver(),
diff --git a/net/base/capturing_net_log.cc b/net/base/capturing_net_log.cc
index eb7f9e5..0ffdfb7 100644
--- a/net/base/capturing_net_log.cc
+++ b/net/base/capturing_net_log.cc
@@ -4,6 +4,7 @@
#include "net/base/capturing_net_log.h"
+#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/values.h"
@@ -34,14 +35,14 @@ CapturingNetLog::CapturedEntry::operator=(const CapturedEntry& entry) {
time = entry.time;
source = entry.source;
phase = entry.phase;
- params.reset(entry.params.get() ? entry.params->DeepCopy() : NULL);
+ params.reset(entry.params ? entry.params->DeepCopy() : NULL);
return *this;
}
bool CapturingNetLog::CapturedEntry::GetStringValue(
const std::string& name,
std::string* value) const {
- if (!params.get())
+ if (!params)
return false;
return params->GetString(name, value);
}
@@ -49,7 +50,7 @@ bool CapturingNetLog::CapturedEntry::GetStringValue(
bool CapturingNetLog::CapturedEntry::GetIntegerValue(
const std::string& name,
int* value) const {
- if (!params.get())
+ if (!params)
return false;
return params->GetInteger(name, value);
}
@@ -58,6 +59,14 @@ bool CapturingNetLog::CapturedEntry::GetNetErrorCode(int* value) const {
return GetIntegerValue("net_error", value);
}
+std::string CapturingNetLog::CapturedEntry::GetParamsJson() const {
+ if (!params)
+ return std::string();
+ std::string json;
+ base::JSONWriter::Write(params.get(), &json);
+ return json;
+}
+
CapturingNetLog::CapturingNetLog()
: last_id_(0),
log_level_(LOG_ALL_BUT_BYTES) {
diff --git a/net/base/capturing_net_log.h b/net/base/capturing_net_log.h
index 413be527..ec78a3f 100644
--- a/net/base/capturing_net_log.h
+++ b/net/base/capturing_net_log.h
@@ -54,6 +54,10 @@ class CapturingNetLog : public NetLog {
// log entry.
bool GetNetErrorCode(int* value) const;
+ // Returns the parameters as a JSON string, or empty string if there are no
+ // parameters.
+ std::string GetParamsJson() const;
+
EventType type;
base::TimeTicks time;
Source source;
diff --git a/net/base/mock_host_resolver.cc b/net/base/mock_host_resolver.cc
index a0835b8..1bfd1ba 100644
--- a/net/base/mock_host_resolver.cc
+++ b/net/base/mock_host_resolver.cc
@@ -71,6 +71,7 @@ int MockHostResolverBase::Resolve(const RequestInfo& info,
RequestHandle* handle,
const BoundNetLog& net_log) {
DCHECK(CalledOnValidThread());
+ num_resolve_++;
size_t id = next_request_id_++;
int rv = ResolveFromIPLiteralOrCache(info, addresses);
if (rv != ERR_DNS_CACHE_MISS) {
@@ -97,6 +98,7 @@ int MockHostResolverBase::Resolve(const RequestInfo& info,
int MockHostResolverBase::ResolveFromCache(const RequestInfo& info,
AddressList* addresses,
const BoundNetLog& net_log) {
+ num_resolve_from_cache_++;
DCHECK(CalledOnValidThread());
next_request_id_++;
int rv = ResolveFromIPLiteralOrCache(info, addresses);
@@ -134,7 +136,9 @@ void MockHostResolverBase::ResolveAllPending() {
MockHostResolverBase::MockHostResolverBase(bool use_caching)
: synchronous_mode_(false),
ondemand_mode_(false),
- next_request_id_(1) {
+ next_request_id_(1),
+ num_resolve_(0),
+ num_resolve_from_cache_(0) {
rules_ = CreateCatchAllHostResolverProc();
if (use_caching) {
@@ -305,6 +309,10 @@ void RuleBasedHostResolverProc::AddSimulatedFailure(
rules_.push_back(rule);
}
+void RuleBasedHostResolverProc::ClearRules() {
+ rules_.clear();
+}
+
int RuleBasedHostResolverProc::Resolve(const std::string& host,
AddressFamily address_family,
HostResolverFlags host_resolver_flags,
diff --git a/net/base/mock_host_resolver.h b/net/base/mock_host_resolver.h
index 5542a64..ee6f1b5 100644
--- a/net/base/mock_host_resolver.h
+++ b/net/base/mock_host_resolver.h
@@ -94,6 +94,16 @@ class MockHostResolverBase : public HostResolver,
// ResolveAllPending().
bool has_pending_requests() const { return !requests_.empty(); }
+ // The number of times that Resolve() has been called.
+ size_t num_resolve() const {
+ return num_resolve_;
+ }
+
+ // The number of times that ResolveFromCache() has been called.
+ size_t num_resolve_from_cache() const {
+ return num_resolve_from_cache_;
+ }
+
protected:
explicit MockHostResolverBase(bool use_caching);
@@ -117,6 +127,9 @@ class MockHostResolverBase : public HostResolver,
RequestMap requests_;
size_t next_request_id_;
+ size_t num_resolve_;
+ size_t num_resolve_from_cache_;
+
DISALLOW_COPY_AND_ASSIGN(MockHostResolverBase);
};
@@ -158,8 +171,10 @@ class RuleBasedHostResolverProc : public HostResolverProc {
// Same as AddRule(), but the replacement is expected to be an IPv4 or IPv6
// literal. This can be used in place of AddRule() to bypass the system's
// host resolver (the address list will be constructed manually).
- // If |canonical-name| is non-empty, it is copied to the resulting AddressList
+ // If |canonical_name| is non-empty, it is copied to the resulting AddressList
// but does not impact DNS resolution.
+ // |ip_literal| can be a single IP address like "192.168.1.1" or a comma
+ // separated list of IP addresses, like "::1,192:168.1.2".
void AddIPLiteralRule(const std::string& host_pattern,
const std::string& ip_literal,
const std::string& canonical_name);
@@ -175,6 +190,9 @@ class RuleBasedHostResolverProc : public HostResolverProc {
// Simulate a lookup failure for |host| (it also can be a pattern).
void AddSimulatedFailure(const std::string& host);
+ // Deletes all the rules that have been added.
+ void ClearRules();
+
// HostResolverProc methods:
virtual int Resolve(const std::string& host,
AddressFamily address_family,
diff --git a/net/data/proxy_resolver_v8_tracing_unittest/dns.js b/net/data/proxy_resolver_v8_tracing_unittest/dns.js
new file mode 100644
index 0000000..fbfb74e
--- /dev/null
+++ b/net/data/proxy_resolver_v8_tracing_unittest/dns.js
@@ -0,0 +1,31 @@
+var g_iteration = 0;
+
+function FindProxyForURL(url, host) {
+ alert('iteration: ' + g_iteration++);
+
+ var ips = [
+ myIpAddress(),
+ dnsResolve(''),
+ dnsResolveEx('host1'),
+ dnsResolve('host2'),
+ dnsResolve('host3'),
+ myIpAddress(),
+ dnsResolve('host3'),
+ dnsResolveEx('host1'),
+ myIpAddress(),
+ dnsResolve('host2'),
+ dnsResolveEx('host6'),
+ myIpAddressEx(),
+ dnsResolve('host1'),
+ ];
+
+ for (var i = 0; i < ips.length; ++i) {
+ // Stringize everything.
+ ips[i] = '' + ips[i];
+ }
+
+ var proxyHost = ips.join('-');
+ proxyHost = proxyHost.replace(/[^0-9a-zA-Z.-]/g, '_');
+
+ return "PROXY " + proxyHost + ":99";
+}
diff --git a/net/data/proxy_resolver_v8_tracing_unittest/dns_during_init.js b/net/data/proxy_resolver_v8_tracing_unittest/dns_during_init.js
new file mode 100644
index 0000000..55aef52
--- /dev/null
+++ b/net/data/proxy_resolver_v8_tracing_unittest/dns_during_init.js
@@ -0,0 +1,14 @@
+var g_ips = [
+ dnsResolve('host1'),
+ dnsResolve('host2')
+];
+
+alert('Watsup');
+alert('Watsup2');
+
+function FindProxyForURL(url, host) {
+ // Note that host1 and host2 should not resolve using the same cache as was
+ // used for g_ips!
+ var ips = g_ips.concat([dnsResolve('host1'), dnsResolve('host2')]);
+ return 'PROXY ' + ips.join('-') + ':99';
+}
diff --git a/net/data/proxy_resolver_v8_tracing_unittest/error.js b/net/data/proxy_resolver_v8_tracing_unittest/error.js
new file mode 100644
index 0000000..83e534c
--- /dev/null
+++ b/net/data/proxy_resolver_v8_tracing_unittest/error.js
@@ -0,0 +1,8 @@
+function FindProxyForURL(url, host) {
+ if (host == 'throw-an-error') {
+ alert('Prepare to DIE!');
+ var x = null;
+ return x.split('-'); // Throws exception.
+ }
+ return "PROXY i-approve-this-message:42";
+}
diff --git a/net/data/proxy_resolver_v8_tracing_unittest/global_sideffects1.js b/net/data/proxy_resolver_v8_tracing_unittest/global_sideffects1.js
new file mode 100644
index 0000000..251af9f
--- /dev/null
+++ b/net/data/proxy_resolver_v8_tracing_unittest/global_sideffects1.js
@@ -0,0 +1,14 @@
+var g_iteration = 0;
+
+function FindProxyForURL(url, host) {
+ g_iteration++;
+
+ var ips = [
+ dnsResolve('host1'),
+ dnsResolve('crazy' + g_iteration)
+ ];
+
+ alert('iteration: ' + g_iteration);
+
+ return 'PROXY ' + ips.join('-') + ':100';
+}
diff --git a/net/data/proxy_resolver_v8_tracing_unittest/global_sideffects2.js b/net/data/proxy_resolver_v8_tracing_unittest/global_sideffects2.js
new file mode 100644
index 0000000..f5e5076a
--- /dev/null
+++ b/net/data/proxy_resolver_v8_tracing_unittest/global_sideffects2.js
@@ -0,0 +1,18 @@
+var g_iteration = 0;
+
+function FindProxyForURL(url, host) {
+ g_iteration++;
+
+ var ips;
+
+ if (g_iteration < 3) {
+ ips = [
+ dnsResolve('host1'),
+ dnsResolve('host2')
+ ];
+ } else {
+ ips = [ dnsResolve('host' + g_iteration) ];
+ }
+
+ return 'PROXY ' + ips.join('-') + ':100';
+}
diff --git a/net/data/proxy_resolver_v8_tracing_unittest/global_sideffects3.js b/net/data/proxy_resolver_v8_tracing_unittest/global_sideffects3.js
new file mode 100644
index 0000000..0421126
--- /dev/null
+++ b/net/data/proxy_resolver_v8_tracing_unittest/global_sideffects3.js
@@ -0,0 +1,13 @@
+var g_iteration = 0;
+
+function FindProxyForURL(url, host) {
+ g_iteration++;
+
+ var results = [];
+ for (var i = 1; i <= g_iteration; ++i) {
+ results.push('' + dnsResolve('host' + i));
+ }
+
+ alert('iteration: ' + g_iteration);
+ return 'PROXY ' + results.join('-') + ':' + g_iteration;
+}
diff --git a/net/data/proxy_resolver_v8_tracing_unittest/global_sideffects4.js b/net/data/proxy_resolver_v8_tracing_unittest/global_sideffects4.js
new file mode 100644
index 0000000..1bfbbfd
--- /dev/null
+++ b/net/data/proxy_resolver_v8_tracing_unittest/global_sideffects4.js
@@ -0,0 +1,15 @@
+var g_iteration = 0;
+
+function FindProxyForURL(url, host) {
+ g_iteration++;
+
+ for (var i = 0; i < g_iteration; ++i) {
+ myIpAddress();
+ }
+
+ var result = '' + dnsResolve('host' + g_iteration);
+ result += g_iteration;
+
+ alert('iteration: ' + g_iteration);
+ return 'PROXY ' + result + ':34';
+}
diff --git a/net/data/proxy_resolver_v8_tracing_unittest/simple.js b/net/data/proxy_resolver_v8_tracing_unittest/simple.js
new file mode 100644
index 0000000..f742081
--- /dev/null
+++ b/net/data/proxy_resolver_v8_tracing_unittest/simple.js
@@ -0,0 +1,3 @@
+function FindProxyForURL(url, host) {
+ return "PROXY " + host + ":99";
+}
diff --git a/net/data/proxy_resolver_v8_tracing_unittest/simple_dns.js b/net/data/proxy_resolver_v8_tracing_unittest/simple_dns.js
new file mode 100644
index 0000000..24867b0
--- /dev/null
+++ b/net/data/proxy_resolver_v8_tracing_unittest/simple_dns.js
@@ -0,0 +1,8 @@
+var g_iteration = 0;
+
+function FindProxyForURL(url, host) {
+ g_iteration++;
+ myIpAddress();
+ var ip = dnsResolve(host);
+ return "PROXY " + ip + ':' + g_iteration;
+}
diff --git a/net/data/proxy_resolver_v8_tracing_unittest/too_many_alerts.js b/net/data/proxy_resolver_v8_tracing_unittest/too_many_alerts.js
new file mode 100644
index 0000000..564e30e
--- /dev/null
+++ b/net/data/proxy_resolver_v8_tracing_unittest/too_many_alerts.js
@@ -0,0 +1,13 @@
+var g_iteration = 0;
+
+function FindProxyForURL(url, host) {
+ g_iteration++;
+
+ dnsResolve(host);
+
+ for (var i = 0; i < 50; i++) {
+ alert('Gee, all these alerts are silly!');
+ }
+
+ return "PROXY foo:" + g_iteration;
+}
diff --git a/net/data/proxy_resolver_v8_tracing_unittest/too_many_empty_alerts.js b/net/data/proxy_resolver_v8_tracing_unittest/too_many_empty_alerts.js
new file mode 100644
index 0000000..6fe85d4
--- /dev/null
+++ b/net/data/proxy_resolver_v8_tracing_unittest/too_many_empty_alerts.js
@@ -0,0 +1,13 @@
+var g_iteration = 0;
+
+function FindProxyForURL(url, host) {
+ g_iteration++;
+
+ dnsResolve(host);
+
+ for (var i = 0; i < 1000; i++) {
+ alert('');
+ }
+
+ return "PROXY foo:" + g_iteration;
+}
diff --git a/net/http/http_network_transaction_spdy2_unittest.cc b/net/http/http_network_transaction_spdy2_unittest.cc
index dd0683b..09742a4 100644
--- a/net/http/http_network_transaction_spdy2_unittest.cc
+++ b/net/http/http_network_transaction_spdy2_unittest.cc
@@ -8084,12 +8084,6 @@ class CapturingProxyResolver : public ProxyResolver {
return LOAD_STATE_IDLE;
}
- virtual LoadState GetLoadStateThreadSafe(
- RequestHandle request) const OVERRIDE {
- NOTREACHED();
- return LOAD_STATE_IDLE;
- }
-
virtual void CancelSetPacScript() {
NOTREACHED();
}
diff --git a/net/http/http_network_transaction_spdy3_unittest.cc b/net/http/http_network_transaction_spdy3_unittest.cc
index 03a2c8e..ff54dad 100644
--- a/net/http/http_network_transaction_spdy3_unittest.cc
+++ b/net/http/http_network_transaction_spdy3_unittest.cc
@@ -8083,12 +8083,6 @@ class CapturingProxyResolver : public ProxyResolver {
return LOAD_STATE_IDLE;
}
- virtual LoadState GetLoadStateThreadSafe(
- RequestHandle request) const OVERRIDE {
- NOTREACHED();
- return LOAD_STATE_IDLE;
- }
-
virtual void CancelSetPacScript() {
NOTREACHED();
}
diff --git a/net/net.gyp b/net/net.gyp
index 4c7d4f0..eeaeab5 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -633,11 +633,8 @@
'proxy/proxy_list.h',
'proxy/proxy_resolver.h',
'proxy/proxy_resolver_error_observer.h',
- 'proxy/proxy_resolver_js_bindings.cc',
- 'proxy/proxy_resolver_js_bindings.h',
'proxy/proxy_resolver_mac.cc',
'proxy/proxy_resolver_mac.h',
- 'proxy/proxy_resolver_request_context.h',
'proxy/proxy_resolver_script.h',
'proxy/proxy_resolver_script_data.cc',
'proxy/proxy_resolver_script_data.h',
@@ -654,9 +651,6 @@
'proxy/proxy_server_mac.cc',
'proxy/proxy_service.cc',
'proxy/proxy_service.h',
- 'proxy/sync_host_resolver.h',
- 'proxy/sync_host_resolver_bridge.cc',
- 'proxy/sync_host_resolver_bridge.h',
'quic/congestion_control/cubic.cc',
'quic/congestion_control/cubic.h',
'quic/congestion_control/fix_rate_receiver.cc',
@@ -1474,13 +1468,12 @@
'proxy/proxy_config_unittest.cc',
'proxy/proxy_info_unittest.cc',
'proxy/proxy_list_unittest.cc',
- 'proxy/proxy_resolver_js_bindings_unittest.cc',
+ 'proxy/proxy_resolver_v8_tracing_unittest.cc',
'proxy/proxy_resolver_v8_unittest.cc',
'proxy/proxy_script_decider_unittest.cc',
'proxy/proxy_script_fetcher_impl_unittest.cc',
'proxy/proxy_server_unittest.cc',
'proxy/proxy_service_unittest.cc',
- 'proxy/sync_host_resolver_bridge_unittest.cc',
'quic/congestion_control/cubic_test.cc',
'quic/congestion_control/fix_rate_test.cc',
'quic/congestion_control/hybrid_slow_start_test.cc',
@@ -1701,6 +1694,7 @@
}, { # else: !use_v8_in_net
'sources!': [
'proxy/proxy_resolver_v8_unittest.cc',
+ 'proxy/proxy_resolver_v8_tracing_unittest.cc',
],
},
],
@@ -2070,6 +2064,8 @@
'sources': [
'proxy/proxy_resolver_v8.cc',
'proxy/proxy_resolver_v8.h',
+ 'proxy/proxy_resolver_v8_tracing.cc',
+ 'proxy/proxy_resolver_v8_tracing.h',
'proxy/proxy_service_v8.cc',
'proxy/proxy_service_v8.h',
],
diff --git a/net/net_unittests.isolate b/net/net_unittests.isolate
index b3c8d7b..0fc30a2 100644
--- a/net/net_unittests.isolate
+++ b/net/net_unittests.isolate
@@ -228,6 +228,17 @@
}, {
'variables': {
'isolate_dependency_tracked': [
+ 'data/proxy_resolver_v8_tracing_unittest/dns.js',
+ 'data/proxy_resolver_v8_tracing_unittest/dns_during_init.js',
+ 'data/proxy_resolver_v8_tracing_unittest/error.js',
+ 'data/proxy_resolver_v8_tracing_unittest/global_sideffects1.js',
+ 'data/proxy_resolver_v8_tracing_unittest/global_sideffects2.js',
+ 'data/proxy_resolver_v8_tracing_unittest/global_sideffects3.js',
+ 'data/proxy_resolver_v8_tracing_unittest/global_sideffects4.js',
+ 'data/proxy_resolver_v8_tracing_unittest/simple.js',
+ 'data/proxy_resolver_v8_tracing_unittest/simple_dns.js',
+ 'data/proxy_resolver_v8_tracing_unittest/too_many_alerts.js',
+ 'data/proxy_resolver_v8_tracing_unittest/too_many_empty_alerts.js',
'data/proxy_resolver_v8_unittest/binding_from_global.js',
'data/proxy_resolver_v8_unittest/bindings.js',
'data/proxy_resolver_v8_unittest/direct.js',
diff --git a/net/proxy/mock_proxy_resolver.cc b/net/proxy/mock_proxy_resolver.cc
index 0d40528..c50f7d4 100644
--- a/net/proxy/mock_proxy_resolver.cc
+++ b/net/proxy/mock_proxy_resolver.cc
@@ -78,12 +78,6 @@ LoadState MockAsyncProxyResolverBase::GetLoadState(
return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
}
-LoadState MockAsyncProxyResolverBase::GetLoadStateThreadSafe(
- RequestHandle request_handle) const {
- NOTREACHED();
- return LOAD_STATE_IDLE;
-}
-
int MockAsyncProxyResolverBase::SetPacScript(
const scoped_refptr<ProxyResolverScriptData>& script_data,
const CompletionCallback& callback) {
diff --git a/net/proxy/mock_proxy_resolver.h b/net/proxy/mock_proxy_resolver.h
index e68e42b..8f78c91 100644
--- a/net/proxy/mock_proxy_resolver.h
+++ b/net/proxy/mock_proxy_resolver.h
@@ -76,8 +76,6 @@ class MockAsyncProxyResolverBase : public ProxyResolver {
const BoundNetLog& /*net_log*/) OVERRIDE;
virtual void CancelRequest(RequestHandle request_handle) OVERRIDE;
virtual LoadState GetLoadState(RequestHandle request_handle) const OVERRIDE;
- virtual LoadState GetLoadStateThreadSafe(
- RequestHandle request_handle) const OVERRIDE;
virtual int SetPacScript(
const scoped_refptr<ProxyResolverScriptData>& script_data,
const net::CompletionCallback& callback) OVERRIDE;
diff --git a/net/proxy/multi_threaded_proxy_resolver.cc b/net/proxy/multi_threaded_proxy_resolver.cc
index bd9890c..01dfe24 100644
--- a/net/proxy/multi_threaded_proxy_resolver.cc
+++ b/net/proxy/multi_threaded_proxy_resolver.cc
@@ -359,11 +359,6 @@ void MultiThreadedProxyResolver::Executor::OnJobCompleted(Job* job) {
void MultiThreadedProxyResolver::Executor::Destroy() {
DCHECK(coordinator_);
- // Give the resolver an opportunity to shutdown from THIS THREAD before
- // joining on the resolver thread. This allows certain implementations
- // to avoid deadlocks.
- resolver_->Shutdown();
-
{
// See http://crbug.com/69710.
base::ThreadRestrictions::ScopedAllowIO allow_io;
@@ -484,19 +479,9 @@ void MultiThreadedProxyResolver::CancelRequest(RequestHandle req) {
LoadState MultiThreadedProxyResolver::GetLoadState(RequestHandle req) const {
DCHECK(CalledOnValidThread());
DCHECK(req);
-
- Job* job = reinterpret_cast<Job*>(req);
- if (job->executor())
- return job->executor()->resolver()->GetLoadStateThreadSafe(NULL);
return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
}
-LoadState MultiThreadedProxyResolver::GetLoadStateThreadSafe(
- RequestHandle req) const {
- NOTIMPLEMENTED();
- return LOAD_STATE_IDLE;
-}
-
void MultiThreadedProxyResolver::CancelSetPacScript() {
DCHECK(CalledOnValidThread());
DCHECK_EQ(0u, pending_jobs_.size());
diff --git a/net/proxy/multi_threaded_proxy_resolver.h b/net/proxy/multi_threaded_proxy_resolver.h
index 82a06f5..3076c36 100644
--- a/net/proxy/multi_threaded_proxy_resolver.h
+++ b/net/proxy/multi_threaded_proxy_resolver.h
@@ -98,8 +98,6 @@ class NET_EXPORT_PRIVATE MultiThreadedProxyResolver
const BoundNetLog& net_log) OVERRIDE;
virtual void CancelRequest(RequestHandle request) OVERRIDE;
virtual LoadState GetLoadState(RequestHandle request) const OVERRIDE;
- virtual LoadState GetLoadStateThreadSafe(
- RequestHandle request) const OVERRIDE;
virtual void CancelSetPacScript() OVERRIDE;
virtual void PurgeMemory() OVERRIDE;
virtual int SetPacScript(
diff --git a/net/proxy/multi_threaded_proxy_resolver_unittest.cc b/net/proxy/multi_threaded_proxy_resolver_unittest.cc
index dbd2f5d..bb856bd 100644
--- a/net/proxy/multi_threaded_proxy_resolver_unittest.cc
+++ b/net/proxy/multi_threaded_proxy_resolver_unittest.cc
@@ -66,12 +66,6 @@ class MockProxyResolver : public ProxyResolver {
return LOAD_STATE_IDLE;
}
- virtual LoadState GetLoadStateThreadSafe(
- RequestHandle request) const OVERRIDE {
- NOTREACHED();
- return LOAD_STATE_IDLE;
- }
-
virtual void CancelSetPacScript() OVERRIDE {
NOTREACHED();
}
@@ -190,12 +184,6 @@ class ForwardingProxyResolver : public ProxyResolver {
return LOAD_STATE_IDLE;
}
- virtual LoadState GetLoadStateThreadSafe(
- RequestHandle request) const OVERRIDE {
- NOTREACHED();
- return LOAD_STATE_IDLE;
- }
-
virtual void CancelSetPacScript() OVERRIDE {
impl_->CancelSetPacScript();
}
diff --git a/net/proxy/proxy_resolver.h b/net/proxy/proxy_resolver.h
index 6b63407..9d3387a 100644
--- a/net/proxy/proxy_resolver.h
+++ b/net/proxy/proxy_resolver.h
@@ -52,9 +52,6 @@ class NET_EXPORT_PRIVATE ProxyResolver {
// Gets the LoadState for |request|.
virtual LoadState GetLoadState(RequestHandle request) const = 0;
- // Gets the LoadState for |request|. May be called from another thread.
- virtual LoadState GetLoadStateThreadSafe(RequestHandle request) const = 0;
-
// The PAC script backend can be specified to the ProxyResolver either via
// URL, or via the javascript text itself. If |expects_pac_bytes| is true,
// then the ProxyResolverScriptData passed to SetPacScript() should
@@ -75,10 +72,6 @@ class NET_EXPORT_PRIVATE ProxyResolver {
const scoped_refptr<ProxyResolverScriptData>& pac_script,
const net::CompletionCallback& callback) = 0;
- // Optional shutdown code to be run before destruction. This is only used
- // by the multithreaded runner to signal cleanup from origin thread
- virtual void Shutdown() {}
-
private:
const bool expects_pac_bytes_;
diff --git a/net/proxy/proxy_resolver_error_observer.h b/net/proxy/proxy_resolver_error_observer.h
index 9176c2f..6ee9cbb 100644
--- a/net/proxy/proxy_resolver_error_observer.h
+++ b/net/proxy/proxy_resolver_error_observer.h
@@ -11,10 +11,7 @@
namespace net {
-// Interface for observing JavaScript error messages from PAC scripts. The
-// default implementation of the ProxyResolverJSBindings takes a class
-// implementing this interface and forwards all JavaScript errors related to
-// PAC scripts.
+// Interface for observing JavaScript error messages from PAC scripts.
class NET_EXPORT_PRIVATE ProxyResolverErrorObserver {
public:
ProxyResolverErrorObserver() {}
@@ -23,6 +20,11 @@ class NET_EXPORT_PRIVATE ProxyResolverErrorObserver {
// Handler for when an error is encountered. |line_number| may be -1
// if a line number is not applicable to this error. |error| is a message
// describing the error.
+ //
+ // Note on threading: This may get called from a worker thread. If the
+ // backing proxy resolver is ProxyResolverV8Tracing, then it will not
+ // be called concurrently, however it will be called from a different
+ // thread than the proxy resolver's origin thread.
virtual void OnPACScriptError(int line_number, const string16& error) = 0;
private:
diff --git a/net/proxy/proxy_resolver_js_bindings.cc b/net/proxy/proxy_resolver_js_bindings.cc
deleted file mode 100644
index 84dcafd..0000000
--- a/net/proxy/proxy_resolver_js_bindings.cc
+++ /dev/null
@@ -1,291 +0,0 @@
-// Copyright (c) 2012 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_resolver_js_bindings.h"
-
-#include "base/bind.h"
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "base/string_util.h"
-#include "base/values.h"
-#include "net/base/address_list.h"
-#include "net/base/host_cache.h"
-#include "net/base/host_resolver.h"
-#include "net/base/net_errors.h"
-#include "net/base/net_log.h"
-#include "net/base/net_util.h"
-#include "net/proxy/proxy_resolver_error_observer.h"
-#include "net/proxy/proxy_resolver_request_context.h"
-#include "net/proxy/sync_host_resolver.h"
-
-namespace net {
-
-namespace {
-
-// TTL for the per-request DNS cache. Applies to both successful and failed
-// DNS resolutions.
-const unsigned kCacheEntryTTLSeconds = 5 * 60;
-
-// Returns event parameters for a PAC error message (line number + message).
-Value* NetLogErrorCallback(int line_number,
- const string16* message,
- NetLog::LogLevel /* log_level */) {
- DictionaryValue* dict = new DictionaryValue();
- dict->SetInteger("line_number", line_number);
- dict->SetString("message", *message);
- return dict;
-}
-
-// ProxyResolverJSBindings implementation.
-class DefaultJSBindings : public ProxyResolverJSBindings {
- public:
- DefaultJSBindings(SyncHostResolver* host_resolver,
- NetLog* net_log,
- ProxyResolverErrorObserver* error_observer)
- : host_resolver_(host_resolver),
- net_log_(net_log),
- error_observer_(error_observer) {
- }
-
- // Handler for "alert(message)".
- virtual void Alert(const string16& message) OVERRIDE {
- VLOG(1) << "PAC-alert: " << message;
-
- // Send to the NetLog.
- LogEventToCurrentRequestAndGlobally(
- NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
- NetLog::StringCallback("message", &message));
- }
-
- // Handler for "myIpAddress()".
- // TODO(eroman): Perhaps enumerate the interfaces directly, using
- // getifaddrs().
- virtual bool MyIpAddress(std::string* first_ip_address) OVERRIDE {
- LogEventToCurrentRequest(NetLog::PHASE_BEGIN,
- NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS);
-
- bool ok = MyIpAddressImpl(first_ip_address);
-
- LogEventToCurrentRequest(NetLog::PHASE_END,
- NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS);
- return ok;
- }
-
- // Handler for "myIpAddressEx()".
- virtual bool MyIpAddressEx(std::string* ip_address_list) OVERRIDE {
- LogEventToCurrentRequest(NetLog::PHASE_BEGIN,
- NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS_EX);
-
- bool ok = MyIpAddressExImpl(ip_address_list);
-
- LogEventToCurrentRequest(NetLog::PHASE_END,
- NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS_EX);
- return ok;
- }
-
- // Handler for "dnsResolve(host)".
- virtual bool DnsResolve(const std::string& host,
- std::string* first_ip_address) OVERRIDE {
- LogEventToCurrentRequest(NetLog::PHASE_BEGIN,
- NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE);
-
- bool ok = DnsResolveImpl(host, first_ip_address);
-
- LogEventToCurrentRequest(NetLog::PHASE_END,
- NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE);
- return ok;
- }
-
- // Handler for "dnsResolveEx(host)".
- virtual bool DnsResolveEx(const std::string& host,
- std::string* ip_address_list) OVERRIDE {
- LogEventToCurrentRequest(NetLog::PHASE_BEGIN,
- NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE_EX);
-
- bool ok = DnsResolveExImpl(host, ip_address_list);
-
- LogEventToCurrentRequest(NetLog::PHASE_END,
- NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE_EX);
- return ok;
- }
-
- // Handler for when an error is encountered. |line_number| may be -1.
- virtual void OnError(int line_number, const string16& message) OVERRIDE {
- // Send to the chrome log.
- if (line_number == -1)
- VLOG(1) << "PAC-error: " << message;
- else
- VLOG(1) << "PAC-error: " << "line: " << line_number << ": " << message;
-
- // Send the error to the NetLog.
- LogEventToCurrentRequestAndGlobally(
- NetLog::TYPE_PAC_JAVASCRIPT_ERROR,
- base::Bind(&NetLogErrorCallback, line_number, &message));
-
- if (error_observer_.get())
- error_observer_->OnPACScriptError(line_number, message);
- }
-
- virtual void Shutdown() OVERRIDE {
- host_resolver_->Shutdown();
- }
-
- private:
- bool MyIpAddressImpl(std::string* first_ip_address) {
- std::string my_hostname = GetHostName();
- if (my_hostname.empty())
- return false;
- return DnsResolveImpl(my_hostname, first_ip_address);
- }
-
- bool MyIpAddressExImpl(std::string* ip_address_list) {
- std::string my_hostname = GetHostName();
- if (my_hostname.empty())
- return false;
- return DnsResolveExImpl(my_hostname, ip_address_list);
- }
-
- bool DnsResolveImpl(const std::string& host,
- std::string* first_ip_address) {
- // Do a sync resolve of the hostname (port doesn't matter).
- // Disable IPv6 results. We do this because the PAC specification isn't
- // really IPv6 friendly, and Internet Explorer also restricts to IPv4.
- // Consequently a lot of existing PAC scripts assume they will only get
- // IPv4 results, and will misbehave if they get an IPv6 result.
- // See http://crbug.com/24641 for more details.
- HostResolver::RequestInfo info(HostPortPair(host, 80));
- info.set_address_family(ADDRESS_FAMILY_IPV4);
- AddressList address_list;
-
- int result = DnsResolveHelper(info, &address_list);
- if (result != OK)
- return false;
-
- // There may be multiple results; we will just use the first one.
- // This returns empty string on failure.
- *first_ip_address = address_list.front().ToStringWithoutPort();
- if (first_ip_address->empty())
- return false;
-
- return true;
- }
-
- bool DnsResolveExImpl(const std::string& host,
- std::string* ip_address_list) {
- // Do a sync resolve of the hostname (port doesn't matter).
- HostResolver::RequestInfo info(HostPortPair(host, 80));
- AddressList address_list;
- int result = DnsResolveHelper(info, &address_list);
-
- if (result != OK)
- return false;
-
- // Stringify all of the addresses in the address list, separated
- // by semicolons.
- std::string address_list_str;
- for (AddressList::const_iterator iter = address_list.begin();
- iter != address_list.end(); ++iter) {
- if (!address_list_str.empty())
- address_list_str += ";";
- const std::string address_string = iter->ToStringWithoutPort();
- if (address_string.empty())
- return false;
- address_list_str += address_string;
- }
-
- *ip_address_list = address_list_str;
- return true;
- }
-
- // Helper to execute a synchronous DNS resolve, using the per-request
- // DNS cache if there is one.
- int DnsResolveHelper(const HostResolver::RequestInfo& info,
- AddressList* address_list) {
- HostCache::Key cache_key(info.hostname(),
- info.address_family(),
- info.host_resolver_flags());
-
- HostCache* host_cache = current_request_context() ?
- current_request_context()->host_cache : NULL;
-
- // First try to service this request from the per-request DNS cache.
- // (we cache DNS failures much more aggressively within the context
- // of a FindProxyForURL() request).
- if (host_cache) {
- const HostCache::Entry* entry =
- host_cache->Lookup(cache_key, base::TimeTicks::Now());
- if (entry) {
- if (entry->error == OK)
- *address_list = entry->addrlist;
- return entry->error;
- }
- }
-
- // Otherwise ask the host resolver.
- const BoundNetLog* net_log = GetNetLogForCurrentRequest();
- int result = host_resolver_->Resolve(info,
- address_list,
- net_log ? *net_log : BoundNetLog());
-
- // Save the result back to the per-request DNS cache.
- if (host_cache) {
- host_cache->Set(cache_key, HostCache::Entry(result, *address_list),
- base::TimeTicks::Now(),
- base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds));
- }
-
- return result;
- }
-
- // May return NULL.
- const BoundNetLog* GetNetLogForCurrentRequest() {
- if (!current_request_context())
- return NULL;
- return current_request_context()->net_log;
- }
-
- void LogEventToCurrentRequest(
- NetLog::EventPhase phase,
- NetLog::EventType type) {
- const BoundNetLog* net_log = GetNetLogForCurrentRequest();
- if (net_log)
- net_log->AddEntry(type, phase);
- }
-
- void LogEventToCurrentRequest(
- NetLog::EventPhase phase,
- NetLog::EventType type,
- const NetLog::ParametersCallback& parameters_callback) {
- const BoundNetLog* net_log = GetNetLogForCurrentRequest();
- if (net_log)
- net_log->AddEntry(type, phase, parameters_callback);
- }
-
- void LogEventToCurrentRequestAndGlobally(
- NetLog::EventType type,
- const NetLog::ParametersCallback& parameters_callback) {
- LogEventToCurrentRequest(NetLog::PHASE_NONE, type, parameters_callback);
-
- // Emit to the global NetLog event stream.
- if (net_log_)
- net_log_->AddGlobalEntry(type, parameters_callback);
- }
-
- scoped_ptr<SyncHostResolver> host_resolver_;
- NetLog* net_log_;
- scoped_ptr<ProxyResolverErrorObserver> error_observer_;
- DISALLOW_COPY_AND_ASSIGN(DefaultJSBindings);
-};
-
-} // namespace
-
-// static
-ProxyResolverJSBindings* ProxyResolverJSBindings::CreateDefault(
- SyncHostResolver* host_resolver,
- NetLog* net_log,
- ProxyResolverErrorObserver* error_observer) {
- return new DefaultJSBindings(host_resolver, net_log, error_observer);
-}
-
-} // namespace net
diff --git a/net/proxy/proxy_resolver_js_bindings.h b/net/proxy/proxy_resolver_js_bindings.h
deleted file mode 100644
index f201707..0000000
--- a/net/proxy/proxy_resolver_js_bindings.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) 2011 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_PROXY_RESOLVER_JS_BINDINGS_H_
-#define NET_PROXY_PROXY_RESOLVER_JS_BINDINGS_H_
-
-#include <string>
-
-#include "base/string16.h"
-#include "net/base/net_export.h"
-
-namespace net {
-
-class HostResolver;
-class NetLog;
-class ProxyResolverErrorObserver;
-struct ProxyResolverRequestContext;
-class SyncHostResolver;
-
-// Interface for the javascript bindings.
-class NET_EXPORT_PRIVATE ProxyResolverJSBindings {
- public:
- ProxyResolverJSBindings() : current_request_context_(NULL) {}
-
- virtual ~ProxyResolverJSBindings() {}
-
- // Handler for "alert(message)"
- virtual void Alert(const string16& message) = 0;
-
- // Handler for "myIpAddress()". Returns true on success and fills
- // |*first_ip_address| with the result.
- virtual bool MyIpAddress(std::string* first_ip_address) = 0;
-
- // Handler for "myIpAddressEx()". Returns true on success and fills
- // |*ip_address_list| with the result.
- //
- // This is a Microsoft extension to PAC for IPv6, see:
- // http://blogs.msdn.com/b/wndp/archive/2006/07/13/ipv6-pac-extensions-v0-9.aspx
-
- virtual bool MyIpAddressEx(std::string* ip_address_list) = 0;
-
- // Handler for "dnsResolve(host)". Returns true on success and fills
- // |*first_ip_address| with the result.
- virtual bool DnsResolve(const std::string& host,
- std::string* first_ip_address) = 0;
-
- // Handler for "dnsResolveEx(host)". Returns true on success and fills
- // |*ip_address_list| with the result.
- //
- // This is a Microsoft extension to PAC for IPv6, see:
- // http://blogs.msdn.com/b/wndp/archive/2006/07/13/ipv6-pac-extensions-v0-9.aspx
- virtual bool DnsResolveEx(const std::string& host,
- std::string* ip_address_list) = 0;
-
- // Handler for when an error is encountered. |line_number| may be -1
- // if a line number is not applicable to this error.
- virtual void OnError(int line_number, const string16& error) = 0;
-
- // Called before the thread running the proxy resolver is stopped.
- virtual void Shutdown() = 0;
-
- // Creates a default javascript bindings implementation that will:
- // - Send script error messages to both VLOG(1) and the NetLog.
- // - Send script alert()s to both VLOG(1) and the NetLog.
- // - Use the provided host resolver to service dnsResolve().
- //
- // Takes ownership of |host_resolver| and |error_observer| (the latter can
- // be NULL).
- static ProxyResolverJSBindings* CreateDefault(
- SyncHostResolver* host_resolver,
- NetLog* net_log,
- ProxyResolverErrorObserver* error_observer);
-
- // Sets details about the currently executing FindProxyForURL() request.
- void set_current_request_context(
- ProxyResolverRequestContext* current_request_context) {
- current_request_context_ = current_request_context;
- }
-
- // Retrieves details about the currently executing FindProxyForURL() request.
- ProxyResolverRequestContext* current_request_context() {
- return current_request_context_;
- }
-
- private:
- ProxyResolverRequestContext* current_request_context_;
-};
-
-} // namespace net
-
-#endif // NET_PROXY_PROXY_RESOLVER_JS_BINDINGS_H_
diff --git a/net/proxy/proxy_resolver_js_bindings_unittest.cc b/net/proxy/proxy_resolver_js_bindings_unittest.cc
deleted file mode 100644
index 97d69bf..0000000
--- a/net/proxy/proxy_resolver_js_bindings_unittest.cc
+++ /dev/null
@@ -1,365 +0,0 @@
-// Copyright (c) 2012 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_resolver_js_bindings.h"
-
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/string_util.h"
-#include "net/base/address_list.h"
-#include "net/base/host_cache.h"
-#include "net/base/mock_host_resolver.h"
-#include "net/base/net_errors.h"
-#include "net/base/net_log.h"
-#include "net/base/net_log_unittest.h"
-#include "net/base/net_util.h"
-#include "net/base/test_completion_callback.h"
-#include "net/proxy/proxy_resolver_request_context.h"
-#include "net/proxy/sync_host_resolver.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-namespace {
-
-// This is a HostResolver that synchronously resolves all hosts to the
-// following address list of length 3:
-// 192.168.1.1
-// 172.22.34.1
-// 200.100.1.2
-class MockHostResolverWithMultipleResults : public SyncHostResolver {
- public:
- // HostResolver methods:
- virtual int Resolve(const HostResolver::RequestInfo& info,
- AddressList* addresses,
- const BoundNetLog& bound_net_log) OVERRIDE {
- return ParseAddressList("192.168.1.1,172.22.34.1,200.100.1.2", "",
- addresses);
- }
-
- virtual void Shutdown() OVERRIDE {}
-
- private:
- virtual ~MockHostResolverWithMultipleResults() {}
-};
-
-class MockFailingHostResolver : public SyncHostResolver {
- public:
- MockFailingHostResolver() : count_(0) {}
-
- // HostResolver methods:
- virtual int Resolve(const HostResolver::RequestInfo& info,
- AddressList* addresses,
- const BoundNetLog& bound_net_log) OVERRIDE {
- count_++;
- return ERR_NAME_NOT_RESOLVED;
- }
-
- virtual void Shutdown() OVERRIDE {}
-
- // Returns the number of times Resolve() has been called.
- int count() const { return count_; }
- void ResetCount() { count_ = 0; }
-
- private:
- int count_;
-};
-
-class MockSyncHostResolver : public SyncHostResolver {
- public:
- MockSyncHostResolver() {
- resolver_.set_synchronous_mode(true);
- }
-
- virtual int Resolve(const HostResolver::RequestInfo& info,
- AddressList* addresses,
- const BoundNetLog& bound_net_log) OVERRIDE {
- return resolver_.Resolve(info, addresses, CompletionCallback(), NULL,
- bound_net_log);
- }
-
- virtual void Shutdown() OVERRIDE {}
-
- RuleBasedHostResolverProc* rules() {
- return resolver_.rules();
- }
-
- private:
- MockHostResolver resolver_;
-};
-
-TEST(ProxyResolverJSBindingsTest, DnsResolve) {
- MockSyncHostResolver* host_resolver = new MockSyncHostResolver;
-
- // Get a hold of a DefaultJSBindings* (it is a hidden impl class).
- scoped_ptr<ProxyResolverJSBindings> bindings(
- ProxyResolverJSBindings::CreateDefault(host_resolver, NULL, NULL));
-
- std::string ip_address;
-
- // Empty string is not considered a valid host (even though on some systems
- // requesting this will resolve to localhost).
- host_resolver->rules()->AddSimulatedFailure("");
- EXPECT_FALSE(bindings->DnsResolve("", &ip_address));
-
- // Should call through to the HostResolver.
- host_resolver->rules()->AddRule("google.com", "192.168.1.1");
- EXPECT_TRUE(bindings->DnsResolve("google.com", &ip_address));
- EXPECT_EQ("192.168.1.1", ip_address);
-
- // Resolve failures should give empty string.
- host_resolver->rules()->AddSimulatedFailure("fail");
- EXPECT_FALSE(bindings->DnsResolve("fail", &ip_address));
-
- // TODO(eroman): would be nice to have an IPV6 test here too, but that
- // won't work on all systems.
-}
-
-TEST(ProxyResolverJSBindingsTest, MyIpAddress) {
- MockSyncHostResolver* host_resolver = new MockSyncHostResolver;
-
- // Get a hold of a DefaultJSBindings* (it is a hidden impl class).
- scoped_ptr<ProxyResolverJSBindings> bindings(
- ProxyResolverJSBindings::CreateDefault(host_resolver, NULL, NULL));
-
- // Our IP address is always going to be 127.0.0.1, since we are using a
- // mock host resolver.
- std::string my_ip_address;
- EXPECT_TRUE(bindings->MyIpAddress(&my_ip_address));
-
- EXPECT_EQ("127.0.0.1", my_ip_address);
-}
-
-// Tests that the regular PAC functions restrict results to IPv4,
-// but that the Microsoft extensions to PAC do not. We test this
-// by seeing whether ADDRESS_FAMILY_IPV4 or ADDRESS_FAMILY_UNSPECIFIED
-// was passed into to the host resolver.
-//
-// Restricted to IPv4 address family:
-// myIpAddress()
-// dnsResolve()
-//
-// Unrestricted address family:
-// myIpAddressEx()
-// dnsResolveEx()
-TEST(ProxyResolverJSBindingsTest, RestrictAddressFamily) {
- MockSyncHostResolver* host_resolver = new MockSyncHostResolver;
-
- // Get a hold of a DefaultJSBindings* (it is a hidden impl class).
- scoped_ptr<ProxyResolverJSBindings> bindings(
- ProxyResolverJSBindings::CreateDefault(host_resolver, NULL, NULL));
-
- // Make it so requests resolve to particular address patterns based on family:
- // IPV4_ONLY --> 192.168.1.*
- // UNSPECIFIED --> 192.168.2.1
- host_resolver->rules()->AddRuleForAddressFamily(
- "foo", ADDRESS_FAMILY_IPV4, "192.168.1.1");
- host_resolver->rules()->AddRuleForAddressFamily(
- "*", ADDRESS_FAMILY_IPV4, "192.168.1.2");
- host_resolver->rules()->AddRuleForAddressFamily(
- "foo", ADDRESS_FAMILY_UNSPECIFIED, "192.168.2.1");
- host_resolver->rules()->AddRuleForAddressFamily(
- "*", ADDRESS_FAMILY_UNSPECIFIED, "192.168.2.2");
-
- // Verify that our mock setups works as expected, and we get different results
- // depending if the address family was IPV4_ONLY or not.
- HostResolver::RequestInfo info(HostPortPair("foo", 80));
- AddressList address_list;
- EXPECT_EQ(OK, host_resolver->Resolve(info, &address_list, BoundNetLog()));
- ASSERT_FALSE(address_list.empty());
- EXPECT_EQ("192.168.2.1", address_list.front().ToStringWithoutPort());
-
- info.set_address_family(ADDRESS_FAMILY_IPV4);
- EXPECT_EQ(OK, host_resolver->Resolve(info, &address_list, BoundNetLog()));
- ASSERT_FALSE(address_list.empty());
- EXPECT_EQ("192.168.1.1", address_list.front().ToStringWithoutPort());
-
- std::string ip_address;
- // Now the actual test.
- EXPECT_TRUE(bindings->MyIpAddress(&ip_address));
- EXPECT_EQ("192.168.1.2", ip_address); // IPv4 restricted.
-
- EXPECT_TRUE(bindings->DnsResolve("foo", &ip_address));
- EXPECT_EQ("192.168.1.1", ip_address); // IPv4 restricted.
-
- EXPECT_TRUE(bindings->DnsResolve("foo2", &ip_address));
- EXPECT_EQ("192.168.1.2", ip_address); // IPv4 restricted.
-
- EXPECT_TRUE(bindings->MyIpAddressEx(&ip_address));
- EXPECT_EQ("192.168.2.2", ip_address); // Unrestricted.
-
- EXPECT_TRUE(bindings->DnsResolveEx("foo", &ip_address));
- EXPECT_EQ("192.168.2.1", ip_address); // Unrestricted.
-
- EXPECT_TRUE(bindings->DnsResolveEx("foo2", &ip_address));
- EXPECT_EQ("192.168.2.2", ip_address); // Unrestricted.
-}
-
-// Test that myIpAddressEx() and dnsResolveEx() both return a semi-colon
-// separated list of addresses (as opposed to the non-Ex versions which
-// just return the first result).
-TEST(ProxyResolverJSBindingsTest, ExFunctionsReturnList) {
- SyncHostResolver* host_resolver =
- new MockHostResolverWithMultipleResults;
-
- // Get a hold of a DefaultJSBindings* (it is a hidden impl class).
- scoped_ptr<ProxyResolverJSBindings> bindings(
- ProxyResolverJSBindings::CreateDefault(host_resolver, NULL, NULL));
-
- std::string ip_addresses;
-
- EXPECT_TRUE(bindings->MyIpAddressEx(&ip_addresses));
- EXPECT_EQ("192.168.1.1;172.22.34.1;200.100.1.2", ip_addresses);
-
- EXPECT_TRUE(bindings->DnsResolveEx("FOO", &ip_addresses));
- EXPECT_EQ("192.168.1.1;172.22.34.1;200.100.1.2", ip_addresses);
-}
-
-TEST(ProxyResolverJSBindingsTest, PerRequestDNSCache) {
- MockFailingHostResolver* host_resolver = new MockFailingHostResolver;
-
- // Get a hold of a DefaultJSBindings* (it is a hidden impl class).
- scoped_ptr<ProxyResolverJSBindings> bindings(
- ProxyResolverJSBindings::CreateDefault(host_resolver, NULL, NULL));
-
- std::string ip_address;
-
- // Call DnsResolve() 4 times for the same hostname -- this should issue
- // 4 separate calls to the underlying host resolver, since there is no
- // current request context.
- EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address));
- EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address));
- EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address));
- EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address));
- EXPECT_EQ(4, host_resolver->count());
-
- host_resolver->ResetCount();
-
- // Now setup a per-request context, and try the same experiment -- we
- // expect the underlying host resolver to receive only 1 request this time,
- // since it will service the others from the per-request DNS cache.
- const unsigned kMaxCacheEntries = 50;
- HostCache cache(kMaxCacheEntries);
- ProxyResolverRequestContext context(NULL, &cache);
- bindings->set_current_request_context(&context);
-
- EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address));
- EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address));
- EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address));
- EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address));
- EXPECT_EQ(1, host_resolver->count());
-
- host_resolver->ResetCount();
-
- // The "Ex" version shares this same cache, however since the flags
- // are different it won't reuse this particular entry.
- EXPECT_FALSE(bindings->DnsResolveEx("foo", &ip_address));
- EXPECT_EQ(1, host_resolver->count());
- EXPECT_FALSE(bindings->DnsResolveEx("foo", &ip_address));
- EXPECT_FALSE(bindings->DnsResolveEx("foo", &ip_address));
- EXPECT_EQ(1, host_resolver->count());
-
- bindings->set_current_request_context(NULL);
-}
-
-// Test that when a binding is called, it logs to the per-request NetLog.
-TEST(ProxyResolverJSBindingsTest, NetLog) {
- MockFailingHostResolver* host_resolver = new MockFailingHostResolver;
-
- CapturingNetLog global_log;
-
- // Get a hold of a DefaultJSBindings* (it is a hidden impl class).
- scoped_ptr<ProxyResolverJSBindings> bindings(
- ProxyResolverJSBindings::CreateDefault(
- host_resolver, &global_log, NULL));
-
- // Attach a capturing NetLog as the current request's log stream.
- CapturingNetLog log;
- BoundNetLog bound_log(BoundNetLog::Make(&log, NetLog::SOURCE_NONE));
- ProxyResolverRequestContext context(&bound_log, NULL);
- bindings->set_current_request_context(&context);
-
- std::string ip_address;
- net::CapturingNetLog::CapturedEntryList entries;
- log.GetEntries(&entries);
- ASSERT_EQ(0u, entries.size());
-
- // Call all the bindings. Each call should be logging something to
- // our NetLog.
-
- bindings->MyIpAddress(&ip_address);
-
- log.GetEntries(&entries);
- EXPECT_EQ(2u, entries.size());
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS));
-
- bindings->MyIpAddressEx(&ip_address);
-
- log.GetEntries(&entries);
- EXPECT_EQ(4u, entries.size());
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 2, NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS_EX));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 3, NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS_EX));
-
- bindings->DnsResolve("foo", &ip_address);
-
- log.GetEntries(&entries);
- EXPECT_EQ(6u, entries.size());
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 4, NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 5, NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE));
-
- bindings->DnsResolveEx("foo", &ip_address);
-
- log.GetEntries(&entries);
- EXPECT_EQ(8u, entries.size());
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 6, NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE_EX));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 7, NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE_EX));
-
- // Nothing has been emitted globally yet.
- net::CapturingNetLog::CapturedEntryList global_log_entries;
- global_log.GetEntries(&global_log_entries);
- EXPECT_EQ(0u, global_log_entries.size());
-
- bindings->OnError(30, string16());
-
- log.GetEntries(&entries);
- EXPECT_EQ(9u, entries.size());
- EXPECT_TRUE(LogContainsEvent(
- entries, 8, NetLog::TYPE_PAC_JAVASCRIPT_ERROR,
- NetLog::PHASE_NONE));
-
- // We also emit errors to the top-level log stream.
- global_log.GetEntries(&global_log_entries);
- EXPECT_EQ(1u, global_log_entries.size());
- EXPECT_TRUE(LogContainsEvent(
- global_log_entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ERROR,
- NetLog::PHASE_NONE));
-
- bindings->Alert(string16());
-
- log.GetEntries(&entries);
- EXPECT_EQ(10u, entries.size());
- EXPECT_TRUE(LogContainsEvent(
- entries, 9, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
- NetLog::PHASE_NONE));
-
- // We also emit javascript alerts to the top-level log stream.
- global_log.GetEntries(&global_log_entries);
- EXPECT_EQ(2u, global_log_entries.size());
- EXPECT_TRUE(LogContainsEvent(
- global_log_entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
- NetLog::PHASE_NONE));
-}
-
-} // namespace
-
-} // namespace net
diff --git a/net/proxy/proxy_resolver_mac.cc b/net/proxy/proxy_resolver_mac.cc
index a5a05af..d452ef8 100644
--- a/net/proxy/proxy_resolver_mac.cc
+++ b/net/proxy/proxy_resolver_mac.cc
@@ -196,11 +196,6 @@ LoadState ProxyResolverMac::GetLoadState(RequestHandle request) const {
return LOAD_STATE_IDLE;
}
-LoadState ProxyResolverMac::GetLoadStateThreadSafe(
- RequestHandle request) const {
- return LOAD_STATE_IDLE;
-}
-
void ProxyResolverMac::CancelSetPacScript() {
NOTREACHED();
}
diff --git a/net/proxy/proxy_resolver_mac.h b/net/proxy/proxy_resolver_mac.h
index 2aafce2..d791a7d 100644
--- a/net/proxy/proxy_resolver_mac.h
+++ b/net/proxy/proxy_resolver_mac.h
@@ -31,9 +31,6 @@ class NET_EXPORT ProxyResolverMac : public ProxyResolver {
virtual LoadState GetLoadState(RequestHandle request) const OVERRIDE;
- virtual LoadState GetLoadStateThreadSafe(
- RequestHandle request) const OVERRIDE;
-
virtual void CancelSetPacScript() OVERRIDE;
virtual int SetPacScript(
diff --git a/net/proxy/proxy_resolver_perftest.cc b/net/proxy/proxy_resolver_perftest.cc
index f5994ca..4eae4c6 100644
--- a/net/proxy/proxy_resolver_perftest.cc
+++ b/net/proxy/proxy_resolver_perftest.cc
@@ -11,9 +11,7 @@
#include "net/base/mock_host_resolver.h"
#include "net/base/net_errors.h"
#include "net/proxy/proxy_info.h"
-#include "net/proxy/proxy_resolver_js_bindings.h"
#include "net/proxy/proxy_resolver_v8.h"
-#include "net/proxy/sync_host_resolver.h"
#include "net/test/test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -23,17 +21,6 @@
#include "net/proxy/proxy_resolver_mac.h"
#endif
-class MockSyncHostResolver : public net::SyncHostResolver {
- public:
- virtual int Resolve(const net::HostResolver::RequestInfo& info,
- net::AddressList* addresses,
- const net::BoundNetLog& net_log) OVERRIDE {
- return net::ERR_NAME_NOT_RESOLVED;
- }
-
- virtual void Shutdown() OVERRIDE {}
-};
-
// This class holds the URL to use for resolving, and the expected result.
// We track the expected result in order to make sure the performance
// test is actually resolving URLs properly, otherwise the perf numbers
@@ -207,12 +194,30 @@ TEST(ProxyResolverPerfTest, ProxyResolverMac) {
}
#endif
-TEST(ProxyResolverPerfTest, ProxyResolverV8) {
- net::ProxyResolverJSBindings* js_bindings =
- net::ProxyResolverJSBindings::CreateDefault(
- new MockSyncHostResolver, NULL, NULL);
+class MockJSBindings : public net::ProxyResolverV8::JSBindings {
+ public:
+ MockJSBindings() {}
- net::ProxyResolverV8 resolver(js_bindings);
+ virtual void Alert(const string16& message) OVERRIDE {
+ CHECK(false);
+ }
+
+ virtual bool ResolveDns(const std::string& host,
+ ResolveDnsOperation op,
+ std::string* output) OVERRIDE {
+ CHECK(false);
+ return false;
+ }
+
+ virtual void OnError(int line_number, const string16& message) OVERRIDE {
+ CHECK(false);
+ }
+};
+
+TEST(ProxyResolverPerfTest, ProxyResolverV8) {
+ MockJSBindings js_bindings;
+ net::ProxyResolverV8 resolver;
+ resolver.set_js_bindings(&js_bindings);
PacPerfSuiteRunner runner(&resolver, "ProxyResolverV8");
runner.RunAllTests();
}
diff --git a/net/proxy/proxy_resolver_request_context.h b/net/proxy/proxy_resolver_request_context.h
deleted file mode 100644
index fdcced1..0000000
--- a/net/proxy/proxy_resolver_request_context.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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_PROXY_RESOLVER_REQUEST_CONTEXT_H_
-#define NET_PROXY_PROXY_RESOLVER_REQUEST_CONTEXT_H_
-
-namespace net {
-
-class HostCache;
-class BoundNetLog;
-
-// This data structure holds state related to an invocation of
-// "FindProxyForURL()". It is used to associate per-request
-// data that can be retrieved by the bindings.
-struct ProxyResolverRequestContext {
- // All of these pointers are expected to remain valid for duration of
- // this instance's lifetime.
- ProxyResolverRequestContext(const BoundNetLog* net_log,
- HostCache* host_cache)
- : net_log(net_log),
- host_cache(host_cache) {
- }
-
- const BoundNetLog* net_log;
- HostCache* host_cache;
-};
-
-} // namespace net
-
-#endif // NET_PROXY_PROXY_RESOLVER_REQUEST_CONTEXT_H_
diff --git a/net/proxy/proxy_resolver_v8.cc b/net/proxy/proxy_resolver_v8.cc
index 6956dae..8f71af9 100644
--- a/net/proxy/proxy_resolver_v8.cc
+++ b/net/proxy/proxy_resolver_v8.cc
@@ -18,13 +18,10 @@
#include "base/utf_string_conversions.h"
#include "googleurl/src/gurl.h"
#include "googleurl/src/url_canon.h"
-#include "net/base/host_cache.h"
#include "net/base/net_errors.h"
#include "net/base/net_log.h"
#include "net/base/net_util.h"
#include "net/proxy/proxy_info.h"
-#include "net/proxy/proxy_resolver_js_bindings.h"
-#include "net/proxy/proxy_resolver_request_context.h"
#include "net/proxy/proxy_resolver_script.h"
#include "v8/include/v8.h"
@@ -337,10 +334,8 @@ bool IsInNetEx(const std::string& ip_address, const std::string& ip_prefix) {
class ProxyResolverV8::Context {
public:
- explicit Context(ProxyResolverJSBindings* js_bindings)
- : is_resolving_host_(false),
- js_bindings_(js_bindings) {
- DCHECK(js_bindings != NULL);
+ explicit Context(ProxyResolverV8* parent)
+ : parent_(parent) {
}
~Context() {
@@ -356,6 +351,10 @@ class ProxyResolverV8::Context {
PurgeMemory();
}
+ JSBindings* js_bindings() {
+ return parent_->js_bindings_;
+ }
+
int ResolveProxy(const GURL& query_url, ProxyInfo* results) {
v8::Locker locked;
v8::HandleScope scope;
@@ -364,7 +363,7 @@ class ProxyResolverV8::Context {
v8::Local<v8::Value> function;
if (!GetFindProxyForURL(&function)) {
- js_bindings_->OnError(
+ js_bindings()->OnError(
-1, ASCIIToUTF16("FindProxyForURL() is undefined."));
return ERR_PAC_SCRIPT_FAILED;
}
@@ -384,7 +383,7 @@ class ProxyResolverV8::Context {
}
if (!ret->IsString()) {
- js_bindings_->OnError(
+ js_bindings()->OnError(
-1, ASCIIToUTF16("FindProxyForURL() did not return a string."));
return ERR_PAC_SCRIPT_FAILED;
}
@@ -399,7 +398,7 @@ class ProxyResolverV8::Context {
string16 error_message =
ASCIIToUTF16("FindProxyForURL() returned a non-ASCII string "
"(crbug.com/47234): ") + ret_str;
- js_bindings_->OnError(-1, error_message);
+ js_bindings()->OnError(-1, error_message);
return ERR_PAC_SCRIPT_FAILED;
}
@@ -477,7 +476,7 @@ class ProxyResolverV8::Context {
// to be a legitimiate PAC script.
v8::Local<v8::Value> function;
if (!GetFindProxyForURL(&function)) {
- js_bindings_->OnError(
+ js_bindings()->OnError(
-1, ASCIIToUTF16("FindProxyForURL() is undefined."));
return ERR_PAC_SCRIPT_FAILED;
}
@@ -485,49 +484,12 @@ class ProxyResolverV8::Context {
return OK;
}
- void SetCurrentRequestContext(ProxyResolverRequestContext* context) {
- js_bindings_->set_current_request_context(context);
- }
-
void PurgeMemory() {
v8::Locker locked;
v8::V8::LowMemoryNotification();
}
- bool is_resolving_host() const {
- base::AutoLock auto_lock(lock_);
- return is_resolving_host_;
- }
-
private:
- class ScopedHostResolve {
- public:
- explicit ScopedHostResolve(Context* context)
- : context_(context) {
- context_->BeginHostResolve();
- }
-
- ~ScopedHostResolve() {
- context_->EndHostResolve();
- }
-
- private:
- Context* const context_;
- DISALLOW_COPY_AND_ASSIGN(ScopedHostResolve);
- };
-
- void BeginHostResolve() {
- base::AutoLock auto_lock(lock_);
- DCHECK(!is_resolving_host_);
- is_resolving_host_ = true;
- }
-
- void EndHostResolve() {
- base::AutoLock auto_lock(lock_);
- DCHECK(is_resolving_host_);
- is_resolving_host_ = false;
- }
-
bool GetFindProxyForURL(v8::Local<v8::Value>* function) {
*function = v8_context_->Global()->Get(
ASCIILiteralToV8String("FindProxyForURL"));
@@ -543,7 +505,7 @@ class ProxyResolverV8::Context {
int line_number = message->GetLineNumber();
string16 error_message;
V8ObjectToUTF16String(message->Get(), &error_message);
- js_bindings_->OnError(line_number, error_message);
+ js_bindings()->OnError(line_number, error_message);
}
// Compiles and runs |script| in the current V8 context.
@@ -584,7 +546,7 @@ class ProxyResolverV8::Context {
return v8::Undefined(); // toString() threw an exception.
}
- context->js_bindings_->Alert(message);
+ context->js_bindings()->Alert(message);
return v8::Undefined();
}
@@ -598,11 +560,10 @@ class ProxyResolverV8::Context {
{
v8::Unlocker unlocker(args.GetIsolate());
- ScopedHostResolve scoped_host_resolve(context);
-
// We shouldn't be called with any arguments, but will not complain if
// we are.
- success = context->js_bindings_->MyIpAddress(&result);
+ success = context->js_bindings()->ResolveDns(
+ "", JSBindings::MY_IP_ADDRESS, &result);
}
if (!success)
@@ -621,11 +582,10 @@ class ProxyResolverV8::Context {
{
v8::Unlocker unlocker(args.GetIsolate());
- ScopedHostResolve scoped_host_resolve(context);
-
// We shouldn't be called with any arguments, but will not complain if
// we are.
- success = context->js_bindings_->MyIpAddressEx(&ip_address_list);
+ success = context->js_bindings()->ResolveDns(
+ "", JSBindings::MY_IP_ADDRESS_EX, &ip_address_list);
}
if (!success)
@@ -648,8 +608,8 @@ class ProxyResolverV8::Context {
{
v8::Unlocker unlocker(args.GetIsolate());
- ScopedHostResolve scoped_host_resolve(context);
- success = context->js_bindings_->DnsResolve(hostname, &ip_address);
+ success = context->js_bindings()->ResolveDns(
+ hostname, JSBindings::DNS_RESOLVE, &ip_address);
}
return success ? ASCIIStringToV8String(ip_address) : v8::Null();
@@ -670,8 +630,8 @@ class ProxyResolverV8::Context {
{
v8::Unlocker unlocker(args.GetIsolate());
- ScopedHostResolve scoped_host_resolve(context);
- success = context->js_bindings_->DnsResolveEx(hostname, &ip_address_list);
+ success = context->js_bindings()->ResolveDns(
+ hostname, JSBindings::DNS_RESOLVE_EX, &ip_address_list);
}
if (!success)
@@ -714,18 +674,16 @@ class ProxyResolverV8::Context {
}
mutable base::Lock lock_;
- bool is_resolving_host_;
- ProxyResolverJSBindings* js_bindings_;
+ ProxyResolverV8* parent_;
v8::Persistent<v8::External> v8_this_;
v8::Persistent<v8::Context> v8_context_;
};
// ProxyResolverV8 ------------------------------------------------------------
-ProxyResolverV8::ProxyResolverV8(
- ProxyResolverJSBindings* custom_js_bindings)
+ProxyResolverV8::ProxyResolverV8()
: ProxyResolver(true /*expects_pac_bytes*/),
- js_bindings_(custom_js_bindings) {
+ js_bindings_(NULL) {
}
ProxyResolverV8::~ProxyResolverV8() {}
@@ -735,26 +693,15 @@ int ProxyResolverV8::GetProxyForURL(
const CompletionCallback& /*callback*/,
RequestHandle* /*request*/,
const BoundNetLog& net_log) {
+ DCHECK(js_bindings_);
+
// If the V8 instance has not been initialized (either because
// SetPacScript() wasn't called yet, or because it failed.
- if (!context_.get())
+ if (!context_)
return ERR_FAILED;
- // Associate some short-lived context with this request. This context will be
- // available to any of the javascript "bindings" that are subsequently invoked
- // from the javascript.
- //
- // In particular, we create a HostCache to aggressively cache failed DNS
- // resolves.
- const unsigned kMaxCacheEntries = 50;
- HostCache host_cache(kMaxCacheEntries);
-
- ProxyResolverRequestContext request_context(&net_log, &host_cache);
-
// Otherwise call into V8.
- context_->SetCurrentRequestContext(&request_context);
int rv = context_->ResolveProxy(query_url, results);
- context_->SetCurrentRequestContext(NULL);
return rv;
}
@@ -769,12 +716,6 @@ LoadState ProxyResolverV8::GetLoadState(RequestHandle request) const {
return LOAD_STATE_IDLE;
}
-LoadState ProxyResolverV8::GetLoadStateThreadSafe(RequestHandle request) const {
- if (context_->is_resolving_host())
- return LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT;
- return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
-}
-
void ProxyResolverV8::CancelSetPacScript() {
NOTREACHED();
}
@@ -783,20 +724,18 @@ void ProxyResolverV8::PurgeMemory() {
context_->PurgeMemory();
}
-void ProxyResolverV8::Shutdown() {
- js_bindings_->Shutdown();
-}
-
int ProxyResolverV8::SetPacScript(
const scoped_refptr<ProxyResolverScriptData>& script_data,
const CompletionCallback& /*callback*/) {
- DCHECK(script_data.get());
+ DCHECK(script_data);
+ DCHECK(js_bindings_);
+
context_.reset();
if (script_data->utf16().empty())
return ERR_PAC_SCRIPT_FAILED;
// Try parsing the PAC script.
- scoped_ptr<Context> context(new Context(js_bindings_.get()));
+ scoped_ptr<Context> context(new Context(this));
int rv = context->InitV8(script_data);
if (rv == OK)
context_.reset(context.release());
diff --git a/net/proxy/proxy_resolver_v8.h b/net/proxy/proxy_resolver_v8.h
index c00bb8a..a310460 100644
--- a/net/proxy/proxy_resolver_v8.h
+++ b/net/proxy/proxy_resolver_v8.h
@@ -12,8 +12,6 @@
namespace net {
-class ProxyResolverJSBindings;
-
// Implementation of ProxyResolver that uses V8 to evaluate PAC scripts.
//
// ----------------------------------------------------------------------------
@@ -34,14 +32,43 @@ class ProxyResolverJSBindings;
// and does not use locking since it expects to be alone.
class NET_EXPORT_PRIVATE ProxyResolverV8 : public ProxyResolver {
public:
- // Constructs a ProxyResolverV8 with custom bindings. ProxyResolverV8 takes
- // ownership of |custom_js_bindings| and deletes it when ProxyResolverV8
- // is destroyed.
- explicit ProxyResolverV8(ProxyResolverJSBindings* custom_js_bindings);
+ // Interface for the javascript bindings.
+ class NET_EXPORT_PRIVATE JSBindings {
+ public:
+ enum ResolveDnsOperation {
+ DNS_RESOLVE,
+ DNS_RESOLVE_EX,
+ MY_IP_ADDRESS,
+ MY_IP_ADDRESS_EX,
+ NUM_DNS_OPERATIONS,
+ };
+
+ JSBindings() {}
+
+ virtual ~JSBindings() {}
+
+ // Handler for "dnsResolve()", "dnsResolveEx()", "myIpAddress()",
+ // "myIpAddressEx()". Returns true on success and fills |*output| with the
+ // result.
+ virtual bool ResolveDns(const std::string& host,
+ ResolveDnsOperation op,
+ std::string* output) = 0;
+
+ // Handler for "alert(message)"
+ virtual void Alert(const string16& message) = 0;
+
+ // Handler for when an error is encountered. |line_number| may be -1
+ // if a line number is not applicable to this error.
+ virtual void OnError(int line_number, const string16& error) = 0;
+ };
+
+ // Constructs a ProxyResolverV8.
+ ProxyResolverV8();
virtual ~ProxyResolverV8();
- ProxyResolverJSBindings* js_bindings() const { return js_bindings_.get(); }
+ JSBindings* js_bindings() const { return js_bindings_; }
+ void set_js_bindings(JSBindings* js_bindings) { js_bindings_ = js_bindings; }
// ProxyResolver implementation:
virtual int GetProxyForURL(const GURL& url,
@@ -51,11 +78,8 @@ class NET_EXPORT_PRIVATE ProxyResolverV8 : public ProxyResolver {
const BoundNetLog& net_log) OVERRIDE;
virtual void CancelRequest(RequestHandle request) OVERRIDE;
virtual LoadState GetLoadState(RequestHandle request) const OVERRIDE;
- virtual LoadState GetLoadStateThreadSafe(
- RequestHandle request) const OVERRIDE;
virtual void CancelSetPacScript() OVERRIDE;
virtual void PurgeMemory() OVERRIDE;
- virtual void Shutdown() OVERRIDE;
virtual int SetPacScript(
const scoped_refptr<ProxyResolverScriptData>& script_data,
const net::CompletionCallback& /*callback*/) OVERRIDE;
@@ -65,9 +89,10 @@ class NET_EXPORT_PRIVATE ProxyResolverV8 : public ProxyResolver {
// script. It corresponds with the data from the last call to
// SetPacScript().
class Context;
+
scoped_ptr<Context> context_;
- scoped_ptr<ProxyResolverJSBindings> js_bindings_;
+ JSBindings* js_bindings_;
DISALLOW_COPY_AND_ASSIGN(ProxyResolverV8);
};
diff --git a/net/proxy/proxy_resolver_v8_tracing.cc b/net/proxy/proxy_resolver_v8_tracing.cc
new file mode 100644
index 0000000..ea32577
--- /dev/null
+++ b/net/proxy/proxy_resolver_v8_tracing.cc
@@ -0,0 +1,984 @@
+// Copyright (c) 2013 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_resolver_v8_tracing.h"
+
+#include "base/bind.h"
+#include "base/message_loop_proxy.h"
+#include "base/stringprintf.h"
+#include "base/synchronization/cancellation_flag.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/values.h"
+#include "net/base/address_list.h"
+#include "net/base/host_resolver.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_log.h"
+#include "net/proxy/proxy_info.h"
+#include "net/proxy/proxy_resolver_error_observer.h"
+#include "net/proxy/proxy_resolver_v8.h"
+
+// The intent of this class is explained in the design document:
+// https://docs.google.com/a/chromium.org/document/d/16Ij5OcVnR3s0MH4Z5XkhI9VTPoMJdaBn9rKreAmGOdE/edit
+//
+// In a nutshell, PAC scripts are Javascript programs and may depend on
+// network I/O, by calling functions like dnsResolve().
+//
+// This is problematic since functions such as dnsResolve() will block the
+// Javascript execution until the DNS result is availble, thereby stalling the
+// PAC thread, which hurts the ability to process parallel proxy resolves.
+// An obvious solution is to simply start more PAC threads, however this scales
+// poorly, which hurts the ability to process parallel proxy resolves.
+//
+// The solution in ProxyResolverV8Tracing is to model PAC scripts as being
+// deterministic, and depending only on the inputted URL. When the script
+// issues a dnsResolve() for a yet unresolved hostname, the Javascript
+// execution is "aborted", and then re-started once the DNS result is
+// known.
+namespace net {
+
+namespace {
+
+// Upper bound on how many *unique* DNS resolves a PAC script is allowed
+// to make. This is a failsafe both for scripts that do a ridiculous
+// number of DNS resolves, as well as scripts which are misbehaving
+// under the tracing optimization. It is not expected to hit this normally.
+const size_t kMaxUniqueResolveDnsPerExec = 20;
+
+// Approximate number of bytes to use for buffering alerts() and errors.
+// This is a failsafe in case repeated executions of the script causes
+// too much memory bloat. It is not expected for well behaved scripts to
+// hit this. (In fact normal scripts should not even have alerts() or errors).
+const size_t kMaxAlertsAndErrorsBytes = 2048;
+
+// Returns event parameters for a PAC error message (line number + message).
+base::Value* NetLogErrorCallback(int line_number,
+ const string16* message,
+ NetLog::LogLevel /* log_level */) {
+ base::DictionaryValue* dict = new base::DictionaryValue();
+ dict->SetInteger("line_number", line_number);
+ dict->SetString("message", *message);
+ return dict;
+}
+
+} // namespace
+
+// The Job class is responsible for executing GetProxyForURL() and
+// SetPacScript(), since both of these operations share similar code.
+//
+// The DNS for these operations can operate in either blocking or
+// non-blocking mode. Blocking mode is used as a fallback when the PAC script
+// seems to be misbehaving under the tracing optimization.
+//
+// Note that this class runs on both the origin thread and a worker
+// thread. Most methods are expected to be used exclusively on one thread
+// or the other.
+//
+// The lifetime of Jobs does not exceed that of the ProxyResolverV8Tracing that
+// spawned it. Destruction might happen on either the origin thread or the
+// worker thread.
+class ProxyResolverV8Tracing::Job
+ : public base::RefCountedThreadSafe<ProxyResolverV8Tracing::Job>,
+ public ProxyResolverV8::JSBindings {
+ public:
+ // |parent| is non-owned. It is the ProxyResolverV8Tracing that spawned this
+ // Job, and must oulive it.
+ explicit Job(ProxyResolverV8Tracing* parent);
+
+ // Called from origin thread.
+ void StartSetPacScript(
+ const scoped_refptr<ProxyResolverScriptData>& script_data,
+ const CompletionCallback& callback);
+
+ // Called from origin thread.
+ void StartGetProxyForURL(const GURL& url,
+ ProxyInfo* results,
+ const BoundNetLog& net_log,
+ const CompletionCallback& callback);
+
+ // Called from origin thread.
+ void Cancel();
+
+ // Called from origin thread.
+ LoadState GetLoadState() const;
+
+ private:
+ typedef std::map<std::string, std::string> DnsCache;
+ friend class base::RefCountedThreadSafe<ProxyResolverV8Tracing::Job>;
+
+ enum Operation {
+ SET_PAC_SCRIPT,
+ GET_PROXY_FOR_URL,
+ };
+
+ struct AlertOrError {
+ bool is_alert;
+ int line_number;
+ string16 message;
+ };
+
+ ~Job();
+
+ void CheckIsOnWorkerThread() const;
+ void CheckIsOnOriginThread() const;
+
+ void SetCallback(const CompletionCallback& callback);
+ void ReleaseCallback();
+
+ ProxyResolverV8* v8_resolver();
+ MessageLoop* worker_loop();
+ HostResolver* host_resolver();
+ ProxyResolverErrorObserver* error_observer();
+ NetLog* net_log();
+
+ // Invokes the user's callback.
+ void NotifyCaller(int result);
+ void NotifyCallerOnOriginLoop(int result);
+
+ void Start(Operation op, bool blocking_dns,
+ const CompletionCallback& callback);
+
+ void ExecuteBlocking();
+ void ExecuteNonBlocking();
+ int ExecuteProxyResolver();
+
+ // Implementation of ProxyResolverv8::JSBindings
+ virtual bool ResolveDns(const std::string& host,
+ ResolveDnsOperation op,
+ std::string* output) OVERRIDE;
+ virtual void Alert(const string16& message) OVERRIDE;
+ virtual void OnError(int line_number, const string16& error) OVERRIDE;
+
+ bool ResolveDnsBlocking(const std::string& host,
+ ResolveDnsOperation op,
+ std::string* output);
+
+ bool ResolveDnsNonBlocking(const std::string& host,
+ ResolveDnsOperation op,
+ std::string* output);
+
+ void DoDnsOperation(const std::string& host, ResolveDnsOperation op,
+ bool* out_cache_hit);
+ void OnDnsOperationComplete(int result);
+
+ void ScheduleRestartWithBlockingDns();
+
+ bool GetDnsFromLocalCache(const std::string& host, ResolveDnsOperation op,
+ std::string* output, bool* return_value);
+
+ void SaveDnsToLocalCache(const std::string& host, ResolveDnsOperation op,
+ int net_error, const net::AddressList& addresses);
+
+ // Builds a RequestInfo to service the specified PAC DNS operation.
+ static HostResolver::RequestInfo MakeDnsRequestInfo(const std::string& host,
+ ResolveDnsOperation op);
+
+ // Makes a key for looking up |host, op| in |dns_cache_|. Strings are used for
+ // convenience, to avoid defining custom comparators.
+ static std::string MakeDnsCacheKey(const std::string& host,
+ ResolveDnsOperation op);
+
+ void HandleAlertOrError(bool is_alert, int line_number,
+ const string16& message);
+ void DispatchBufferedAlertsAndErrors();
+ void DispatchAlertOrError(bool is_alert, int line_number,
+ const string16& message);
+
+ void LogEventToCurrentRequestAndGlobally(
+ NetLog::EventType type,
+ const NetLog::ParametersCallback& parameters_callback);
+
+ // The thread which called into ProxyResolverV8Tracing, and on which the
+ // completion callback is expected to run.
+ scoped_refptr<base::MessageLoopProxy> origin_loop_;
+
+ // The ProxyResolverV8Tracing which spawned this Job.
+ // Initialized on origin thread and then accessed from both threads.
+ ProxyResolverV8Tracing* parent_;
+
+ // The callback to run (on the origin thread) when the Job finishes.
+ // Should only be accessed from origin thread.
+ CompletionCallback callback_;
+
+ // Flag to indicate whether the request has been cancelled.
+ base::CancellationFlag cancelled_;
+
+ // The operation that this Job is running.
+ // Initialized on origin thread and then accessed from both threads.
+ Operation operation_;
+
+ // The DNS mode for this Job.
+ // Initialized on origin thread, mutated on worker thread, and accessed
+ // by both the origin thread and worker thread.
+ bool blocking_dns_;
+
+ // Used to block the worker thread on a DNS operation taking place on the
+ // origin thread.
+ base::WaitableEvent event_;
+
+ // Map of DNS operations completed so far. Written into on the origin thread
+ // and read on the worker thread.
+ DnsCache dns_cache_;
+
+ // The job holds a reference to itself to ensure that it remains alive until
+ // either completion or cancellation.
+ scoped_refptr<Job> owned_self_reference_;
+
+ // -------------------------------------------------------
+ // State specific to SET_PAC_SCRIPT.
+ // -------------------------------------------------------
+
+ scoped_refptr<ProxyResolverScriptData> script_data_;
+
+ // -------------------------------------------------------
+ // State specific to GET_PROXY_FOR_URL.
+ // -------------------------------------------------------
+
+ ProxyInfo* user_results_; // Owned by caller, lives on origin thread.
+ GURL url_;
+ ProxyInfo results_;
+ BoundNetLog bound_net_log_;
+
+ // ---------------------------------------------------------------------------
+ // State for ExecuteNonBlocking()
+ // ---------------------------------------------------------------------------
+ // These variables are used exclusively on the worker thread and are only
+ // meaningful when executing inside of ExecuteNonBlocking().
+
+ // Whether this execution was abandoned due to a missing DNS dependency.
+ bool abandoned_;
+
+ // Number of calls made to ResolveDns() by this execution.
+ int num_dns_;
+
+ // Sequence of calls made to Alert() or OnError() by this execution.
+ std::vector<AlertOrError> alerts_and_errors_;
+ size_t alerts_and_errors_byte_cost_; // Approximate byte cost of the above.
+
+ // Number of calls made to ResolveDns() by the PREVIOUS execution.
+ int last_num_dns_;
+
+ // Whether the current execution needs to be restarted in blocking mode.
+ bool should_restart_with_blocking_dns_;
+
+ // ---------------------------------------------------------------------------
+ // State for pending DNS request.
+ // ---------------------------------------------------------------------------
+ // These variables are used exclusively on the origin thread.
+
+ HostResolver::RequestHandle pending_dns_;
+ // Only meaningful when |pending_dns_|:
+ std::string pending_dns_host_;
+ ResolveDnsOperation pending_dns_op_;
+ AddressList pending_dns_addresses_;
+};
+
+ProxyResolverV8Tracing::Job::Job(ProxyResolverV8Tracing* parent)
+ : origin_loop_(base::MessageLoopProxy::current()),
+ parent_(parent),
+ event_(true, false),
+ last_num_dns_(0),
+ pending_dns_(NULL) {
+ CheckIsOnOriginThread();
+}
+
+void ProxyResolverV8Tracing::Job::StartSetPacScript(
+ const scoped_refptr<ProxyResolverScriptData>& script_data,
+ const CompletionCallback& callback) {
+ CheckIsOnOriginThread();
+
+ script_data_ = script_data;
+
+ // Script initialization uses blocking DNS since there isn't any
+ // advantage to using non-blocking mode here. That is because the
+ // parent ProxyService can't submit any ProxyResolve requests until
+ // initialization has completed successfully!
+ Start(SET_PAC_SCRIPT, true /*blocking*/, callback);
+}
+
+void ProxyResolverV8Tracing::Job::StartGetProxyForURL(
+ const GURL& url,
+ ProxyInfo* results,
+ const BoundNetLog& net_log,
+ const CompletionCallback& callback) {
+ CheckIsOnOriginThread();
+
+ url_ = url;
+ user_results_ = results;
+ bound_net_log_ = net_log;
+
+ Start(GET_PROXY_FOR_URL, false /*non-blocking*/, callback);
+}
+
+void ProxyResolverV8Tracing::Job::Cancel() {
+ CheckIsOnOriginThread();
+
+ // There are several possibilities to consider for cancellation:
+ // (a) The job has been posted to the worker thread, however script execution
+ // has not yet started.
+ // (b) The script is executing on the worker thread.
+ // (c) The script is executing on the worker thread, however is blocked inside
+ // of dnsResolve() waiting for a response from the origin thread.
+ // (d) Nothing is running on the worker thread, however the host resolver has
+ // a pending DNS request which upon completion will restart the script
+ // execution.
+ // (e) The worker thread has a pending task to restart execution, which was
+ // posted after the DNS dependency was resolved and saved to local cache.
+ // (f) The script execution completed entirely, and posted a task to the
+ // origin thread to notify the caller.
+ //
+ // |cancelled_| is read on both the origin thread and worker thread. The
+ // code that runs on the worker thread is littered with checks on
+ // |cancelled_| to break out early.
+ cancelled_.Set();
+
+ ReleaseCallback();
+
+ if (pending_dns_) {
+ host_resolver()->CancelRequest(pending_dns_);
+ pending_dns_ = NULL;
+ }
+
+ // The worker thread might be blocked waiting for DNS.
+ event_.Signal();
+
+ owned_self_reference_ = NULL;
+}
+
+LoadState ProxyResolverV8Tracing::Job::GetLoadState() const {
+ CheckIsOnOriginThread();
+
+ if (pending_dns_)
+ return LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT;
+
+ return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
+}
+
+ProxyResolverV8Tracing::Job::~Job() {
+ DCHECK(!pending_dns_);
+ DCHECK(callback_.is_null());
+}
+
+void ProxyResolverV8Tracing::Job::CheckIsOnWorkerThread() const {
+ DCHECK_EQ(MessageLoop::current(), parent_->thread_->message_loop());
+}
+
+void ProxyResolverV8Tracing::Job::CheckIsOnOriginThread() const {
+ DCHECK(origin_loop_->BelongsToCurrentThread());
+}
+
+void ProxyResolverV8Tracing::Job::SetCallback(
+ const CompletionCallback& callback) {
+ CheckIsOnOriginThread();
+ DCHECK(callback_.is_null());
+ parent_->num_outstanding_callbacks_++;
+ callback_ = callback;
+}
+
+void ProxyResolverV8Tracing::Job::ReleaseCallback() {
+ CheckIsOnOriginThread();
+ DCHECK(!callback_.is_null());
+ CHECK_GT(parent_->num_outstanding_callbacks_, 0);
+ parent_->num_outstanding_callbacks_--;
+ callback_.Reset();
+
+ // For good measure, clear this other user-owned pointer.
+ user_results_ = NULL;
+}
+
+ProxyResolverV8* ProxyResolverV8Tracing::Job::v8_resolver() {
+ return parent_->v8_resolver_.get();
+}
+
+MessageLoop* ProxyResolverV8Tracing::Job::worker_loop() {
+ return parent_->thread_->message_loop();
+}
+
+HostResolver* ProxyResolverV8Tracing::Job::host_resolver() {
+ return parent_->host_resolver_;
+}
+
+ProxyResolverErrorObserver* ProxyResolverV8Tracing::Job::error_observer() {
+ return parent_->error_observer_.get();
+}
+
+NetLog* ProxyResolverV8Tracing::Job::net_log() {
+ return parent_->net_log_;
+}
+
+void ProxyResolverV8Tracing::Job::NotifyCaller(int result) {
+ CheckIsOnWorkerThread();
+
+ origin_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&Job::NotifyCallerOnOriginLoop, this, result));
+}
+
+void ProxyResolverV8Tracing::Job::NotifyCallerOnOriginLoop(int result) {
+ CheckIsOnOriginThread();
+
+ if (cancelled_.IsSet())
+ return;
+
+ DCHECK(!callback_.is_null());
+ DCHECK(!pending_dns_);
+
+ if (operation_ == GET_PROXY_FOR_URL)
+ *user_results_ = results_;
+
+ // There is only ever 1 outstanding SET_PAC_SCRIPT job. It needs to be
+ // tracked to support cancellation.
+ if (operation_ == SET_PAC_SCRIPT) {
+ DCHECK_EQ(parent_->set_pac_script_job_.get(), this);
+ parent_->set_pac_script_job_ = NULL;
+ }
+
+ CompletionCallback callback = callback_;
+ ReleaseCallback();
+ callback.Run(result);
+
+ owned_self_reference_ = NULL;
+}
+
+void ProxyResolverV8Tracing::Job::Start(Operation op, bool blocking_dns,
+ const CompletionCallback& callback) {
+ CheckIsOnOriginThread();
+
+ operation_ = op;
+ blocking_dns_ = blocking_dns;
+ SetCallback(callback);
+
+ owned_self_reference_ = this;
+
+ worker_loop()->PostTask(FROM_HERE,
+ blocking_dns_ ? base::Bind(&Job::ExecuteBlocking, this) :
+ base::Bind(&Job::ExecuteNonBlocking, this));
+}
+
+void ProxyResolverV8Tracing::Job::ExecuteBlocking() {
+ CheckIsOnWorkerThread();
+ DCHECK(blocking_dns_);
+
+ if (cancelled_.IsSet())
+ return;
+
+ NotifyCaller(ExecuteProxyResolver());
+}
+
+void ProxyResolverV8Tracing::Job::ExecuteNonBlocking() {
+ CheckIsOnWorkerThread();
+ DCHECK(!blocking_dns_);
+
+ if (cancelled_.IsSet())
+ return;
+
+ // Reset state for the current execution.
+ abandoned_ = false;
+ num_dns_ = 0;
+ alerts_and_errors_.clear();
+ alerts_and_errors_byte_cost_ = 0;
+ should_restart_with_blocking_dns_ = false;
+
+ int result = ExecuteProxyResolver();
+
+ if (should_restart_with_blocking_dns_) {
+ DCHECK(!blocking_dns_);
+ DCHECK(abandoned_);
+ blocking_dns_ = true;
+ ExecuteBlocking();
+ return;
+ }
+
+ if (abandoned_)
+ return;
+
+ DispatchBufferedAlertsAndErrors();
+ NotifyCaller(result);
+}
+
+int ProxyResolverV8Tracing::Job::ExecuteProxyResolver() {
+ JSBindings* prev_bindings = v8_resolver()->js_bindings();
+ v8_resolver()->set_js_bindings(this);
+
+ int result = ERR_UNEXPECTED; // Initialized to silence warnings.
+
+ switch (operation_) {
+ case SET_PAC_SCRIPT:
+ result = v8_resolver()->SetPacScript(
+ script_data_, CompletionCallback());
+ break;
+ case GET_PROXY_FOR_URL:
+ result = v8_resolver()->GetProxyForURL(
+ url_,
+ // Important: Do not write directly into |user_results_|, since if the
+ // request were to be cancelled from the origin thread, must guarantee
+ // that |user_results_| is not accessed anymore.
+ &results_,
+ CompletionCallback(),
+ NULL,
+ bound_net_log_);
+ break;
+ }
+
+ v8_resolver()->set_js_bindings(prev_bindings);
+ return result;
+}
+
+bool ProxyResolverV8Tracing::Job::ResolveDns(const std::string& host,
+ ResolveDnsOperation op,
+ std::string* output) {
+ if (cancelled_.IsSet())
+ return false;
+
+ if ((op == DNS_RESOLVE || op == DNS_RESOLVE_EX) && host.empty()) {
+ // a DNS resolve with an empty hostname is considered an error.
+ return false;
+ }
+
+ return blocking_dns_ ?
+ ResolveDnsBlocking(host, op, output) :
+ ResolveDnsNonBlocking(host, op, output);
+}
+
+void ProxyResolverV8Tracing::Job::Alert(const string16& message) {
+ HandleAlertOrError(true, -1, message);
+}
+
+void ProxyResolverV8Tracing::Job::OnError(int line_number,
+ const string16& error) {
+ HandleAlertOrError(false, line_number, error);
+}
+
+bool ProxyResolverV8Tracing::Job::ResolveDnsBlocking(const std::string& host,
+ ResolveDnsOperation op,
+ std::string* output) {
+ CheckIsOnWorkerThread();
+
+ // Check if the DNS result for this host has already been cached.
+ bool rv;
+ if (GetDnsFromLocalCache(host, op, output, &rv)) {
+ // Yay, cache hit!
+ return rv;
+ }
+
+ // If the host was not in the local cache, this is a new hostname.
+
+ if (dns_cache_.size() >= kMaxUniqueResolveDnsPerExec) {
+ // Safety net for scripts with unexpectedly many DNS calls.
+ // We will continue running to completion, but will fail every
+ // subsequent DNS request.
+ return false;
+ }
+
+ bool unused;
+ origin_loop_->PostTask(
+ FROM_HERE, base::Bind(&Job::DoDnsOperation, this, host, op, &unused));
+
+ // Wait for the DNS operation to be completed by the host resolver on the
+ // origin thread. After waking up, either the request was cancelled, or
+ // the DNS result is now available in the cache.
+ event_.Wait();
+ event_.Reset();
+
+ if (cancelled_.IsSet())
+ return false;
+
+ CHECK(GetDnsFromLocalCache(host, op, output, &rv));
+ return rv;
+}
+
+bool ProxyResolverV8Tracing::Job::ResolveDnsNonBlocking(const std::string& host,
+ ResolveDnsOperation op,
+ std::string* output) {
+ CheckIsOnWorkerThread();
+
+ if (abandoned_) {
+ // If this execution was already abandoned can fail right away. Only 1 DNS
+ // dependency will be traced at a time (for more predictable outcomes).
+ return false;
+ }
+
+ num_dns_ += 1;
+
+ // Check if the DNS result for this host has already been cached.
+ bool rv;
+ if (GetDnsFromLocalCache(host, op, output, &rv)) {
+ // Yay, cache hit!
+ return rv;
+ }
+
+ // If the host was not in the local cache, then this is a new hostname.
+
+ if (num_dns_ <= last_num_dns_) {
+ // The sequence of DNS operations is different from last time!
+ ScheduleRestartWithBlockingDns();
+ return false;
+ }
+
+ if (dns_cache_.size() >= kMaxUniqueResolveDnsPerExec) {
+ // Safety net for scripts with unexpectedly many DNS calls.
+ return false;
+ }
+
+ DCHECK(!should_restart_with_blocking_dns_);
+
+ // Post the DNS request to the origin thread.
+ bool resolver_cache_hit = false;
+ origin_loop_->PostTask(
+ FROM_HERE, base::Bind(&Job::DoDnsOperation, this, host, op,
+ &resolver_cache_hit));
+
+ // As an optimization to avoid restarting too often, wait until the
+ // resolver's cache has been inspected on the origin thread.
+ event_.Wait();
+ event_.Reset();
+
+ if (cancelled_.IsSet())
+ return false;
+
+ if (resolver_cache_hit) {
+ CHECK(GetDnsFromLocalCache(host, op, output, &rv));
+ return rv;
+ }
+
+ // Otherwise if the result was not in the cache, then a DNS request has
+ // been started. Abandon this invocation of FindProxyForURL(), it will be
+ // restarted once the DNS request completes.
+ abandoned_ = true;
+ last_num_dns_ = num_dns_;
+ return false;
+}
+
+void ProxyResolverV8Tracing::Job::DoDnsOperation(
+ const std::string& host, ResolveDnsOperation op, bool* out_cache_hit) {
+ CheckIsOnOriginThread();
+ DCHECK(!pending_dns_);
+
+ if (cancelled_.IsSet())
+ return;
+
+ int result = host_resolver()->Resolve(
+ MakeDnsRequestInfo(host, op),
+ &pending_dns_addresses_,
+ base::Bind(&Job::OnDnsOperationComplete, this),
+ &pending_dns_,
+ bound_net_log_);
+
+ bool completed_synchronously = result != ERR_IO_PENDING;
+
+ if (!blocking_dns_) {
+ // Check if the DNS result can be serviced directly from the cache.
+ // (The worker thread is blocked waiting for this information).
+ if (completed_synchronously) {
+ SaveDnsToLocalCache(host, op, result, pending_dns_addresses_);
+ pending_dns_ = NULL;
+ }
+
+ // Important: Do not read/write |out_cache_hit| after signalling, since
+ // the memory may no longer be valid.
+ *out_cache_hit = completed_synchronously;
+ event_.Signal();
+
+ if (completed_synchronously)
+ return;
+ }
+
+ pending_dns_host_ = host;
+ pending_dns_op_ = op;
+
+ if (completed_synchronously)
+ OnDnsOperationComplete(result);
+}
+
+void ProxyResolverV8Tracing::Job::OnDnsOperationComplete(int result) {
+ CheckIsOnOriginThread();
+
+ DCHECK(pending_dns_);
+ DCHECK(!cancelled_.IsSet());
+
+ SaveDnsToLocalCache(pending_dns_host_, pending_dns_op_, result,
+ pending_dns_addresses_);
+ pending_dns_ = NULL;
+
+ if (!blocking_dns_) {
+ // Restart. This time it should make more progress due to having
+ // cached items.
+ worker_loop()->PostTask(FROM_HERE,
+ base::Bind(&Job::ExecuteNonBlocking, this));
+ } else {
+ // Otherwise wakeup the blocked worker thread.
+ event_.Signal();
+ }
+}
+
+void ProxyResolverV8Tracing::Job::ScheduleRestartWithBlockingDns() {
+ CheckIsOnWorkerThread();
+
+ DCHECK(!should_restart_with_blocking_dns_);
+ DCHECK(!abandoned_);
+ DCHECK(!blocking_dns_);
+
+ abandoned_ = true;
+
+ // The restart will happen after ExecuteNonBlocking() finishes.
+ should_restart_with_blocking_dns_ = true;
+}
+
+bool ProxyResolverV8Tracing::Job::GetDnsFromLocalCache(
+ const std::string& host,
+ ResolveDnsOperation op,
+ std::string* output,
+ bool* return_value) {
+ CheckIsOnWorkerThread();
+
+ DnsCache::const_iterator it = dns_cache_.find(MakeDnsCacheKey(host, op));
+ if (it == dns_cache_.end())
+ return false;
+
+ *output = it->second;
+ *return_value = !it->second.empty();
+ return true;
+}
+
+void ProxyResolverV8Tracing::Job::SaveDnsToLocalCache(
+ const std::string& host,
+ ResolveDnsOperation op,
+ int net_error,
+ const net::AddressList& addresses) {
+ CheckIsOnOriginThread();
+
+ // Serialize the result into a string to save to the cache.
+ std::string cache_value;
+ if (net_error != OK) {
+ cache_value = std::string();
+ } else if (op == DNS_RESOLVE || op == MY_IP_ADDRESS) {
+ // dnsResolve() and myIpAddress() are expected to return a single IP
+ // address.
+ cache_value = addresses.front().ToStringWithoutPort();
+ } else {
+ // The *Ex versions are expected to return a semi-colon separated list.
+ for (AddressList::const_iterator iter = addresses.begin();
+ iter != addresses.end(); ++iter) {
+ if (!cache_value.empty())
+ cache_value += ";";
+ cache_value += iter->ToStringWithoutPort();
+ }
+ }
+
+ dns_cache_[MakeDnsCacheKey(host, op)] = cache_value;
+}
+
+// static
+HostResolver::RequestInfo ProxyResolverV8Tracing::Job::MakeDnsRequestInfo(
+ const std::string& host, ResolveDnsOperation op) {
+ HostPortPair host_port = HostPortPair(host, 80);
+ if (op == MY_IP_ADDRESS || op == MY_IP_ADDRESS_EX) {
+ host_port.set_host(GetHostName());
+ }
+
+ HostResolver::RequestInfo info(host_port);
+
+ // The non-ex flavors are limited to IPv4 results.
+ if (op == MY_IP_ADDRESS || op == DNS_RESOLVE) {
+ info.set_address_family(ADDRESS_FAMILY_IPV4);
+ }
+
+ return info;
+}
+
+std::string ProxyResolverV8Tracing::Job::MakeDnsCacheKey(
+ const std::string& host, ResolveDnsOperation op) {
+ return StringPrintf("%d:%s", op, host.c_str());
+}
+
+void ProxyResolverV8Tracing::Job::HandleAlertOrError(bool is_alert,
+ int line_number,
+ const string16& message) {
+ CheckIsOnWorkerThread();
+
+ if (cancelled_.IsSet())
+ return;
+
+ if (blocking_dns_) {
+ // In blocking DNS mode the events can be dispatched immediately.
+ DispatchAlertOrError(is_alert, line_number, message);
+ return;
+ }
+
+ // Otherwise in nonblocking mode, buffer all the messages until
+ // the end.
+
+ if (abandoned_)
+ return;
+
+ alerts_and_errors_byte_cost_ += sizeof(AlertOrError) + message.size() * 2;
+
+ // If there have been lots of messages, enqueing could be expensive on
+ // memory. Consider a script which does megabytes worth of alerts().
+ // Avoid this by falling back to blocking mode.
+ if (alerts_and_errors_byte_cost_ > kMaxAlertsAndErrorsBytes) {
+ ScheduleRestartWithBlockingDns();
+ return;
+ }
+
+ AlertOrError entry = {is_alert, line_number, message};
+ alerts_and_errors_.push_back(entry);
+}
+
+void ProxyResolverV8Tracing::Job::DispatchBufferedAlertsAndErrors() {
+ CheckIsOnWorkerThread();
+ DCHECK(!blocking_dns_);
+ DCHECK(!abandoned_);
+
+ for (size_t i = 0; i < alerts_and_errors_.size(); ++i) {
+ const AlertOrError& x = alerts_and_errors_[i];
+ DispatchAlertOrError(x.is_alert, x.line_number, x.message);
+ }
+}
+
+void ProxyResolverV8Tracing::Job::DispatchAlertOrError(
+ bool is_alert, int line_number, const string16& message) {
+ CheckIsOnWorkerThread();
+
+ // Note that the handling of cancellation is racy with regard to
+ // alerts/errors. The request might get cancelled shortly after this
+ // check! (There is no lock being held to guarantee otherwise).
+ //
+ // If this happens, then some information will get written to the NetLog
+ // needlessly, however the NetLog will still be alive so it shouldn't cause
+ // problems.
+ if (cancelled_.IsSet())
+ return;
+
+ if (is_alert) {
+ // -------------------
+ // alert
+ // -------------------
+ VLOG(1) << "PAC-alert: " << message;
+
+ // Send to the NetLog.
+ LogEventToCurrentRequestAndGlobally(
+ NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
+ NetLog::StringCallback("message", &message));
+ } else {
+ // -------------------
+ // error
+ // -------------------
+ if (line_number == -1)
+ VLOG(1) << "PAC-error: " << message;
+ else
+ VLOG(1) << "PAC-error: " << "line: " << line_number << ": " << message;
+
+ // Send the error to the NetLog.
+ LogEventToCurrentRequestAndGlobally(
+ NetLog::TYPE_PAC_JAVASCRIPT_ERROR,
+ base::Bind(&NetLogErrorCallback, line_number, &message));
+
+ if (error_observer())
+ error_observer()->OnPACScriptError(line_number, message);
+ }
+}
+
+void ProxyResolverV8Tracing::Job::LogEventToCurrentRequestAndGlobally(
+ NetLog::EventType type,
+ const NetLog::ParametersCallback& parameters_callback) {
+ CheckIsOnWorkerThread();
+ bound_net_log_.AddEvent(type, parameters_callback);
+
+ // Emit to the global NetLog event stream.
+ if (net_log())
+ net_log()->AddGlobalEntry(type, parameters_callback);
+}
+
+ProxyResolverV8Tracing::ProxyResolverV8Tracing(
+ HostResolver* host_resolver,
+ ProxyResolverErrorObserver* error_observer,
+ NetLog* net_log)
+ : ProxyResolver(true /*expects_pac_bytes*/),
+ host_resolver_(host_resolver),
+ error_observer_(error_observer),
+ net_log_(net_log),
+ num_outstanding_callbacks_(0) {
+ DCHECK(host_resolver);
+ // Start up the thread.
+ thread_.reset(new base::Thread("Proxy resolver"));
+ CHECK(thread_->Start());
+
+ v8_resolver_.reset(new ProxyResolverV8);
+}
+
+ProxyResolverV8Tracing::~ProxyResolverV8Tracing() {
+ // Note, all requests should have been cancelled.
+ CHECK(!set_pac_script_job_);
+ CHECK_EQ(0, num_outstanding_callbacks_);
+
+ // Join the worker thread.
+ // See http://crbug.com/69710.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+ thread_.reset();
+}
+
+int ProxyResolverV8Tracing::GetProxyForURL(const GURL& url,
+ ProxyInfo* results,
+ const CompletionCallback& callback,
+ RequestHandle* request,
+ const BoundNetLog& net_log) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(!callback.is_null());
+ DCHECK(!set_pac_script_job_);
+
+ scoped_refptr<Job> job = new Job(this);
+
+ if (request)
+ *request = job.get();
+
+ job->StartGetProxyForURL(url, results, net_log, callback);
+ return ERR_IO_PENDING;
+}
+
+void ProxyResolverV8Tracing::CancelRequest(RequestHandle request) {
+ Job* job = reinterpret_cast<Job*>(request);
+ job->Cancel();
+}
+
+LoadState ProxyResolverV8Tracing::GetLoadState(RequestHandle request) const {
+ Job* job = reinterpret_cast<Job*>(request);
+ return job->GetLoadState();
+}
+
+void ProxyResolverV8Tracing::CancelSetPacScript() {
+ DCHECK(set_pac_script_job_);
+ set_pac_script_job_->Cancel();
+ set_pac_script_job_ = NULL;
+}
+
+void ProxyResolverV8Tracing::PurgeMemory() {
+ thread_->message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&ProxyResolverV8::PurgeMemory,
+ // The use of unretained is safe, since the worker thread
+ // cannot outlive |this|.
+ base::Unretained(v8_resolver_.get())));
+}
+
+int ProxyResolverV8Tracing::SetPacScript(
+ const scoped_refptr<ProxyResolverScriptData>& script_data,
+ const CompletionCallback& callback) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(!callback.is_null());
+
+ // Note that there should not be any outstanding (non-cancelled) Jobs when
+ // setting the PAC script (ProxyService should guarantee this). If there are,
+ // then they might complete in strange ways after the new script is set.
+ DCHECK(!set_pac_script_job_);
+ CHECK_EQ(0, num_outstanding_callbacks_);
+
+ set_pac_script_job_ = new Job(this);
+ set_pac_script_job_->StartSetPacScript(script_data, callback);
+
+ return ERR_IO_PENDING;
+}
+
+} // namespace net
diff --git a/net/proxy/proxy_resolver_v8_tracing.h b/net/proxy/proxy_resolver_v8_tracing.h
new file mode 100644
index 0000000..5877aa2
--- /dev/null
+++ b/net/proxy/proxy_resolver_v8_tracing.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2013 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_PROXY_RESOLVER_V8_TRACING_H_
+#define NET_PROXY_PROXY_RESOLVER_V8_TRACING_H_
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/non_thread_safe.h"
+#include "net/base/net_export.h"
+#include "net/proxy/proxy_resolver.h"
+
+namespace base {
+class Thread;
+class MessageLoopProxy;
+} // namespace base
+
+namespace net {
+
+class HostResolver;
+class NetLog;
+class ProxyResolverErrorObserver;
+class ProxyResolverV8;
+
+// ProxyResolverV8Tracing is a non-blocking ProxyResolver. It executes
+// ProxyResolverV8 on a single helper thread, and does some magic to avoid
+// blocking in DNS. For more details see the design document:
+// https://docs.google.com/a/google.com/document/d/16Ij5OcVnR3s0MH4Z5XkhI9VTPoMJdaBn9rKreAmGOdE/edit?pli=1
+class NET_EXPORT_PRIVATE ProxyResolverV8Tracing
+ : public ProxyResolver,
+ NON_EXPORTED_BASE(public base::NonThreadSafe) {
+ public:
+ // Constructs a ProxyResolver that will issue DNS requests through
+ // |host_resolver|, forward Javascript errors through |error_observer|, and
+ // log Javascript errors and alerts to |net_log|.
+ //
+ // Note that the constructor takes ownership of |error_observer|, whereas
+ // |host_resolver| and |net_log| are expected to outlive |this|.
+ ProxyResolverV8Tracing(HostResolver* host_resolver,
+ ProxyResolverErrorObserver* error_observer,
+ NetLog* net_log);
+
+ virtual ~ProxyResolverV8Tracing();
+
+ // ProxyResolver implementation:
+ virtual int GetProxyForURL(const GURL& url,
+ ProxyInfo* results,
+ const CompletionCallback& callback,
+ RequestHandle* request,
+ const BoundNetLog& net_log) OVERRIDE;
+ virtual void CancelRequest(RequestHandle request) OVERRIDE;
+ virtual LoadState GetLoadState(RequestHandle request) const OVERRIDE;
+ virtual void CancelSetPacScript() OVERRIDE;
+ virtual void PurgeMemory() OVERRIDE;
+ virtual int SetPacScript(
+ const scoped_refptr<ProxyResolverScriptData>& script_data,
+ const CompletionCallback& callback) OVERRIDE;
+
+ private:
+ class Job;
+
+ // The worker thread on which the ProxyResolverV8 will be run.
+ scoped_ptr<base::Thread> thread_;
+ scoped_ptr<ProxyResolverV8> v8_resolver_;
+
+ // Non-owned host resolver, which is to be operated on the origin thread.
+ HostResolver* host_resolver_;
+
+ scoped_ptr<ProxyResolverErrorObserver> error_observer_;
+ NetLog* net_log_;
+
+ // The outstanding SetPacScript operation, or NULL.
+ scoped_refptr<Job> set_pac_script_job_;
+
+ // The number of outstanding (non-cancelled) jobs.
+ int num_outstanding_callbacks_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProxyResolverV8Tracing);
+};
+
+} // namespace net
+
+#endif // NET_PROXY_PROXY_RESOLVER_V8_TRACING_H_
diff --git a/net/proxy/proxy_resolver_v8_tracing_unittest.cc b/net/proxy/proxy_resolver_v8_tracing_unittest.cc
new file mode 100644
index 0000000..36e6087
--- /dev/null
+++ b/net/proxy/proxy_resolver_v8_tracing_unittest.cc
@@ -0,0 +1,928 @@
+// Copyright (c) 2013 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_resolver_v8_tracing.h"
+
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/stl_util.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/host_cache.h"
+#include "net/base/mock_host_resolver.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_log.h"
+#include "net/base/net_log_unittest.h"
+#include "net/base/test_completion_callback.h"
+#include "net/proxy/proxy_info.h"
+#include "net/proxy/proxy_resolver_error_observer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+class ProxyResolverV8TracingTest : public testing::Test {
+ public:
+ virtual void TearDown() OVERRIDE {
+ // Drain any pending messages, which may be left over from cancellation.
+ // This way they get reliably run as part of the current test, rather than
+ // spilling into the next test's execution.
+ MessageLoop::current()->RunUntilIdle();
+ }
+};
+
+scoped_refptr<ProxyResolverScriptData> LoadScriptData(const char* filename) {
+ FilePath path;
+ PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ path = path.AppendASCII("net");
+ path = path.AppendASCII("data");
+ path = path.AppendASCII("proxy_resolver_v8_tracing_unittest");
+ path = path.AppendASCII(filename);
+
+ // Try to read the file from disk.
+ std::string file_contents;
+ bool ok = file_util::ReadFileToString(path, &file_contents);
+
+ // If we can't load the file from disk, something is misconfigured.
+ EXPECT_TRUE(ok) << "Failed to read file: " << path.value();
+
+ // Load the PAC script into the ProxyResolver.
+ return ProxyResolverScriptData::FromUTF8(file_contents);
+}
+
+void InitResolver(ProxyResolverV8Tracing* resolver, const char* filename) {
+ TestCompletionCallback callback;
+ int rv =
+ resolver->SetPacScript(LoadScriptData(filename), callback.callback());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback.WaitForResult());
+}
+
+class MockErrorObserver : public ProxyResolverErrorObserver {
+ public:
+ MockErrorObserver() : event_(true, false) {}
+
+ virtual void OnPACScriptError(int line_number,
+ const string16& error) OVERRIDE {
+ {
+ base::AutoLock l(lock_);
+ output += StringPrintf("Error: line %d: %s\n", line_number,
+ UTF16ToASCII(error).c_str());
+ }
+ event_.Signal();
+ }
+
+ std::string GetOutput() {
+ base::AutoLock l(lock_);
+ return output;
+ }
+
+ void WaitForOutput() {
+ event_.Wait();
+ }
+
+ private:
+ base::Lock lock_;
+ std::string output;
+
+ base::WaitableEvent event_;
+};
+
+TEST_F(ProxyResolverV8TracingTest, Simple) {
+ CapturingNetLog log;
+ CapturingBoundNetLog request_log;
+ MockCachingHostResolver host_resolver;
+ MockErrorObserver* error_observer = new MockErrorObserver;
+ ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
+
+ InitResolver(&resolver, "simple.js");
+
+ TestCompletionCallback callback;
+ ProxyInfo proxy_info;
+
+ int rv = resolver.GetProxyForURL(
+ GURL("http://foo/"), &proxy_info, callback.callback(),
+ NULL, request_log.bound());
+
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback.WaitForResult());
+
+ EXPECT_EQ("foo:99", proxy_info.proxy_server().ToURI());
+
+ EXPECT_EQ(0u, host_resolver.num_resolve());
+
+ // There were no errors.
+ EXPECT_EQ("", error_observer->GetOutput());
+
+ // Check the NetLogs -- nothing was logged.
+ EXPECT_EQ(0u, log.GetSize());
+ EXPECT_EQ(0u, request_log.GetSize());
+}
+
+TEST_F(ProxyResolverV8TracingTest, JavascriptError) {
+ CapturingNetLog log;
+ CapturingBoundNetLog request_log;
+ MockCachingHostResolver host_resolver;
+ MockErrorObserver* error_observer = new MockErrorObserver;
+ ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
+
+ InitResolver(&resolver, "error.js");
+
+ TestCompletionCallback callback;
+ ProxyInfo proxy_info;
+
+ int rv = resolver.GetProxyForURL(
+ GURL("http://throw-an-error/"), &proxy_info, callback.callback(), NULL,
+ request_log.bound());
+
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult());
+
+ EXPECT_EQ(0u, host_resolver.num_resolve());
+
+ EXPECT_EQ("Error: line 5: Uncaught TypeError: Cannot call method 'split' "
+ "of null\n", error_observer->GetOutput());
+
+ // Check the NetLogs -- there was 1 alert and 1 javascript error, and they
+ // were output to both the global log, and per-request log.
+ CapturingNetLog::CapturedEntryList entries_list[2];
+ log.GetEntries(&entries_list[0]);
+ request_log.GetEntries(&entries_list[1]);
+
+ for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
+ const CapturingNetLog::CapturedEntryList& entries = entries_list[list_i];
+ EXPECT_EQ(2u, entries.size());
+ EXPECT_TRUE(
+ LogContainsEvent(entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
+ NetLog::PHASE_NONE));
+ EXPECT_TRUE(
+ LogContainsEvent(entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_ERROR,
+ NetLog::PHASE_NONE));
+
+ EXPECT_EQ("{\"message\":\"Prepare to DIE!\"}", entries[0].GetParamsJson());
+ EXPECT_EQ("{\"line_number\":5,\"message\":\"Uncaught TypeError: Cannot "
+ "call method 'split' of null\"}", entries[1].GetParamsJson());
+ }
+}
+
+TEST_F(ProxyResolverV8TracingTest, TooManyAlerts) {
+ CapturingNetLog log;
+ CapturingBoundNetLog request_log;
+ MockCachingHostResolver host_resolver;
+ MockErrorObserver* error_observer = new MockErrorObserver;
+ ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
+
+ InitResolver(&resolver, "too_many_alerts.js");
+
+ TestCompletionCallback callback;
+ ProxyInfo proxy_info;
+
+ int rv = resolver.GetProxyForURL(
+ GURL("http://foo/"),
+ &proxy_info,
+ callback.callback(),
+ NULL,
+ request_log.bound());
+
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback.WaitForResult());
+
+ // Iteration1 does a DNS resolve
+ // Iteration2 exceeds the alert buffer
+ // Iteration3 runs in blocking mode and completes
+ EXPECT_EQ("foo:3", proxy_info.proxy_server().ToURI());
+
+ EXPECT_EQ(1u, host_resolver.num_resolve());
+
+ // No errors.
+ EXPECT_EQ("", error_observer->GetOutput());
+
+ // Check the NetLogs -- the script generated 50 alerts, which were mirrored
+ // to both the global and per-request logs.
+ CapturingNetLog::CapturedEntryList entries_list[2];
+ log.GetEntries(&entries_list[0]);
+ request_log.GetEntries(&entries_list[1]);
+
+ for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
+ const CapturingNetLog::CapturedEntryList& entries = entries_list[list_i];
+ EXPECT_EQ(50u, entries.size());
+ for (size_t i = 0; i < entries.size(); ++i) {
+ ASSERT_TRUE(
+ LogContainsEvent(entries, i, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
+ NetLog::PHASE_NONE));
+ }
+ }
+}
+
+// Verify that buffered alerts cannot grow unboundedly, even when the message is
+// empty string.
+TEST_F(ProxyResolverV8TracingTest, TooManyEmptyAlerts) {
+ CapturingNetLog log;
+ CapturingBoundNetLog request_log;
+ MockCachingHostResolver host_resolver;
+ MockErrorObserver* error_observer = new MockErrorObserver;
+ ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
+
+ InitResolver(&resolver, "too_many_empty_alerts.js");
+
+ TestCompletionCallback callback;
+ ProxyInfo proxy_info;
+
+ int rv = resolver.GetProxyForURL(
+ GURL("http://foo/"),
+ &proxy_info,
+ callback.callback(),
+ NULL,
+ request_log.bound());
+
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback.WaitForResult());
+
+ EXPECT_EQ("foo:3", proxy_info.proxy_server().ToURI());
+
+ EXPECT_EQ(1u, host_resolver.num_resolve());
+
+ // No errors.
+ EXPECT_EQ("", error_observer->GetOutput());
+
+ // Check the NetLogs -- the script generated 50 alerts, which were mirrored
+ // to both the global and per-request logs.
+ CapturingNetLog::CapturedEntryList entries_list[2];
+ log.GetEntries(&entries_list[0]);
+ request_log.GetEntries(&entries_list[1]);
+
+ for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
+ const CapturingNetLog::CapturedEntryList& entries = entries_list[list_i];
+ EXPECT_EQ(1000u, entries.size());
+ for (size_t i = 0; i < entries.size(); ++i) {
+ ASSERT_TRUE(
+ LogContainsEvent(entries, i, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
+ NetLog::PHASE_NONE));
+ }
+ }
+}
+
+// This test runs a PAC script that issues a sequence of DNS resolves. The test
+// verifies the final result, and that the underlying DNS resolver received
+// the correct set of queries.
+TEST_F(ProxyResolverV8TracingTest, Dns) {
+ CapturingNetLog log;
+ CapturingBoundNetLog request_log;
+ MockCachingHostResolver host_resolver;
+ MockErrorObserver* error_observer = new MockErrorObserver;
+ ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
+
+ host_resolver.rules()->AddRuleForAddressFamily(
+ "host1", ADDRESS_FAMILY_IPV4, "166.155.144.44");
+ host_resolver.rules()->AddIPLiteralRule("host1", "::1,192.168.1.1", "");
+ host_resolver.rules()->AddSimulatedFailure("host2");
+ host_resolver.rules()->AddRule("host3", "166.155.144.33");
+ host_resolver.rules()->AddRule("host5", "166.155.144.55");
+ host_resolver.rules()->AddSimulatedFailure("host6");
+ host_resolver.rules()->AddRuleForAddressFamily(
+ "*", ADDRESS_FAMILY_IPV4, "122.133.144.155");
+ host_resolver.rules()->AddRule("*", "133.122.100.200");
+
+ InitResolver(&resolver, "dns.js");
+
+ TestCompletionCallback callback;
+ ProxyInfo proxy_info;
+
+ int rv = resolver.GetProxyForURL(
+ GURL("http://foo/"),
+ &proxy_info,
+ callback.callback(),
+ NULL,
+ request_log.bound());
+
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback.WaitForResult());
+
+ // The test does 13 DNS resolution, however only 7 of them are unique.
+ EXPECT_EQ(7u, host_resolver.num_resolve());
+
+ const char* kExpectedResult =
+ "122.133.144.155-" // myIpAddress()
+ "null-" // dnsResolve('')
+ "__1_192.168.1.1-" // dnsResolveEx('host1')
+ "null-" // dnsResolve('host2')
+ "166.155.144.33-" // dnsResolve('host3')
+ "122.133.144.155-" // myIpAddress()
+ "166.155.144.33-" // dnsResolve('host3')
+ "__1_192.168.1.1-" // dnsResolveEx('host1')
+ "122.133.144.155-" // myIpAddress()
+ "null-" // dnsResolve('host2')
+ "-" // dnsResolveEx('host6')
+ "133.122.100.200-" // myIpAddressEx()
+ "166.155.144.44" // dnsResolve('host1')
+ ":99";
+
+ EXPECT_EQ(kExpectedResult, proxy_info.proxy_server().ToURI());
+
+ // No errors.
+ EXPECT_EQ("", error_observer->GetOutput());
+
+ // Check the NetLogs -- the script generated 1 alert, mirrored to both
+ // the per-request and global logs.
+ CapturingNetLog::CapturedEntryList entries_list[2];
+ log.GetEntries(&entries_list[0]);
+ request_log.GetEntries(&entries_list[1]);
+
+ for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
+ const CapturingNetLog::CapturedEntryList& entries = entries_list[list_i];
+ EXPECT_EQ(1u, entries.size());
+ EXPECT_TRUE(
+ LogContainsEvent(entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
+ NetLog::PHASE_NONE));
+ EXPECT_EQ("{\"message\":\"iteration: 7\"}", entries[0].GetParamsJson());
+ }
+}
+
+// This test runs a PAC script that does "myIpAddress()" followed by
+// "dnsResolve()". This requires 2 restarts. However once the HostResolver's
+// cache is warmed, subsequent calls should take 0 restarts.
+TEST_F(ProxyResolverV8TracingTest, DnsChecksCache) {
+ CapturingNetLog log;
+ CapturingBoundNetLog request_log;
+ MockCachingHostResolver host_resolver;
+ MockErrorObserver* error_observer = new MockErrorObserver;
+ ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
+
+ host_resolver.rules()->AddRule("foopy", "166.155.144.11");
+ host_resolver.rules()->AddRule("*", "122.133.144.155");
+
+ InitResolver(&resolver, "simple_dns.js");
+
+ TestCompletionCallback callback1;
+ TestCompletionCallback callback2;
+ ProxyInfo proxy_info;
+
+ int rv = resolver.GetProxyForURL(
+ GURL("http://foopy/req1"),
+ &proxy_info,
+ callback1.callback(),
+ NULL,
+ request_log.bound());
+
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback1.WaitForResult());
+
+ // The test does 2 DNS resolutions.
+ EXPECT_EQ(2u, host_resolver.num_resolve());
+
+ // The first request took 2 restarts, hence on g_iteration=3.
+ EXPECT_EQ("166.155.144.11:3", proxy_info.proxy_server().ToURI());
+
+ rv = resolver.GetProxyForURL(
+ GURL("http://foopy/req2"),
+ &proxy_info,
+ callback2.callback(),
+ NULL,
+ request_log.bound());
+
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback2.WaitForResult());
+
+ EXPECT_EQ(4u, host_resolver.num_resolve());
+
+ // This time no restarts were required, so g_iteration incremented by 1.
+ EXPECT_EQ("166.155.144.11:4", proxy_info.proxy_server().ToURI());
+
+ // No errors.
+ EXPECT_EQ("", error_observer->GetOutput());
+
+ EXPECT_EQ(0u, log.GetSize());
+ EXPECT_EQ(0u, request_log.GetSize());
+}
+
+// This test runs a weird PAC script that was designed to defeat the DNS tracing
+// optimization. The proxy resolver should detect the inconsistency and
+// fall-back to synchronous mode execution.
+TEST_F(ProxyResolverV8TracingTest, FallBackToSynchronous1) {
+ CapturingNetLog log;
+ CapturingBoundNetLog request_log;
+ MockCachingHostResolver host_resolver;
+ MockErrorObserver* error_observer = new MockErrorObserver;
+ ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
+
+ host_resolver.rules()->AddRule("host1", "166.155.144.11");
+ host_resolver.rules()->AddRule("crazy4", "133.199.111.4");
+ host_resolver.rules()->AddRule("*", "122.133.144.155");
+
+ InitResolver(&resolver, "global_sideffects1.js");
+
+ TestCompletionCallback callback;
+ ProxyInfo proxy_info;
+
+ int rv = resolver.GetProxyForURL(
+ GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
+ request_log.bound());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback.WaitForResult());
+
+ // The script itself only does 2 DNS resolves per execution, however it
+ // constructs the hostname using a global counter which changes on each
+ // invocation.
+ EXPECT_EQ(3u, host_resolver.num_resolve());
+
+ EXPECT_EQ("166.155.144.11-133.199.111.4:100",
+ proxy_info.proxy_server().ToURI());
+
+ // No errors.
+ EXPECT_EQ("", error_observer->GetOutput());
+
+ // Check the NetLogs -- the script generated 1 alert, mirrored to both
+ // the per-request and global logs.
+ CapturingNetLog::CapturedEntryList entries_list[2];
+ log.GetEntries(&entries_list[0]);
+ request_log.GetEntries(&entries_list[1]);
+
+ for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
+ const CapturingNetLog::CapturedEntryList& entries = entries_list[list_i];
+ EXPECT_EQ(1u, entries.size());
+ EXPECT_TRUE(
+ LogContainsEvent(entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
+ NetLog::PHASE_NONE));
+ EXPECT_EQ("{\"message\":\"iteration: 4\"}", entries[0].GetParamsJson());
+ }
+}
+
+// This test runs a weird PAC script that was designed to defeat the DNS tracing
+// optimization. The proxy resolver should detect the inconsistency and
+// fall-back to synchronous mode execution.
+TEST_F(ProxyResolverV8TracingTest, FallBackToSynchronous2) {
+ CapturingNetLog log;
+ CapturingBoundNetLog request_log;
+ MockCachingHostResolver host_resolver;
+ MockErrorObserver* error_observer = new MockErrorObserver;
+ ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
+
+ host_resolver.rules()->AddRule("host1", "166.155.144.11");
+ host_resolver.rules()->AddRule("host2", "166.155.144.22");
+ host_resolver.rules()->AddRule("host3", "166.155.144.33");
+ host_resolver.rules()->AddRule("host4", "166.155.144.44");
+ host_resolver.rules()->AddRule("*", "122.133.144.155");
+
+ InitResolver(&resolver, "global_sideffects2.js");
+
+ TestCompletionCallback callback;
+ ProxyInfo proxy_info;
+
+ int rv = resolver.GetProxyForURL(
+ GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
+ request_log.bound());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback.WaitForResult());
+
+ EXPECT_EQ(3u, host_resolver.num_resolve());
+
+ EXPECT_EQ("166.155.144.44:100", proxy_info.proxy_server().ToURI());
+
+ // No errors.
+ EXPECT_EQ("", error_observer->GetOutput());
+
+ // Check the NetLogs -- nothing was logged.
+ EXPECT_EQ(0u, log.GetSize());
+ EXPECT_EQ(0u, request_log.GetSize());
+}
+
+// This test runs a weird PAC script that yields a never ending sequence
+// of DNS resolves when restarting. Running it will hit the maximum
+// DNS resolves per request limit (20) after which every DNS resolve will
+// fail.
+TEST_F(ProxyResolverV8TracingTest, InfiniteDNSSequence) {
+ CapturingNetLog log;
+ CapturingBoundNetLog request_log;
+ MockCachingHostResolver host_resolver;
+ MockErrorObserver* error_observer = new MockErrorObserver;
+ ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
+
+ host_resolver.rules()->AddRule("host*", "166.155.144.11");
+ host_resolver.rules()->AddRule("*", "122.133.144.155");
+
+ InitResolver(&resolver, "global_sideffects3.js");
+
+ TestCompletionCallback callback;
+ ProxyInfo proxy_info;
+
+ int rv = resolver.GetProxyForURL(
+ GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
+ request_log.bound());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback.WaitForResult());
+
+ EXPECT_EQ(20u, host_resolver.num_resolve());
+
+ EXPECT_EQ(
+ "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
+ "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
+ "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
+ "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
+ "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
+ "null:21", proxy_info.proxy_server().ToURI());
+
+ // No errors.
+ EXPECT_EQ("", error_observer->GetOutput());
+
+ // Check the NetLogs -- 1 alert was logged.
+ EXPECT_EQ(1u, log.GetSize());
+ EXPECT_EQ(1u, request_log.GetSize());
+}
+
+// This test runs a weird PAC script that yields a never ending sequence
+// of DNS resolves when restarting. Running it will hit the maximum
+// DNS resolves per request limit (20) after which every DNS resolve will
+// fail.
+TEST_F(ProxyResolverV8TracingTest, InfiniteDNSSequence2) {
+ CapturingNetLog log;
+ CapturingBoundNetLog request_log;
+ MockCachingHostResolver host_resolver;
+ MockErrorObserver* error_observer = new MockErrorObserver;
+ ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
+
+ host_resolver.rules()->AddRule("host*", "166.155.144.11");
+ host_resolver.rules()->AddRule("*", "122.133.144.155");
+
+ InitResolver(&resolver, "global_sideffects4.js");
+
+ TestCompletionCallback callback;
+ ProxyInfo proxy_info;
+
+ int rv = resolver.GetProxyForURL(
+ GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
+ request_log.bound());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback.WaitForResult());
+
+ EXPECT_EQ(20u, host_resolver.num_resolve());
+
+ EXPECT_EQ("null21:34", proxy_info.proxy_server().ToURI());
+
+ // No errors.
+ EXPECT_EQ("", error_observer->GetOutput());
+
+ // Check the NetLogs -- 1 alert was logged.
+ EXPECT_EQ(1u, log.GetSize());
+ EXPECT_EQ(1u, request_log.GetSize());
+}
+
+// Tests a PAC script which does DNS resolves during initialization.
+TEST_F(ProxyResolverV8TracingTest, DnsDuringInit) {
+ CapturingNetLog log;
+ CapturingBoundNetLog request_log;
+ MockCachingHostResolver host_resolver;
+ MockErrorObserver* error_observer = new MockErrorObserver;
+ ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
+
+ host_resolver.rules()->AddRule("host1", "91.13.12.1");
+ host_resolver.rules()->AddRule("host2", "91.13.12.2");
+
+ InitResolver(&resolver, "dns_during_init.js");
+
+ // Initialization did 2 dnsResolves.
+ EXPECT_EQ(2u, host_resolver.num_resolve());
+
+ host_resolver.rules()->ClearRules();
+ host_resolver.GetHostCache()->clear();
+
+ host_resolver.rules()->AddRule("host1", "145.88.13.3");
+ host_resolver.rules()->AddRule("host2", "137.89.8.45");
+
+ TestCompletionCallback callback;
+ ProxyInfo proxy_info;
+
+ int rv = resolver.GetProxyForURL(
+ GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
+ request_log.bound());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback.WaitForResult());
+
+ // Fetched host1 and host2 again, since the ones done during initialization
+ // should not have been cached.
+ EXPECT_EQ(4u, host_resolver.num_resolve());
+
+ EXPECT_EQ("91.13.12.1-91.13.12.2-145.88.13.3-137.89.8.45:99",
+ proxy_info.proxy_server().ToURI());
+
+ // Check the NetLogs -- the script generated 2 alerts during initialization.
+ EXPECT_EQ(0u, request_log.GetSize());
+ CapturingNetLog::CapturedEntryList entries;
+ log.GetEntries(&entries);
+
+ ASSERT_EQ(2u, entries.size());
+ EXPECT_TRUE(
+ LogContainsEvent(entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
+ NetLog::PHASE_NONE));
+ EXPECT_TRUE(
+ LogContainsEvent(entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
+ NetLog::PHASE_NONE));
+
+ EXPECT_EQ("{\"message\":\"Watsup\"}", entries[0].GetParamsJson());
+ EXPECT_EQ("{\"message\":\"Watsup2\"}", entries[1].GetParamsJson());
+}
+
+void CrashCallback(int) {
+ // Be extra sure that if the callback ever gets invoked, the test will fail.
+ CHECK(false);
+}
+
+// Start some requests, cancel them all, and then destroy the resolver.
+// Note the execution order for this test can vary. Since multiple
+// threads are involved, the cancellation may be received a different
+// times.
+TEST_F(ProxyResolverV8TracingTest, CancelAll) {
+ MockCachingHostResolver host_resolver;
+ MockErrorObserver* error_observer = new MockErrorObserver;
+ ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
+
+ host_resolver.rules()->AddSimulatedFailure("*");
+
+ InitResolver(&resolver, "dns.js");
+
+ const size_t kNumRequests = 5;
+ ProxyInfo proxy_info[kNumRequests];
+ ProxyResolver::RequestHandle request[kNumRequests];
+
+ for (size_t i = 0; i < kNumRequests; ++i) {
+ int rv = resolver.GetProxyForURL(
+ GURL("http://foo/"), &proxy_info[i],
+ base::Bind(&CrashCallback), &request[i], BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ }
+
+ for (size_t i = 0; i < kNumRequests; ++i) {
+ resolver.CancelRequest(request[i]);
+ }
+}
+
+// Note the execution order for this test can vary. Since multiple
+// threads are involved, the cancellation may be received a different
+// times.
+TEST_F(ProxyResolverV8TracingTest, CancelSome) {
+ MockCachingHostResolver host_resolver;
+ MockErrorObserver* error_observer = new MockErrorObserver;
+ ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
+
+ host_resolver.rules()->AddSimulatedFailure("*");
+
+ InitResolver(&resolver, "dns.js");
+
+ ProxyInfo proxy_info1;
+ ProxyInfo proxy_info2;
+ ProxyResolver::RequestHandle request1;
+ ProxyResolver::RequestHandle request2;
+ TestCompletionCallback callback;
+
+ int rv = resolver.GetProxyForURL(
+ GURL("http://foo/"), &proxy_info1,
+ base::Bind(&CrashCallback), &request1, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = resolver.GetProxyForURL(
+ GURL("http://foo/"), &proxy_info2,
+ callback.callback(), &request2, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ resolver.CancelRequest(request1);
+
+ EXPECT_EQ(OK, callback.WaitForResult());
+}
+
+// Cancel a request after it has finished running on the worker thread, and has
+// posted a task the completion task back to origin thread.
+TEST_F(ProxyResolverV8TracingTest, CancelWhilePendingCompletionTask) {
+ MockCachingHostResolver host_resolver;
+ MockErrorObserver* error_observer = new MockErrorObserver;
+ ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
+
+ host_resolver.rules()->AddSimulatedFailure("*");
+
+ InitResolver(&resolver, "error.js");
+
+ ProxyInfo proxy_info1;
+ ProxyInfo proxy_info2;
+ ProxyInfo proxy_info3;
+ ProxyResolver::RequestHandle request1;
+ ProxyResolver::RequestHandle request2;
+ ProxyResolver::RequestHandle request3;
+ TestCompletionCallback callback;
+
+ int rv = resolver.GetProxyForURL(
+ GURL("http://foo/"), &proxy_info1,
+ base::Bind(&CrashCallback), &request1, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = resolver.GetProxyForURL(
+ GURL("http://throw-an-error/"), &proxy_info2,
+ callback.callback(), &request2, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ // Wait until the first request has finished running on the worker thread.
+ // (The second request will output an error).
+ error_observer->WaitForOutput();
+
+ // Cancel the first request, while it has a pending completion task on
+ // the origin thread.
+ resolver.CancelRequest(request1);
+
+ EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult());
+
+ // Start another request, to make sure it is able to complete.
+ rv = resolver.GetProxyForURL(
+ GURL("http://i-have-no-idea-what-im-doing/"), &proxy_info3,
+ callback.callback(), &request3, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ EXPECT_EQ(OK, callback.WaitForResult());
+
+ EXPECT_EQ("i-approve-this-message:42",
+ proxy_info3.proxy_server().ToURI());
+}
+
+// This implementation of HostResolver allows blocking until a resolve request
+// has been received. The resolve requests it receives will never be completed.
+class BlockableHostResolver : public HostResolver {
+ public:
+ BlockableHostResolver()
+ : num_cancelled_requests_(0), waiting_for_resolve_(false) {}
+
+ virtual int Resolve(const RequestInfo& info,
+ AddressList* addresses,
+ const CompletionCallback& callback,
+ RequestHandle* out_req,
+ const BoundNetLog& net_log) OVERRIDE {
+ EXPECT_FALSE(callback.is_null());
+ EXPECT_TRUE(out_req);
+ *out_req = reinterpret_cast<RequestHandle*>(1); // Magic value.
+
+ if (!action_.is_null())
+ action_.Run();
+
+ // Indicate to the caller that a request was received.
+ EXPECT_TRUE(waiting_for_resolve_);
+ MessageLoop::current()->Quit();
+
+ // Return ERR_IO_PENDING as this request will NEVER be completed.
+ // Expectation is for the caller to later cancel the request.
+ return ERR_IO_PENDING;
+ }
+
+ virtual int ResolveFromCache(const RequestInfo& info,
+ AddressList* addresses,
+ const BoundNetLog& net_log) OVERRIDE {
+ NOTREACHED();
+ return ERR_DNS_CACHE_MISS;
+ }
+
+ virtual void CancelRequest(RequestHandle req) OVERRIDE {
+ EXPECT_EQ(reinterpret_cast<RequestHandle*>(1), req);
+ num_cancelled_requests_++;
+ }
+
+ void SetAction(const base::Callback<void(void)>& action) {
+ action_ = action;
+ }
+
+ // Waits until Resolve() has been called.
+ void WaitUntilRequestIsReceived() {
+ waiting_for_resolve_ = true;
+ MessageLoop::current()->Run();
+ DCHECK(waiting_for_resolve_);
+ waiting_for_resolve_ = false;
+ }
+
+ int num_cancelled_requests() const {
+ return num_cancelled_requests_;
+ }
+
+ private:
+ int num_cancelled_requests_;
+ bool waiting_for_resolve_;
+ base::Callback<void(void)> action_;
+};
+
+// This cancellation test exercises a more predictable cancellation codepath --
+// when the request has an outstanding DNS request in flight.
+TEST_F(ProxyResolverV8TracingTest, CancelWhileOutstandingNonBlockingDns) {
+ BlockableHostResolver host_resolver;
+ MockErrorObserver* error_observer = new MockErrorObserver;
+ ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
+
+ InitResolver(&resolver, "dns.js");
+
+ ProxyInfo proxy_info1;
+ ProxyInfo proxy_info2;
+ ProxyResolver::RequestHandle request1;
+ ProxyResolver::RequestHandle request2;
+
+ int rv = resolver.GetProxyForURL(
+ GURL("http://foo/req1"), &proxy_info1,
+ base::Bind(&CrashCallback), &request1, BoundNetLog());
+
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ host_resolver.WaitUntilRequestIsReceived();
+
+ rv = resolver.GetProxyForURL(
+ GURL("http://foo/req2"), &proxy_info2,
+ base::Bind(&CrashCallback), &request2, BoundNetLog());
+
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ host_resolver.WaitUntilRequestIsReceived();
+
+ resolver.CancelRequest(request1);
+ resolver.CancelRequest(request2);
+
+ EXPECT_EQ(2, host_resolver.num_cancelled_requests());
+
+ // After leaving this scope, the ProxyResolver is destroyed.
+ // This should not cause any problems, as the outstanding work
+ // should have been cancelled.
+}
+
+// In non-blocking mode, the worker thread actually does block for
+// a short time to see if the result is in the DNS cache. Test
+// cancellation while the worker thread is waiting on this event.
+TEST_F(ProxyResolverV8TracingTest, CancelWhileBlockedInNonBlockingDns) {
+ BlockableHostResolver host_resolver;
+ MockErrorObserver* error_observer = new MockErrorObserver;
+ ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
+
+ InitResolver(&resolver, "dns.js");
+
+ ProxyInfo proxy_info;
+ ProxyResolver::RequestHandle request;
+
+ int rv = resolver.GetProxyForURL(
+ GURL("http://foo/"), &proxy_info,
+ base::Bind(&CrashCallback), &request, BoundNetLog());
+
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ host_resolver.SetAction(base::Bind(&ProxyResolverV8Tracing::CancelRequest,
+ base::Unretained(&resolver), request));
+
+ host_resolver.WaitUntilRequestIsReceived();
+
+ // At this point the host resolver ran Resolve(), and should have cancelled
+ // the request.
+
+ EXPECT_EQ(1, host_resolver.num_cancelled_requests());
+}
+
+// Cancel the request while there is a pending DNS request, however before
+// the request is sent to the host resolver.
+TEST_F(ProxyResolverV8TracingTest, CancelWhileBlockedInNonBlockingDns2) {
+ MockCachingHostResolver host_resolver;
+ MockErrorObserver* error_observer = new MockErrorObserver;
+ ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
+
+ InitResolver(&resolver, "dns.js");
+
+ ProxyInfo proxy_info;
+ ProxyResolver::RequestHandle request;
+
+ int rv = resolver.GetProxyForURL(
+ GURL("http://foo/"), &proxy_info,
+ base::Bind(&CrashCallback), &request, BoundNetLog());
+
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ // Wait a bit, so the DNS task has hopefully been posted. The test will
+ // work whatever the delay is here, but it is most useful if the delay
+ // is large enough to allow a task to be posted back.
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
+ resolver.CancelRequest(request);
+
+ EXPECT_EQ(0u, host_resolver.num_resolve());
+}
+
+TEST_F(ProxyResolverV8TracingTest, CancelSetPacWhileOutstandingBlockingDns) {
+ BlockableHostResolver host_resolver;
+ MockErrorObserver* error_observer = new MockErrorObserver;
+
+ ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
+
+ int rv =
+ resolver.SetPacScript(LoadScriptData("dns_during_init.js"),
+ base::Bind(&CrashCallback));
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ host_resolver.WaitUntilRequestIsReceived();
+
+ resolver.CancelSetPacScript();
+ EXPECT_EQ(1, host_resolver.num_cancelled_requests());
+}
+
+} // namespace
+
+} // namespace net
diff --git a/net/proxy/proxy_resolver_v8_unittest.cc b/net/proxy/proxy_resolver_v8_unittest.cc
index b93d4f3..41683a2 100644
--- a/net/proxy/proxy_resolver_v8_unittest.cc
+++ b/net/proxy/proxy_resolver_v8_unittest.cc
@@ -12,7 +12,6 @@
#include "net/base/net_errors.h"
#include "net/base/net_log_unittest.h"
#include "net/proxy/proxy_info.h"
-#include "net/proxy/proxy_resolver_js_bindings.h"
#include "net/proxy/proxy_resolver_v8.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -22,7 +21,7 @@ namespace {
// Javascript bindings for ProxyResolverV8, which returns mock values.
// Each time one of the bindings is called into, we push the input into a
// list, for later verification.
-class MockJSBindings : public ProxyResolverJSBindings {
+class MockJSBindings : public ProxyResolverV8::JSBindings {
public:
MockJSBindings() : my_ip_address_count(0), my_ip_address_ex_count(0) {}
@@ -31,30 +30,35 @@ class MockJSBindings : public ProxyResolverJSBindings {
alerts.push_back(UTF16ToUTF8(message));
}
- virtual bool MyIpAddress(std::string* ip_address) OVERRIDE {
- my_ip_address_count++;
- *ip_address = my_ip_address_result;
- return !my_ip_address_result.empty();
- }
+ virtual bool ResolveDns(const std::string& host,
+ ResolveDnsOperation op,
+ std::string* output) OVERRIDE {
+ if (op == MY_IP_ADDRESS) {
+ my_ip_address_count++;
+ *output = my_ip_address_result;
+ return !my_ip_address_result.empty();
+ }
- virtual bool MyIpAddressEx(std::string* ip_address_list) OVERRIDE {
- my_ip_address_ex_count++;
- *ip_address_list = my_ip_address_ex_result;
- return !my_ip_address_ex_result.empty();
- }
+ if (op == MY_IP_ADDRESS_EX) {
+ my_ip_address_ex_count++;
+ *output = my_ip_address_ex_result;
+ return !my_ip_address_ex_result.empty();
+ }
- virtual bool DnsResolve(const std::string& host, std::string* ip_address)
- OVERRIDE {
- dns_resolves.push_back(host);
- *ip_address = dns_resolve_result;
- return !dns_resolve_result.empty();
- }
+ if (op == DNS_RESOLVE) {
+ dns_resolves.push_back(host);
+ *output = dns_resolve_result;
+ return !dns_resolve_result.empty();
+ }
- virtual bool DnsResolveEx(const std::string& host,
- std::string* ip_address_list) OVERRIDE {
- dns_resolves_ex.push_back(host);
- *ip_address_list = dns_resolve_ex_result;
- return !dns_resolve_ex_result.empty();
+ if (op == DNS_RESOLVE_EX) {
+ dns_resolves_ex.push_back(host);
+ *output = dns_resolve_ex_result;
+ return !dns_resolve_ex_result.empty();
+ }
+
+ CHECK(false);
+ return false;
}
virtual void OnError(int line_number, const string16& message) OVERRIDE {
@@ -65,8 +69,6 @@ class MockJSBindings : public ProxyResolverJSBindings {
errors_line_number.push_back(line_number);
}
- virtual void Shutdown() OVERRIDE {}
-
// Mock values to return.
std::string my_ip_address_result;
std::string my_ip_address_ex_result;
@@ -88,10 +90,12 @@ class MockJSBindings : public ProxyResolverJSBindings {
// disk.
class ProxyResolverV8WithMockBindings : public ProxyResolverV8 {
public:
- ProxyResolverV8WithMockBindings() : ProxyResolverV8(new MockJSBindings()) {}
+ ProxyResolverV8WithMockBindings() {
+ set_js_bindings(&mock_js_bindings_);
+ }
- MockJSBindings* mock_js_bindings() const {
- return reinterpret_cast<MockJSBindings*>(js_bindings());
+ MockJSBindings* mock_js_bindings() {
+ return &mock_js_bindings_;
}
// Initialize with the PAC script data at |filename|.
@@ -117,13 +121,15 @@ class ProxyResolverV8WithMockBindings : public ProxyResolverV8 {
return SetPacScript(ProxyResolverScriptData::FromUTF8(file_contents),
CompletionCallback());
}
+
+ private:
+ MockJSBindings mock_js_bindings_;
};
// Doesn't really matter what these values are for many of the tests.
const GURL kQueryUrl("http://www.google.com");
const GURL kPacUrl;
-
TEST(ProxyResolverV8Test, Direct) {
ProxyResolverV8WithMockBindings resolver;
int result = resolver.SetPacScriptFromDisk("direct.js");
diff --git a/net/proxy/proxy_resolver_winhttp.cc b/net/proxy/proxy_resolver_winhttp.cc
index 1e14fbb..1ddc8ca 100644
--- a/net/proxy/proxy_resolver_winhttp.cc
+++ b/net/proxy/proxy_resolver_winhttp.cc
@@ -128,11 +128,6 @@ LoadState ProxyResolverWinHttp::GetLoadState(RequestHandle request) const {
return LOAD_STATE_IDLE;
}
-LoadState ProxyResolverWinHttp::GetLoadStateThreadSafe(
- RequestHandle request) const {
- return LOAD_STATE_IDLE;
-}
-
void ProxyResolverWinHttp::CancelSetPacScript() {
NOTREACHED();
}
diff --git a/net/proxy/proxy_resolver_winhttp.h b/net/proxy/proxy_resolver_winhttp.h
index e92827a..047fbf5 100644
--- a/net/proxy/proxy_resolver_winhttp.h
+++ b/net/proxy/proxy_resolver_winhttp.h
@@ -30,9 +30,6 @@ class NET_EXPORT_PRIVATE ProxyResolverWinHttp : public ProxyResolver {
virtual LoadState GetLoadState(RequestHandle request) const OVERRIDE;
- virtual LoadState GetLoadStateThreadSafe(
- RequestHandle request) const OVERRIDE;
-
virtual void CancelSetPacScript() OVERRIDE;
virtual int SetPacScript(
diff --git a/net/proxy/proxy_service.cc b/net/proxy/proxy_service.cc
index 181441d..8cfa1f3 100644
--- a/net/proxy/proxy_service.cc
+++ b/net/proxy/proxy_service.cc
@@ -28,7 +28,6 @@
#include "net/proxy/proxy_resolver.h"
#include "net/proxy/proxy_script_decider.h"
#include "net/proxy/proxy_script_fetcher.h"
-#include "net/proxy/sync_host_resolver_bridge.h"
#include "net/url_request/url_request_context.h"
#if defined(OS_WIN)
@@ -195,12 +194,6 @@ class ProxyResolverNull : public ProxyResolver {
return LOAD_STATE_IDLE;
}
- virtual LoadState GetLoadStateThreadSafe(
- RequestHandle request) const OVERRIDE {
- NOTREACHED();
- return LOAD_STATE_IDLE;
- }
-
virtual void CancelSetPacScript() OVERRIDE {
NOTREACHED();
}
@@ -238,12 +231,6 @@ class ProxyResolverFromPacString : public ProxyResolver {
return LOAD_STATE_IDLE;
}
- virtual LoadState GetLoadStateThreadSafe(
- RequestHandle request) const OVERRIDE {
- NOTREACHED();
- return LOAD_STATE_IDLE;
- }
-
virtual void CancelSetPacScript() OVERRIDE {
NOTREACHED();
}
diff --git a/net/proxy/proxy_service_v8.cc b/net/proxy/proxy_service_v8.cc
index 44ae82c..d5a3dd7 100644
--- a/net/proxy/proxy_service_v8.cc
+++ b/net/proxy/proxy_service_v8.cc
@@ -5,71 +5,16 @@
#include "net/proxy/proxy_service_v8.h"
#include "base/logging.h"
-#include "net/proxy/multi_threaded_proxy_resolver.h"
#include "net/proxy/network_delegate_error_observer.h"
#include "net/proxy/proxy_resolver.h"
-#include "net/proxy/proxy_resolver_js_bindings.h"
-#include "net/proxy/proxy_resolver_v8.h"
+#include "net/proxy/proxy_resolver_v8_tracing.h"
#include "net/proxy/proxy_service.h"
-#include "net/proxy/sync_host_resolver_bridge.h"
namespace net {
-namespace {
-
-// This factory creates V8ProxyResolvers with appropriate javascript bindings.
-class ProxyResolverFactoryForV8 : public ProxyResolverFactory {
- public:
- // |async_host_resolver|, |io_loop| and |net_log| must remain
- // valid for the duration of our lifetime.
- // |async_host_resolver| will only be operated on |io_loop|.
- // TODO(willchan): remove io_loop and replace it with origin_loop.
- ProxyResolverFactoryForV8(HostResolver* async_host_resolver,
- MessageLoop* io_loop,
- base::MessageLoopProxy* origin_loop,
- NetLog* net_log,
- NetworkDelegate* network_delegate)
- : ProxyResolverFactory(true /*expects_pac_bytes*/),
- async_host_resolver_(async_host_resolver),
- io_loop_(io_loop),
- origin_loop_(origin_loop),
- net_log_(net_log),
- network_delegate_(network_delegate) {
- }
-
- virtual ProxyResolver* CreateProxyResolver() OVERRIDE {
- // Create a synchronous host resolver wrapper that operates
- // |async_host_resolver_| on |io_loop_|.
- SyncHostResolverBridge* sync_host_resolver =
- new SyncHostResolverBridge(async_host_resolver_, io_loop_);
-
- NetworkDelegateErrorObserver* error_observer =
- new NetworkDelegateErrorObserver(
- network_delegate_, origin_loop_.get());
-
- // ProxyResolverJSBindings takes ownership of |error_observer| and
- // |sync_host_resolver|.
- ProxyResolverJSBindings* js_bindings =
- ProxyResolverJSBindings::CreateDefault(
- sync_host_resolver, net_log_, error_observer);
-
- // ProxyResolverV8 takes ownership of |js_bindings|.
- return new ProxyResolverV8(js_bindings);
- }
-
- private:
- HostResolver* const async_host_resolver_;
- MessageLoop* io_loop_;
- scoped_refptr<base::MessageLoopProxy> origin_loop_;
- NetLog* net_log_;
- NetworkDelegate* network_delegate_;
-};
-
-} // namespace
// static
ProxyService* CreateProxyServiceUsingV8ProxyResolver(
ProxyConfigService* proxy_config_service,
- size_t num_pac_threads,
ProxyScriptFetcher* proxy_script_fetcher,
DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher,
HostResolver* host_resolver,
@@ -80,19 +25,12 @@ ProxyService* CreateProxyServiceUsingV8ProxyResolver(
DCHECK(dhcp_proxy_script_fetcher);
DCHECK(host_resolver);
- if (num_pac_threads == 0)
- num_pac_threads = ProxyService::kDefaultNumPacThreads;
-
- ProxyResolverFactory* sync_resolver_factory =
- new ProxyResolverFactoryForV8(
- host_resolver,
- MessageLoop::current(),
- base::MessageLoopProxy::current(),
- net_log,
- network_delegate);
+ ProxyResolverErrorObserver* error_observer =
+ new NetworkDelegateErrorObserver(
+ network_delegate, base::MessageLoopProxy::current());
ProxyResolver* proxy_resolver =
- new MultiThreadedProxyResolver(sync_resolver_factory, num_pac_threads);
+ new ProxyResolverV8Tracing(host_resolver, error_observer, net_log);
ProxyService* proxy_service =
new ProxyService(proxy_config_service, proxy_resolver, net_log);
diff --git a/net/proxy/proxy_service_v8.h b/net/proxy/proxy_service_v8.h
index 0ff574d..0e339eb 100644
--- a/net/proxy/proxy_service_v8.h
+++ b/net/proxy/proxy_service_v8.h
@@ -21,21 +21,6 @@ class ProxyService;
// Creates a proxy service that polls |proxy_config_service| to notice when
// the proxy settings change. We take ownership of |proxy_config_service|.
//
-// |num_pac_threads| specifies the maximum number of threads to use for
-// executing PAC scripts. Threads are created lazily on demand.
-// If |0| is specified, then a default number of threads will be selected.
-//
-// Having more threads avoids stalling proxy resolve requests when the
-// PAC script takes a while to run. This is particularly a problem when PAC
-// scripts do synchronous DNS resolutions, since that can take on the order
-// of seconds.
-//
-// However, the disadvantages of using more than 1 thread are:
-// (a) can cause compatibility issues for scripts that rely on side effects
-// between runs (such scripts should not be common though).
-// (b) increases the memory used by proxy resolving, as each thread will
-// duplicate its own script context.
-
// |proxy_script_fetcher| specifies the dependency to use for downloading
// any PAC scripts. The resulting ProxyService will take ownership of it.
//
@@ -54,7 +39,6 @@ class ProxyService;
// ##########################################################################
NET_EXPORT ProxyService* CreateProxyServiceUsingV8ProxyResolver(
ProxyConfigService* proxy_config_service,
- size_t num_pac_threads,
ProxyScriptFetcher* proxy_script_fetcher,
DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher,
HostResolver* host_resolver,
diff --git a/net/proxy/sync_host_resolver.h b/net/proxy/sync_host_resolver.h
deleted file mode 100644
index 153dfad..0000000
--- a/net/proxy/sync_host_resolver.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) 2012 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_SYNC_HOST_RESOLVER_H_
-#define NET_PROXY_SYNC_HOST_RESOLVER_H_
-
-#include "net/base/host_resolver.h"
-#include "net/base/net_export.h"
-
-namespace net {
-
-class BoundNetLog;
-
-// Interface used by ProxyResolverJSBindings to abstract a synchronous host
-// resolver module (which includes a Shutdown method).
-class NET_EXPORT_PRIVATE SyncHostResolver {
- public:
- virtual ~SyncHostResolver() {}
-
- virtual int Resolve(const HostResolver::RequestInfo& info,
- AddressList* addresses,
- const BoundNetLog& net_log) = 0;
-
- // Optionally aborts any blocking resolves that are in progress.
- virtual void Shutdown() = 0;
-};
-
-} // namespace net
-
-#endif // NET_PROXY_SYNC_HOST_RESOLVER_H_
diff --git a/net/proxy/sync_host_resolver_bridge.cc b/net/proxy/sync_host_resolver_bridge.cc
deleted file mode 100644
index 9f55524..0000000
--- a/net/proxy/sync_host_resolver_bridge.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright (c) 2012 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/sync_host_resolver_bridge.h"
-
-#include "base/bind.h"
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "base/message_loop.h"
-#include "base/synchronization/lock.h"
-#include "base/synchronization/waitable_event.h"
-#include "net/base/net_errors.h"
-#include "net/base/net_log.h"
-
-namespace net {
-
-// SyncHostResolverBridge::Core ----------------------------------------------
-
-class SyncHostResolverBridge::Core
- : public base::RefCountedThreadSafe<SyncHostResolverBridge::Core> {
- public:
- Core(HostResolver* resolver, MessageLoop* host_resolver_loop);
-
- int ResolveSynchronously(const HostResolver::RequestInfo& info,
- AddressList* addresses,
- const BoundNetLog& net_log);
-
- // Returns true if Shutdown() has been called.
- bool HasShutdown() const {
- base::AutoLock l(lock_);
- return HasShutdownLocked();
- }
-
- // Called on |host_resolver_loop_|.
- void Shutdown();
-
- private:
- friend class base::RefCountedThreadSafe<SyncHostResolverBridge::Core>;
- ~Core() {}
-
- bool HasShutdownLocked() const {
- return has_shutdown_;
- }
-
- // Called on |host_resolver_loop_|.
- void StartResolve(const HostResolver::RequestInfo& info,
- AddressList* addresses,
- const BoundNetLog& net_log);
-
- // Called on |host_resolver_loop_|.
- void OnResolveCompletion(int result);
-
- // Not called on |host_resolver_loop_|.
- int WaitForResolveCompletion();
-
- HostResolver* const host_resolver_;
- MessageLoop* const host_resolver_loop_;
- // The result from the current request (set on |host_resolver_loop_|).
- int err_;
- // The currently outstanding request to |host_resolver_|, or NULL.
- HostResolver::RequestHandle outstanding_request_;
-
- // Event to notify completion of resolve request. We always Signal() on
- // |host_resolver_loop_| and Wait() on a different thread.
- base::WaitableEvent event_;
-
- // True if Shutdown() has been called. Must hold |lock_| to access it.
- bool has_shutdown_;
-
- // Mutex to guard accesses to |has_shutdown_|.
- mutable base::Lock lock_;
-
- DISALLOW_COPY_AND_ASSIGN(Core);
-};
-
-SyncHostResolverBridge::Core::Core(HostResolver* host_resolver,
- MessageLoop* host_resolver_loop)
- : host_resolver_(host_resolver),
- host_resolver_loop_(host_resolver_loop),
- err_(0),
- outstanding_request_(NULL),
- event_(true, false),
- has_shutdown_(false) {}
-
-int SyncHostResolverBridge::Core::ResolveSynchronously(
- const HostResolver::RequestInfo& info,
- net::AddressList* addresses,
- const BoundNetLog& net_log) {
- // Otherwise start an async resolve on the resolver's thread.
- host_resolver_loop_->PostTask(
- FROM_HERE,
- base::Bind(&Core::StartResolve, this, info, addresses, net_log));
-
- return WaitForResolveCompletion();
-}
-
-void SyncHostResolverBridge::Core::StartResolve(
- const HostResolver::RequestInfo& info,
- net::AddressList* addresses,
- const BoundNetLog& net_log) {
- DCHECK_EQ(MessageLoop::current(), host_resolver_loop_);
- DCHECK(!outstanding_request_);
-
- if (HasShutdown())
- return;
-
- int error = host_resolver_->Resolve(
- info, addresses, base::Bind(&Core::OnResolveCompletion, this),
- &outstanding_request_, net_log);
- if (error != ERR_IO_PENDING)
- OnResolveCompletion(error); // Completed synchronously.
-}
-
-void SyncHostResolverBridge::Core::OnResolveCompletion(int result) {
- DCHECK_EQ(MessageLoop::current(), host_resolver_loop_);
- err_ = result;
- outstanding_request_ = NULL;
- event_.Signal();
-}
-
-int SyncHostResolverBridge::Core::WaitForResolveCompletion() {
- DCHECK_NE(MessageLoop::current(), host_resolver_loop_);
- event_.Wait();
-
- {
- base::AutoLock l(lock_);
- if (HasShutdownLocked())
- return ERR_ABORTED;
- event_.Reset();
- }
-
- return err_;
-}
-
-void SyncHostResolverBridge::Core::Shutdown() {
- DCHECK_EQ(MessageLoop::current(), host_resolver_loop_);
-
- if (outstanding_request_) {
- host_resolver_->CancelRequest(outstanding_request_);
- outstanding_request_ = NULL;
- }
-
- {
- base::AutoLock l(lock_);
- has_shutdown_ = true;
- }
-
- // Wake up the PAC thread in case it was waiting for resolve completion.
- event_.Signal();
-}
-
-// SyncHostResolverBridge -----------------------------------------------------
-
-SyncHostResolverBridge::SyncHostResolverBridge(HostResolver* host_resolver,
- MessageLoop* host_resolver_loop)
- : host_resolver_loop_(host_resolver_loop),
- core_(new Core(host_resolver, host_resolver_loop)) {
- DCHECK(host_resolver_loop_);
-}
-
-SyncHostResolverBridge::~SyncHostResolverBridge() {
- DCHECK(core_->HasShutdown());
-}
-
-int SyncHostResolverBridge::Resolve(const HostResolver::RequestInfo& info,
- AddressList* addresses,
- const BoundNetLog& net_log) {
- return core_->ResolveSynchronously(info, addresses, net_log);
-}
-
-void SyncHostResolverBridge::Shutdown() {
- DCHECK_EQ(MessageLoop::current(), host_resolver_loop_);
- core_->Shutdown();
-}
-
-} // namespace net
diff --git a/net/proxy/sync_host_resolver_bridge.h b/net/proxy/sync_host_resolver_bridge.h
deleted file mode 100644
index 1de67b5..0000000
--- a/net/proxy/sync_host_resolver_bridge.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 2012 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_SYNC_HOST_RESOLVER_BRIDGE_H_
-#define NET_PROXY_SYNC_HOST_RESOLVER_BRIDGE_H_
-
-#include "base/compiler_specific.h"
-#include "base/memory/ref_counted.h"
-#include "net/proxy/sync_host_resolver.h"
-
-class MessageLoop;
-
-namespace net {
-
-// Wrapper around HostResolver to give a sync API while running the resolver
-// in async mode on |host_resolver_loop|.
-class NET_EXPORT_PRIVATE SyncHostResolverBridge : public SyncHostResolver {
- public:
- SyncHostResolverBridge(HostResolver* host_resolver,
- MessageLoop* host_resolver_loop);
-
- virtual ~SyncHostResolverBridge();
-
- // SyncHostResolver methods:
- virtual int Resolve(const HostResolver::RequestInfo& info,
- AddressList* addresses,
- const BoundNetLog& net_log) OVERRIDE;
-
- // The Shutdown() method should be called prior to destruction, from
- // |host_resolver_loop_|. It aborts any in progress synchronous resolves, to
- // prevent deadlocks from happening.
- virtual void Shutdown() OVERRIDE;
-
- private:
- class Core;
-
- MessageLoop* const host_resolver_loop_;
- scoped_refptr<Core> core_;
- DISALLOW_COPY_AND_ASSIGN(SyncHostResolverBridge);
-};
-
-} // namespace net
-
-#endif // NET_PROXY_SYNC_HOST_RESOLVER_BRIDGE_H_
diff --git a/net/proxy/sync_host_resolver_bridge_unittest.cc b/net/proxy/sync_host_resolver_bridge_unittest.cc
deleted file mode 100644
index 81ec33e..0000000
--- a/net/proxy/sync_host_resolver_bridge_unittest.cc
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright (c) 2012 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/sync_host_resolver_bridge.h"
-
-#include "base/threading/thread.h"
-#include "base/synchronization/waitable_event.h"
-#include "net/base/address_list.h"
-#include "net/base/net_errors.h"
-#include "net/base/net_log.h"
-#include "net/proxy/multi_threaded_proxy_resolver.h"
-#include "net/base/test_completion_callback.h"
-#include "net/proxy/proxy_info.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-// TODO(eroman): This test should be moved into
-// multi_threaded_proxy_resolver_unittest.cc.
-
-namespace net {
-
-namespace {
-
-// This implementation of HostResolver allows blocking until a resolve request
-// has been received. The resolve requests it receives will never be completed.
-class BlockableHostResolver : public HostResolver {
- public:
- BlockableHostResolver()
- : event_(true, false),
- was_request_cancelled_(false) {
- }
-
- virtual int Resolve(const RequestInfo& info,
- AddressList* addresses,
- const CompletionCallback& callback,
- RequestHandle* out_req,
- const BoundNetLog& net_log) OVERRIDE {
- EXPECT_FALSE(callback.is_null());
- EXPECT_TRUE(out_req);
- *out_req = reinterpret_cast<RequestHandle*>(1); // Magic value.
-
- // Indicate to the caller that a request was received.
- event_.Signal();
-
- // We return ERR_IO_PENDING, as this request will NEVER be completed.
- // Expectation is for the caller to later cancel the request.
- return ERR_IO_PENDING;
- }
-
- virtual int ResolveFromCache(const RequestInfo& info,
- AddressList* addresses,
- const BoundNetLog& net_log) OVERRIDE {
- NOTIMPLEMENTED();
- return ERR_UNEXPECTED;
- }
-
- virtual void CancelRequest(RequestHandle req) OVERRIDE {
- EXPECT_EQ(reinterpret_cast<RequestHandle*>(1), req);
- was_request_cancelled_ = true;
- }
-
- // Waits until Resolve() has been called.
- void WaitUntilRequestIsReceived() {
- event_.Wait();
- }
-
- bool was_request_cancelled() const {
- return was_request_cancelled_;
- }
-
- private:
- // Event to notify when a resolve request was received.
- base::WaitableEvent event_;
- bool was_request_cancelled_;
-};
-
-// This implementation of ProxyResolver simply does a synchronous resolve
-// on |host_resolver| in response to GetProxyForURL().
-class SyncProxyResolver : public ProxyResolver {
- public:
- explicit SyncProxyResolver(SyncHostResolverBridge* host_resolver)
- : ProxyResolver(false), host_resolver_(host_resolver) {}
-
- virtual int GetProxyForURL(const GURL& url,
- ProxyInfo* results,
- const CompletionCallback& callback,
- RequestHandle* request,
- const BoundNetLog& net_log) {
- EXPECT_FALSE(!callback.is_null());
- EXPECT_FALSE(request);
-
- // Do a synchronous host resolve.
- HostResolver::RequestInfo info(HostPortPair::FromURL(url));
- AddressList addresses;
- int rv = host_resolver_->Resolve(info, &addresses, net_log);
-
- EXPECT_EQ(ERR_ABORTED, rv);
-
- return rv;
- }
-
- virtual void CancelRequest(RequestHandle request) OVERRIDE {
- NOTREACHED();
- }
-
- virtual LoadState GetLoadState(RequestHandle request) const OVERRIDE {
- NOTREACHED();
- return LOAD_STATE_IDLE;
- }
-
- virtual LoadState GetLoadStateThreadSafe(
- RequestHandle request) const OVERRIDE {
- NOTREACHED();
- return LOAD_STATE_IDLE;
- }
-
- virtual void Shutdown() OVERRIDE {
- host_resolver_->Shutdown();
- }
-
- virtual void CancelSetPacScript() OVERRIDE {
- NOTREACHED();
- }
-
- virtual int SetPacScript(
- const scoped_refptr<ProxyResolverScriptData>& script_data,
- const CompletionCallback& callback) OVERRIDE {
- return OK;
- }
-
- private:
- SyncHostResolverBridge* const host_resolver_;
-};
-
-class SyncProxyResolverFactory : public ProxyResolverFactory {
- public:
- // Takes ownership of |sync_host_resolver|.
- explicit SyncProxyResolverFactory(SyncHostResolverBridge* sync_host_resolver)
- : ProxyResolverFactory(false),
- sync_host_resolver_(sync_host_resolver) {
- }
-
- virtual ProxyResolver* CreateProxyResolver() OVERRIDE {
- return new SyncProxyResolver(sync_host_resolver_.get());
- }
-
- private:
- const scoped_ptr<SyncHostResolverBridge> sync_host_resolver_;
-};
-
-// This helper thread is used to create the circumstances for the deadlock.
-// It is analagous to the "IO thread" which would be main thread running the
-// network stack.
-class IOThread : public base::Thread {
- public:
- IOThread() : base::Thread("IO-thread") {}
-
- virtual ~IOThread() {
- Stop();
- }
-
- BlockableHostResolver* async_resolver() {
- return async_resolver_.get();
- }
-
- protected:
- virtual void Init() OVERRIDE {
- async_resolver_.reset(new BlockableHostResolver());
-
- // Create a synchronous host resolver that operates the async host
- // resolver on THIS thread.
- SyncHostResolverBridge* sync_resolver =
- new SyncHostResolverBridge(async_resolver_.get(), message_loop());
-
- proxy_resolver_.reset(
- new MultiThreadedProxyResolver(
- new SyncProxyResolverFactory(sync_resolver),
- 1u));
-
- // Initialize the resolver.
- TestCompletionCallback callback;
- proxy_resolver_->SetPacScript(ProxyResolverScriptData::FromURL(GURL()),
- callback.callback());
- EXPECT_EQ(OK, callback.WaitForResult());
-
- // Start an asynchronous request to the proxy resolver
- // (note that it will never complete).
- proxy_resolver_->GetProxyForURL(
- GURL("http://test/"), &results_, callback_.callback(), &request_,
- BoundNetLog());
- }
-
- virtual void CleanUp() OVERRIDE {
- // Cancel the outstanding request (note however that this will not
- // unblock the PAC thread though).
- proxy_resolver_->CancelRequest(request_);
-
- // Delete the single threaded proxy resolver.
- proxy_resolver_.reset();
-
- // (There may have been a completion posted back to origin thread, avoid
- // leaking it by running).
- MessageLoop::current()->RunUntilIdle();
-
- // During the teardown sequence of the single threaded proxy resolver,
- // the outstanding host resolve should have been cancelled.
- EXPECT_TRUE(async_resolver_->was_request_cancelled());
- }
-
- private:
- // This (async) host resolver will outlive the thread that is operating it
- // synchronously.
- scoped_ptr<BlockableHostResolver> async_resolver_;
-
- scoped_ptr<ProxyResolver> proxy_resolver_;
-
- // Data for the outstanding request to the single threaded proxy resolver.
- TestCompletionCallback callback_;
- ProxyInfo results_;
- ProxyResolver::RequestHandle request_;
-};
-
-// Test that a deadlock does not happen during shutdown when a host resolve
-// is outstanding on the SyncHostResolverBridge.
-// This is a regression test for http://crbug.com/41244.
-TEST(MultiThreadedProxyResolverTest, ShutdownIsCalledBeforeThreadJoin) {
- IOThread io_thread;
- base::Thread::Options options;
- options.message_loop_type = MessageLoop::TYPE_IO;
- ASSERT_TRUE(io_thread.StartWithOptions(options));
-
- io_thread.async_resolver()->WaitUntilRequestIsReceived();
-
- // Now upon exitting this scope, the IOThread is destroyed -- this will
- // stop the IOThread, which will in turn delete the
- // SingleThreadedProxyResolver, which in turn will stop its internal
- // PAC thread (which is currently blocked waiting on the host resolve which
- // is running on IOThread). The IOThread::Cleanup() will verify that after
- // the PAC thread is stopped, it cancels the request on the HostResolver.
-}
-
-} // namespace
-
-} // namespace net