172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/net/connection_tester.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/command_line.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/compiler_specific.h"
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h"
1172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/task.h"
123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread_restrictions.h"
133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/importer/firefox_proxy_settings.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_switches.h"
1621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "net/base/cert_verifier.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/cookie_monster.h"
18731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "net/base/dnsrr_resolver.h"
19731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "net/base/host_resolver.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/host_resolver_impl.h"
213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/base/io_buffer.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_errors.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_util.h"
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/ssl_config_service_defaults.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/ftp/ftp_network_layer.h"
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/http/http_auth_handler_factory.h"
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/http/http_cache.h"
2872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "net/http/http_network_session.h"
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/proxy/proxy_config_service_fixed.h"
3021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "net/proxy/proxy_script_fetcher_impl.h"
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/url_request/url_request.h"
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/url_request/url_request_context.h"
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// ExperimentURLRequestContext ------------------------------------------------
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// An instance of ExperimentURLRequestContext is created for each experiment
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// run by ConnectionTester. The class initializes network dependencies according
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// to the specified "experiment".
4172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenclass ExperimentURLRequestContext : public net::URLRequestContext {
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
4372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  explicit ExperimentURLRequestContext(
4472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      net::URLRequestContext* proxy_request_context)
4521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      : proxy_request_context_(proxy_request_context) {}
46731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int Init(const ConnectionTester::Experiment& experiment) {
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int rv;
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Create a custom HostResolver for this experiment.
51dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    net::HostResolver* host_resolver_tmp = NULL;
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rv = CreateHostResolver(experiment.host_resolver_experiment,
53dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                            &host_resolver_tmp);
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (rv != net::OK)
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return rv;  // Failure.
56dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    set_host_resolver(host_resolver_tmp);
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Create a custom ProxyService for this this experiment.
59dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    scoped_refptr<net::ProxyService> proxy_service_tmp = NULL;
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rv = CreateProxyService(experiment.proxy_settings_experiment,
61dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                            &proxy_service_tmp);
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (rv != net::OK)
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return rv;  // Failure.
64dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    set_proxy_service(proxy_service_tmp);
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The rest of the dependencies are standard, and don't depend on the
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // experiment being run.
68dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    set_cert_verifier(new net::CertVerifier);
69dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    set_dnsrr_resolver(new net::DnsRRResolver);
70dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    set_ftp_transaction_factory(new net::FtpNetworkLayer(host_resolver_tmp));
71dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    set_ssl_config_service(new net::SSLConfigServiceDefaults);
72dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    set_http_auth_handler_factory(net::HttpAuthHandlerFactory::CreateDefault(
73dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        host_resolver_tmp));
7472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
7572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    net::HttpNetworkSession::Params session_params;
76dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    session_params.host_resolver = host_resolver_tmp;
77dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    session_params.dnsrr_resolver = dnsrr_resolver();
78dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    session_params.cert_verifier = cert_verifier();
79dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    session_params.proxy_service = proxy_service_tmp;
80dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    session_params.http_auth_handler_factory = http_auth_handler_factory();
81dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    session_params.ssl_config_service = ssl_config_service();
8272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    scoped_refptr<net::HttpNetworkSession> network_session(
8372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        new net::HttpNetworkSession(session_params));
84dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    set_http_transaction_factory(new net::HttpCache(
8572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        network_session,
86dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        net::HttpCache::DefaultBackend::InMemory(0)));
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // In-memory cookie store.
88dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    set_cookie_store(new net::CookieMonster(NULL, NULL));
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return net::OK;
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch protected:
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual ~ExperimentURLRequestContext() {
95dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    delete ftp_transaction_factory();
96dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    delete http_transaction_factory();
97dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    delete http_auth_handler_factory();
98dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    delete dnsrr_resolver();
99dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    delete cert_verifier();
100dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    delete host_resolver();
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Creates a host resolver for |experiment|. On success returns net::OK and
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // fills |host_resolver| with a new pointer. Otherwise returns a network
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // error code.
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int CreateHostResolver(
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ConnectionTester::HostResolverExperiment experiment,
109731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      net::HostResolver** host_resolver) {
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Create a vanilla HostResolver that disables caching.
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const size_t kMaxJobs = 50u;
112731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    net::HostResolverImpl* impl =
1133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        new net::HostResolverImpl(NULL, NULL, kMaxJobs, NULL);
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *host_resolver = impl;
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Modify it slightly based on the experiment being run.
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    switch (experiment) {
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case ConnectionTester::HOST_RESOLVER_EXPERIMENT_PLAIN:
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return net::OK;
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case ConnectionTester::HOST_RESOLVER_EXPERIMENT_DISABLE_IPV6:
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        impl->SetDefaultAddressFamily(net::ADDRESS_FAMILY_IPV4);
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return net::OK;
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case ConnectionTester::HOST_RESOLVER_EXPERIMENT_IPV6_PROBE: {
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Note that we don't use impl->ProbeIPv6Support() since that finishes
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // asynchronously and may not take effect in time for the test.
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // So instead we will probe synchronously (might take 100-200 ms).
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        net::AddressFamily family = net::IPv6Supported() ?
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            net::ADDRESS_FAMILY_UNSPECIFIED : net::ADDRESS_FAMILY_IPV4;
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        impl->SetDefaultAddressFamily(family);
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return net::OK;
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      default:
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NOTREACHED();
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return net::ERR_UNEXPECTED;
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Creates a proxy config service for |experiment|. On success returns net::OK
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // and fills |config_service| with a new pointer. Otherwise returns a network
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // error code.
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int CreateProxyConfigService(
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ConnectionTester::ProxySettingsExperiment experiment,
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      scoped_ptr<net::ProxyConfigService>* config_service) {
14521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    scoped_ptr<base::ThreadRestrictions::ScopedAllowIO> allow_io;
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    switch (experiment) {
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case ConnectionTester::PROXY_EXPERIMENT_USE_SYSTEM_SETTINGS:
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return CreateSystemProxyConfigService(config_service);
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case ConnectionTester::PROXY_EXPERIMENT_USE_FIREFOX_SETTINGS:
15021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        // http://crbug.com/67664: This call can lead to blocking IO on the IO
15121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        // thread.  This is a bug and should be fixed.
15221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        allow_io.reset(new base::ThreadRestrictions::ScopedAllowIO);
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return CreateFirefoxProxyConfigService(config_service);
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case ConnectionTester::PROXY_EXPERIMENT_USE_AUTO_DETECT:
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        config_service->reset(new net::ProxyConfigServiceFixed(
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            net::ProxyConfig::CreateAutoDetect()));
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return net::OK;
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case ConnectionTester::PROXY_EXPERIMENT_USE_DIRECT:
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        config_service->reset(new net::ProxyConfigServiceFixed(
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            net::ProxyConfig::CreateDirect()));
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return net::OK;
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      default:
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NOTREACHED();
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return net::ERR_UNEXPECTED;
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Creates a proxy service for |experiment|. On success returns net::OK
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // and fills |config_service| with a new pointer. Otherwise returns a network
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // error code.
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int CreateProxyService(
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ConnectionTester::ProxySettingsExperiment experiment,
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      scoped_refptr<net::ProxyService>* proxy_service) {
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Create an appropriate proxy config service.
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<net::ProxyConfigService> config_service;
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int rv = CreateProxyConfigService(experiment, &config_service);
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (rv != net::OK)
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return rv;  // Failure.
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (CommandLine::ForCurrentProcess()->HasSwitch(
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        switches::kSingleProcess)) {
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We can't create a standard proxy resolver in single-process mode.
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Rather than falling-back to some other implementation, fail.
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return net::ERR_NOT_IMPLEMENTED;
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
187731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    *proxy_service = net::ProxyService::CreateUsingV8ProxyResolver(
188731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        config_service.release(),
189731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        0u,
19021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        new net::ProxyScriptFetcherImpl(proxy_request_context_),
191731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        host_resolver(),
192731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        NULL);
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return net::OK;
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Creates a proxy config service that pulls from the system proxy settings.
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // On success returns net::OK and fills |config_service| with a new pointer.
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Otherwise returns a network error code.
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int CreateSystemProxyConfigService(
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      scoped_ptr<net::ProxyConfigService>* config_service) {
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_LINUX)
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(eroman): This is not supported on Linux yet, because of how
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // construction needs ot happen on the UI thread.
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return net::ERR_NOT_IMPLEMENTED;
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    config_service->reset(
2083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        net::ProxyService::CreateSystemProxyConfigService(
2093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            MessageLoop::current(), NULL));
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return net::OK;
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Creates a fixed proxy config service that is initialized using Firefox's
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // current proxy settings. On success returns net::OK and fills
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // |config_service| with a new pointer. Otherwise returns a network error
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // code.
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int CreateFirefoxProxyConfigService(
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      scoped_ptr<net::ProxyConfigService>* config_service) {
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Fetch Firefox's proxy settings (can fail if Firefox is not installed).
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    FirefoxProxySettings firefox_settings;
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!FirefoxProxySettings::GetSettings(&firefox_settings))
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return net::ERR_FILE_NOT_FOUND;
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (FirefoxProxySettings::SYSTEM == firefox_settings.config_type())
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return CreateSystemProxyConfigService(config_service);
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    net::ProxyConfig config;
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (firefox_settings.ToProxyConfig(&config)) {
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      config_service->reset(new net::ProxyConfigServiceFixed(config));
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return net::OK;
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return net::ERR_FAILED;
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
236731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
23772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  const scoped_refptr<net::URLRequestContext> proxy_request_context_;
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// ConnectionTester::TestRunner ----------------------------------------------
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TestRunner is a helper class for running an individual experiment. It can
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// be deleted any time after it is started, and this will abort the request.
24621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenclass ConnectionTester::TestRunner : public net::URLRequest::Delegate {
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // |tester| must remain alive throughout the TestRunner's lifetime.
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // |tester| will be notified of completion.
25072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  explicit TestRunner(ConnectionTester* tester)
25172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      : tester_(tester),
25272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {}
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Starts running |experiment|. Notifies tester->OnExperimentCompleted() when
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // it is done.
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Run(const Experiment& experiment);
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
25821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Overridden from net::URLRequest::Delegate:
25921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  virtual void OnResponseStarted(net::URLRequest* request);
26021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  virtual void OnReadCompleted(net::URLRequest* request, int bytes_read);
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(eroman): handle cases requiring authentication.
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The number of bytes to read each response body chunk.
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const int kReadBufferSize = 1024;
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Starts reading the response's body (and keeps reading until an error or
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // end of stream).
26921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  void ReadBody(net::URLRequest* request);
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Called when the request has completed (for both success and failure).
27221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  void OnResponseCompleted(net::URLRequest* request);
27372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  void OnExperimentCompletedWithResult(int result);
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ConnectionTester* tester_;
27621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  scoped_ptr<net::URLRequest> request_;
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
27872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ScopedRunnableMethodFactory<TestRunner> method_factory_;
27972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(TestRunner);
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
28321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid ConnectionTester::TestRunner::OnResponseStarted(net::URLRequest* request) {
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!request->status().is_success()) {
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OnResponseCompleted(request);
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Start reading the body.
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ReadBody(request);
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
29321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid ConnectionTester::TestRunner::OnReadCompleted(net::URLRequest* request,
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                   int bytes_read) {
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (bytes_read <= 0) {
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OnResponseCompleted(request);
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Keep reading until the stream is closed. Throw the data read away.
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ReadBody(request);
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
30421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid ConnectionTester::TestRunner::ReadBody(net::URLRequest* request) {
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Read the response body |kReadBufferSize| bytes at a time.
306513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_refptr<net::IOBuffer> unused_buffer(
307513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      new net::IOBuffer(kReadBufferSize));
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int num_bytes;
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->Read(unused_buffer, kReadBufferSize, &num_bytes)) {
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OnReadCompleted(request, num_bytes);
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (!request->status().is_io_pending()) {
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Read failed synchronously.
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OnResponseCompleted(request);
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
31721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid ConnectionTester::TestRunner::OnResponseCompleted(
31821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    net::URLRequest* request) {
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int result = net::OK;
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!request->status().is_success()) {
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK_NE(net::ERR_IO_PENDING, request->status().os_error());
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result = request->status().os_error();
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
32472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
32572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Post a task to notify the parent rather than handling it right away,
32672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // to avoid re-entrancy problems with URLRequest. (Don't want the caller
32772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // to end up deleting the URLRequest while in the middle of processing).
32872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  MessageLoop::current()->PostTask(
32972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      FROM_HERE,
33072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      method_factory_.NewRunnableMethod(
33172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          &TestRunner::OnExperimentCompletedWithResult, result));
33272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
33372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
33472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ConnectionTester::TestRunner::OnExperimentCompletedWithResult(int result) {
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tester_->OnExperimentCompleted(result);
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ConnectionTester::TestRunner::Run(const Experiment& experiment) {
33972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Try to create a net::URLRequestContext for this experiment.
340513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_refptr<ExperimentURLRequestContext> context(
34121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      new ExperimentURLRequestContext(tester_->proxy_request_context_));
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int rv = context->Init(experiment);
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv != net::OK) {
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Complete the experiment with a failure.
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tester_->OnExperimentCompleted(rv);
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Fetch a request using the experimental context.
35021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  request_.reset(new net::URLRequest(experiment.url, this));
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request_->set_context(context);
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request_->Start();
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// ConnectionTester ----------------------------------------------------------
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
35772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenConnectionTester::ConnectionTester(
35872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    Delegate* delegate,
35972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    net::URLRequestContext* proxy_request_context)
36021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    : delegate_(delegate), proxy_request_context_(proxy_request_context) {
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(delegate);
36221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(proxy_request_context);
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochConnectionTester::~ConnectionTester() {
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Cancellation happens automatically by deleting test_runner_.
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ConnectionTester::RunAllTests(const GURL& url) {
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Select all possible experiments to run. (In no particular order).
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // It is possible that some of these experiments are actually duplicates.
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetAllPossibleExperimentCombinations(url, &remaining_experiments_);
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delegate_->OnStartConnectionTestSuite();
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StartNextExperiment();
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstring16 ConnectionTester::ProxySettingsExperimentDescription(
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ProxySettingsExperiment experiment) {
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(eroman): Use proper string resources.
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (experiment) {
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case PROXY_EXPERIMENT_USE_DIRECT:
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return ASCIIToUTF16("Don't use any proxy");
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case PROXY_EXPERIMENT_USE_SYSTEM_SETTINGS:
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return ASCIIToUTF16("Use system proxy settings");
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case PROXY_EXPERIMENT_USE_FIREFOX_SETTINGS:
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return ASCIIToUTF16("Use Firefox's proxy settings");
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case PROXY_EXPERIMENT_USE_AUTO_DETECT:
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return ASCIIToUTF16("Auto-detect proxy settings");
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default:
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return string16();
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstring16 ConnectionTester::HostResolverExperimentDescription(
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    HostResolverExperiment experiment) {
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(eroman): Use proper string resources.
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (experiment) {
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case HOST_RESOLVER_EXPERIMENT_PLAIN:
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return string16();
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case HOST_RESOLVER_EXPERIMENT_DISABLE_IPV6:
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return ASCIIToUTF16("Disable IPv6 host resolving");
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case HOST_RESOLVER_EXPERIMENT_IPV6_PROBE:
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return ASCIIToUTF16("Probe for IPv6 host resolving");
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default:
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return string16();
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ConnectionTester::GetAllPossibleExperimentCombinations(
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL& url,
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ConnectionTester::ExperimentList* list) {
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  list->clear();
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t resolver_experiment = 0;
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       resolver_experiment < HOST_RESOLVER_EXPERIMENT_COUNT;
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       ++resolver_experiment) {
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (size_t proxy_experiment = 0;
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         proxy_experiment < PROXY_EXPERIMENT_COUNT;
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         ++proxy_experiment) {
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Experiment experiment(
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          url,
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          static_cast<ProxySettingsExperiment>(proxy_experiment),
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          static_cast<HostResolverExperiment>(resolver_experiment));
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      list->push_back(experiment);
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ConnectionTester::StartNextExperiment() {
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!remaining_experiments_.empty());
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!current_test_runner_.get());
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delegate_->OnStartConnectionTestExperiment(current_experiment());
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  current_test_runner_.reset(new TestRunner(this));
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  current_test_runner_->Run(current_experiment());
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ConnectionTester::OnExperimentCompleted(int result) {
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Experiment current = current_experiment();
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Advance to the next experiment.
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  remaining_experiments_.erase(remaining_experiments_.begin());
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  current_test_runner_.reset();
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Notify the delegate of completion.
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delegate_->OnCompletedConnectionTestExperiment(current, result);
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (remaining_experiments_.empty()) {
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delegate_->OnCompletedConnectionTestSuite();
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    StartNextExperiment();
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
460