This source file includes following definitions.
- weak_factory_
- CreateProxyConfigService
- Init
- CreateHostResolver
- CreateProxyService
- CreateSystemProxyConfigService
- FirefoxProxySettingsTask
- FirefoxProxySettingsReply
- CreateFirefoxProxyConfigService
- weak_factory_
- OnResponseStarted
- OnReadCompleted
- ReadBody
- OnResponseCompleted
- OnExperimentCompletedWithResult
- ProxyConfigServiceCreated
- net_log_
- RunAllTests
- ProxySettingsExperimentDescription
- HostResolverExperimentDescription
- GetAllPossibleExperimentCombinations
- StartNextExperiment
- OnExperimentCompleted
#include "chrome/browser/net/connection_tester.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/thread_task_runner_handle.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/common/chrome_switches.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/cookie_store_factory.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/base/request_priority.h"
#include "net/cert/cert_verifier.h"
#include "net/dns/host_resolver.h"
#include "net/http/http_auth_handler_factory.h"
#include "net/http/http_cache.h"
#include "net/http/http_network_session.h"
#include "net/http/http_server_properties_impl.h"
#include "net/http/transport_security_state.h"
#include "net/proxy/dhcp_proxy_script_fetcher_factory.h"
#include "net/proxy/proxy_config_service_fixed.h"
#include "net/proxy/proxy_script_fetcher_impl.h"
#include "net/proxy/proxy_service.h"
#include "net/proxy/proxy_service_v8.h"
#include "net/ssl/ssl_config_service_defaults.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_storage.h"
#if !defined(OS_ANDROID) && !defined(OS_IOS)
#include "chrome/browser/net/firefox_proxy_settings.h"
#endif
namespace {
class ExperimentURLRequestContext : public net::URLRequestContext {
public:
explicit ExperimentURLRequestContext(
net::URLRequestContext* proxy_request_context) :
#if !defined(OS_IOS)
proxy_request_context_(proxy_request_context),
#endif
storage_(this),
weak_factory_(this) {}
virtual ~ExperimentURLRequestContext() {}
int CreateProxyConfigService(
ConnectionTester::ProxySettingsExperiment experiment,
scoped_ptr<net::ProxyConfigService>* config_service,
base::Callback<void(int)> callback) {
switch (experiment) {
case ConnectionTester::PROXY_EXPERIMENT_USE_SYSTEM_SETTINGS:
return CreateSystemProxyConfigService(config_service);
case ConnectionTester::PROXY_EXPERIMENT_USE_FIREFOX_SETTINGS:
return CreateFirefoxProxyConfigService(config_service, callback);
case ConnectionTester::PROXY_EXPERIMENT_USE_AUTO_DETECT:
config_service->reset(new net::ProxyConfigServiceFixed(
net::ProxyConfig::CreateAutoDetect()));
return net::OK;
case ConnectionTester::PROXY_EXPERIMENT_USE_DIRECT:
config_service->reset(new net::ProxyConfigServiceFixed(
net::ProxyConfig::CreateDirect()));
return net::OK;
default:
NOTREACHED();
return net::ERR_UNEXPECTED;
}
}
int Init(const ConnectionTester::Experiment& experiment,
scoped_ptr<net::ProxyConfigService>* proxy_config_service,
net::NetLog* net_log) {
int rv;
scoped_ptr<net::HostResolver> host_resolver_tmp;
rv = CreateHostResolver(experiment.host_resolver_experiment,
&host_resolver_tmp);
if (rv != net::OK)
return rv;
storage_.set_host_resolver(host_resolver_tmp.Pass());
scoped_ptr<net::ProxyService> experiment_proxy_service;
rv = CreateProxyService(experiment.proxy_settings_experiment,
proxy_config_service, &experiment_proxy_service);
if (rv != net::OK)
return rv;
storage_.set_proxy_service(experiment_proxy_service.release());
storage_.set_cert_verifier(net::CertVerifier::CreateDefault());
storage_.set_transport_security_state(new net::TransportSecurityState);
storage_.set_ssl_config_service(new net::SSLConfigServiceDefaults);
storage_.set_http_auth_handler_factory(
net::HttpAuthHandlerFactory::CreateDefault(host_resolver()));
storage_.set_http_server_properties(
scoped_ptr<net::HttpServerProperties>(
new net::HttpServerPropertiesImpl()));
net::HttpNetworkSession::Params session_params;
session_params.host_resolver = host_resolver();
session_params.cert_verifier = cert_verifier();
session_params.transport_security_state = transport_security_state();
session_params.proxy_service = proxy_service();
session_params.ssl_config_service = ssl_config_service();
session_params.http_auth_handler_factory = http_auth_handler_factory();
session_params.http_server_properties = http_server_properties();
session_params.net_log = net_log;
scoped_refptr<net::HttpNetworkSession> network_session(
new net::HttpNetworkSession(session_params));
storage_.set_http_transaction_factory(new net::HttpCache(
network_session.get(), net::HttpCache::DefaultBackend::InMemory(0)));
storage_.set_cookie_store(
content::CreateCookieStore(content::CookieStoreConfig()));
return net::OK;
}
private:
int CreateHostResolver(
ConnectionTester::HostResolverExperiment experiment,
scoped_ptr<net::HostResolver>* host_resolver) {
const size_t kMaxJobs = 50u;
const size_t kMaxRetryAttempts = 4u;
net::HostResolver::Options options;
options.max_concurrent_resolves = kMaxJobs;
options.max_retry_attempts = kMaxRetryAttempts;
options.enable_caching = false;
scoped_ptr<net::HostResolver> resolver(
net::HostResolver::CreateSystemResolver(options, NULL ));
switch (experiment) {
case ConnectionTester::HOST_RESOLVER_EXPERIMENT_PLAIN:
break;
case ConnectionTester::HOST_RESOLVER_EXPERIMENT_DISABLE_IPV6:
resolver->SetDefaultAddressFamily(net::ADDRESS_FAMILY_IPV4);
break;
case ConnectionTester::HOST_RESOLVER_EXPERIMENT_IPV6_PROBE: {
break;
}
default:
NOTREACHED();
return net::ERR_UNEXPECTED;
}
host_resolver->swap(resolver);
return net::OK;
}
int CreateProxyService(
ConnectionTester::ProxySettingsExperiment experiment,
scoped_ptr<net::ProxyConfigService>* proxy_config_service,
scoped_ptr<net::ProxyService>* experiment_proxy_service) {
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSingleProcess)) {
return net::ERR_NOT_IMPLEMENTED;
}
net::DhcpProxyScriptFetcherFactory dhcp_factory;
#if defined(OS_IOS)
experiment_proxy_service->reset(
net::ProxyService::CreateUsingSystemProxyResolver(
proxy_config_service->release(), 0u, NULL));
#else
experiment_proxy_service->reset(
net::CreateProxyServiceUsingV8ProxyResolver(
proxy_config_service->release(),
new net::ProxyScriptFetcherImpl(proxy_request_context_),
dhcp_factory.Create(proxy_request_context_),
host_resolver(),
NULL,
NULL));
#endif
return net::OK;
}
int CreateSystemProxyConfigService(
scoped_ptr<net::ProxyConfigService>* config_service) {
#if defined(OS_LINUX) || defined(OS_OPENBSD)
return net::ERR_NOT_IMPLEMENTED;
#else
config_service->reset(net::ProxyService::CreateSystemProxyConfigService(
base::ThreadTaskRunnerHandle::Get().get(), NULL));
return net::OK;
#endif
}
#if !defined(OS_ANDROID) && !defined(OS_IOS)
static int FirefoxProxySettingsTask(
FirefoxProxySettings* firefox_settings) {
if (!FirefoxProxySettings::GetSettings(firefox_settings))
return net::ERR_FILE_NOT_FOUND;
return net::OK;
}
void FirefoxProxySettingsReply(
scoped_ptr<net::ProxyConfigService>* config_service,
FirefoxProxySettings* firefox_settings,
base::Callback<void(int)> callback,
int rv) {
if (rv == net::OK) {
if (FirefoxProxySettings::SYSTEM == firefox_settings->config_type()) {
rv = CreateSystemProxyConfigService(config_service);
} else {
net::ProxyConfig config;
if (firefox_settings->ToProxyConfig(&config))
config_service->reset(new net::ProxyConfigServiceFixed(config));
else
rv = net::ERR_FAILED;
}
}
callback.Run(rv);
}
#endif
int CreateFirefoxProxyConfigService(
scoped_ptr<net::ProxyConfigService>* config_service,
base::Callback<void(int)> callback) {
#if defined(OS_ANDROID) || defined(OS_IOS)
return net::ERR_NOT_IMPLEMENTED;
#else
FirefoxProxySettings* ff_settings = new FirefoxProxySettings();
base::Callback<int(void)> task = base::Bind(
&FirefoxProxySettingsTask, ff_settings);
base::Callback<void(int)> reply = base::Bind(
&ExperimentURLRequestContext::FirefoxProxySettingsReply,
weak_factory_.GetWeakPtr(), config_service,
base::Owned(ff_settings), callback);
if (!content::BrowserThread::PostTaskAndReplyWithResult<int>(
content::BrowserThread::FILE, FROM_HERE, task, reply))
return net::ERR_FAILED;
return net::ERR_IO_PENDING;
#endif
}
#if !defined(OS_IOS)
net::URLRequestContext* const proxy_request_context_;
#endif
net::URLRequestContextStorage storage_;
base::WeakPtrFactory<ExperimentURLRequestContext> weak_factory_;
};
}
class ConnectionTester::TestRunner : public net::URLRequest::Delegate {
public:
TestRunner(ConnectionTester* tester, net::NetLog* net_log)
: tester_(tester),
net_log_(net_log),
weak_factory_(this) {}
void ProxyConfigServiceCreated(
const Experiment& experiment,
scoped_ptr<net::ProxyConfigService>* proxy_config_service, int status);
void Run(const Experiment& experiment);
virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE;
virtual void OnReadCompleted(net::URLRequest* request,
int bytes_read) OVERRIDE;
private:
static const int kReadBufferSize = 1024;
void ReadBody(net::URLRequest* request);
void OnResponseCompleted(net::URLRequest* request);
void OnExperimentCompletedWithResult(int result);
ConnectionTester* tester_;
scoped_ptr<ExperimentURLRequestContext> request_context_;
scoped_ptr<net::URLRequest> request_;
net::NetLog* net_log_;
base::WeakPtrFactory<TestRunner> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(TestRunner);
};
void ConnectionTester::TestRunner::OnResponseStarted(net::URLRequest* request) {
if (!request->status().is_success()) {
OnResponseCompleted(request);
return;
}
ReadBody(request);
}
void ConnectionTester::TestRunner::OnReadCompleted(net::URLRequest* request,
int bytes_read) {
if (bytes_read <= 0) {
OnResponseCompleted(request);
return;
}
ReadBody(request);
}
void ConnectionTester::TestRunner::ReadBody(net::URLRequest* request) {
scoped_refptr<net::IOBuffer> unused_buffer(
new net::IOBuffer(kReadBufferSize));
int num_bytes;
if (request->Read(unused_buffer.get(), kReadBufferSize, &num_bytes)) {
OnReadCompleted(request, num_bytes);
} else if (!request->status().is_io_pending()) {
OnResponseCompleted(request);
}
}
void ConnectionTester::TestRunner::OnResponseCompleted(
net::URLRequest* request) {
int result = net::OK;
if (!request->status().is_success()) {
DCHECK_NE(net::ERR_IO_PENDING, request->status().error());
result = request->status().error();
}
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&TestRunner::OnExperimentCompletedWithResult,
weak_factory_.GetWeakPtr(), result));
}
void ConnectionTester::TestRunner::OnExperimentCompletedWithResult(int result) {
tester_->OnExperimentCompleted(result);
}
void ConnectionTester::TestRunner::ProxyConfigServiceCreated(
const Experiment& experiment,
scoped_ptr<net::ProxyConfigService>* proxy_config_service,
int status) {
if (status == net::OK)
status = request_context_->Init(experiment,
proxy_config_service,
net_log_);
if (status != net::OK) {
tester_->OnExperimentCompleted(status);
return;
}
request_ = request_context_->CreateRequest(
experiment.url, net::DEFAULT_PRIORITY, this, NULL);
request_->Start();
}
void ConnectionTester::TestRunner::Run(const Experiment& experiment) {
request_context_.reset(
new ExperimentURLRequestContext(tester_->proxy_request_context_));
scoped_ptr<net::ProxyConfigService>* proxy_config_service =
new scoped_ptr<net::ProxyConfigService>();
base::Callback<void(int)> config_service_callback =
base::Bind(
&TestRunner::ProxyConfigServiceCreated, weak_factory_.GetWeakPtr(),
experiment, base::Owned(proxy_config_service));
int rv = request_context_->CreateProxyConfigService(
experiment.proxy_settings_experiment,
proxy_config_service, config_service_callback);
if (rv != net::ERR_IO_PENDING)
ProxyConfigServiceCreated(experiment, proxy_config_service, rv);
}
ConnectionTester::ConnectionTester(
Delegate* delegate,
net::URLRequestContext* proxy_request_context,
net::NetLog* net_log)
: delegate_(delegate),
proxy_request_context_(proxy_request_context),
net_log_(net_log) {
DCHECK(delegate);
DCHECK(proxy_request_context);
}
ConnectionTester::~ConnectionTester() {
}
void ConnectionTester::RunAllTests(const GURL& url) {
GetAllPossibleExperimentCombinations(url, &remaining_experiments_);
delegate_->OnStartConnectionTestSuite();
StartNextExperiment();
}
base::string16 ConnectionTester::ProxySettingsExperimentDescription(
ProxySettingsExperiment experiment) {
switch (experiment) {
case PROXY_EXPERIMENT_USE_DIRECT:
return base::ASCIIToUTF16("Don't use any proxy");
case PROXY_EXPERIMENT_USE_SYSTEM_SETTINGS:
return base::ASCIIToUTF16("Use system proxy settings");
case PROXY_EXPERIMENT_USE_FIREFOX_SETTINGS:
return base::ASCIIToUTF16("Use Firefox's proxy settings");
case PROXY_EXPERIMENT_USE_AUTO_DETECT:
return base::ASCIIToUTF16("Auto-detect proxy settings");
default:
NOTREACHED();
return base::string16();
}
}
base::string16 ConnectionTester::HostResolverExperimentDescription(
HostResolverExperiment experiment) {
switch (experiment) {
case HOST_RESOLVER_EXPERIMENT_PLAIN:
return base::string16();
case HOST_RESOLVER_EXPERIMENT_DISABLE_IPV6:
return base::ASCIIToUTF16("Disable IPv6 host resolving");
case HOST_RESOLVER_EXPERIMENT_IPV6_PROBE:
return base::ASCIIToUTF16("Probe for IPv6 host resolving");
default:
NOTREACHED();
return base::string16();
}
}
void ConnectionTester::GetAllPossibleExperimentCombinations(
const GURL& url,
ConnectionTester::ExperimentList* list) {
list->clear();
for (size_t resolver_experiment = 0;
resolver_experiment < HOST_RESOLVER_EXPERIMENT_COUNT;
++resolver_experiment) {
for (size_t proxy_experiment = 0;
proxy_experiment < PROXY_EXPERIMENT_COUNT;
++proxy_experiment) {
Experiment experiment(
url,
static_cast<ProxySettingsExperiment>(proxy_experiment),
static_cast<HostResolverExperiment>(resolver_experiment));
list->push_back(experiment);
}
}
}
void ConnectionTester::StartNextExperiment() {
DCHECK(!remaining_experiments_.empty());
DCHECK(!current_test_runner_.get());
delegate_->OnStartConnectionTestExperiment(current_experiment());
current_test_runner_.reset(new TestRunner(this, net_log_));
current_test_runner_->Run(current_experiment());
}
void ConnectionTester::OnExperimentCompleted(int result) {
Experiment current = current_experiment();
remaining_experiments_.erase(remaining_experiments_.begin());
current_test_runner_.reset();
delegate_->OnCompletedConnectionTestExperiment(current, result);
if (remaining_experiments_.empty()) {
delegate_->OnCompletedConnectionTestSuite();
} else {
StartNextExperiment();
}
}