seccomp-bpf: Remove legacy SandboxBPFPolicy class
[chromium-blink-merge.git] / chrome / browser / net / connection_tester.cc
blob703eefa16b7f9475f7fb1d7b83e849663391ef44
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/net/connection_tester.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/compiler_specific.h"
10 #include "base/logging.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "base/threading/thread_restrictions.h"
16 #include "chrome/common/chrome_switches.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/cookie_store_factory.h"
19 #include "net/base/io_buffer.h"
20 #include "net/base/net_errors.h"
21 #include "net/base/net_util.h"
22 #include "net/base/request_priority.h"
23 #include "net/cert/cert_verifier.h"
24 #include "net/dns/host_resolver.h"
25 #include "net/http/http_auth_handler_factory.h"
26 #include "net/http/http_cache.h"
27 #include "net/http/http_network_session.h"
28 #include "net/http/http_server_properties_impl.h"
29 #include "net/http/transport_security_state.h"
30 #include "net/proxy/dhcp_proxy_script_fetcher_factory.h"
31 #include "net/proxy/proxy_config_service_fixed.h"
32 #include "net/proxy/proxy_script_fetcher_impl.h"
33 #include "net/proxy/proxy_service.h"
34 #include "net/proxy/proxy_service_v8.h"
35 #include "net/ssl/ssl_config_service_defaults.h"
36 #include "net/url_request/url_request.h"
37 #include "net/url_request/url_request_context.h"
38 #include "net/url_request/url_request_context_storage.h"
39 #include "net/url_request/url_request_job_factory_impl.h"
41 #if !defined(OS_ANDROID) && !defined(OS_IOS)
42 #include "chrome/browser/net/firefox_proxy_settings.h"
43 #endif
45 namespace {
47 // ExperimentURLRequestContext ------------------------------------------------
49 // An instance of ExperimentURLRequestContext is created for each experiment
50 // run by ConnectionTester. The class initializes network dependencies according
51 // to the specified "experiment".
52 class ExperimentURLRequestContext : public net::URLRequestContext {
53 public:
54 explicit ExperimentURLRequestContext(
55 net::URLRequestContext* proxy_request_context) :
56 #if !defined(OS_IOS)
57 proxy_request_context_(proxy_request_context),
58 #endif
59 storage_(this),
60 weak_factory_(this) {}
62 virtual ~ExperimentURLRequestContext() {
63 AssertNoURLRequests();
66 // Creates a proxy config service for |experiment|. On success returns net::OK
67 // and fills |config_service| with a new pointer. Otherwise returns a network
68 // error code.
69 int CreateProxyConfigService(
70 ConnectionTester::ProxySettingsExperiment experiment,
71 scoped_ptr<net::ProxyConfigService>* config_service,
72 base::Callback<void(int)> callback) {
73 switch (experiment) {
74 case ConnectionTester::PROXY_EXPERIMENT_USE_SYSTEM_SETTINGS:
75 return CreateSystemProxyConfigService(config_service);
76 case ConnectionTester::PROXY_EXPERIMENT_USE_FIREFOX_SETTINGS:
77 return CreateFirefoxProxyConfigService(config_service, callback);
78 case ConnectionTester::PROXY_EXPERIMENT_USE_AUTO_DETECT:
79 config_service->reset(new net::ProxyConfigServiceFixed(
80 net::ProxyConfig::CreateAutoDetect()));
81 return net::OK;
82 case ConnectionTester::PROXY_EXPERIMENT_USE_DIRECT:
83 config_service->reset(new net::ProxyConfigServiceFixed(
84 net::ProxyConfig::CreateDirect()));
85 return net::OK;
86 default:
87 NOTREACHED();
88 return net::ERR_UNEXPECTED;
92 int Init(const ConnectionTester::Experiment& experiment,
93 scoped_ptr<net::ProxyConfigService>* proxy_config_service,
94 net::NetLog* net_log) {
95 int rv;
97 // Create a custom HostResolver for this experiment.
98 scoped_ptr<net::HostResolver> host_resolver_tmp;
99 rv = CreateHostResolver(experiment.host_resolver_experiment,
100 &host_resolver_tmp);
101 if (rv != net::OK)
102 return rv; // Failure.
103 storage_.set_host_resolver(host_resolver_tmp.Pass());
105 // Create a custom ProxyService for this this experiment.
106 scoped_ptr<net::ProxyService> experiment_proxy_service;
107 rv = CreateProxyService(experiment.proxy_settings_experiment,
108 proxy_config_service, &experiment_proxy_service);
109 if (rv != net::OK)
110 return rv; // Failure.
111 storage_.set_proxy_service(experiment_proxy_service.release());
113 // The rest of the dependencies are standard, and don't depend on the
114 // experiment being run.
115 storage_.set_cert_verifier(net::CertVerifier::CreateDefault());
116 storage_.set_transport_security_state(new net::TransportSecurityState);
117 storage_.set_ssl_config_service(new net::SSLConfigServiceDefaults);
118 storage_.set_http_auth_handler_factory(
119 net::HttpAuthHandlerFactory::CreateDefault(host_resolver()));
120 storage_.set_http_server_properties(
121 scoped_ptr<net::HttpServerProperties>(
122 new net::HttpServerPropertiesImpl()));
124 net::HttpNetworkSession::Params session_params;
125 session_params.host_resolver = host_resolver();
126 session_params.cert_verifier = cert_verifier();
127 session_params.transport_security_state = transport_security_state();
128 session_params.proxy_service = proxy_service();
129 session_params.ssl_config_service = ssl_config_service();
130 session_params.http_auth_handler_factory = http_auth_handler_factory();
131 session_params.http_server_properties = http_server_properties();
132 session_params.net_log = net_log;
133 scoped_refptr<net::HttpNetworkSession> network_session(
134 new net::HttpNetworkSession(session_params));
135 storage_.set_http_transaction_factory(new net::HttpCache(
136 network_session.get(), net::HttpCache::DefaultBackend::InMemory(0)));
137 // In-memory cookie store.
138 storage_.set_cookie_store(
139 content::CreateCookieStore(content::CookieStoreConfig()));
140 // Creating a new job factory avoids added ProtocolHandlers and
141 // layered URLRequestInterceptingJobFactories.
142 storage_.set_job_factory(new net::URLRequestJobFactoryImpl());
144 return net::OK;
147 private:
148 // Creates a host resolver for |experiment|. On success returns net::OK and
149 // fills |host_resolver| with a new pointer. Otherwise returns a network
150 // error code.
151 int CreateHostResolver(
152 ConnectionTester::HostResolverExperiment experiment,
153 scoped_ptr<net::HostResolver>* host_resolver) {
154 // Create a vanilla HostResolver that disables caching.
155 const size_t kMaxJobs = 50u;
156 const size_t kMaxRetryAttempts = 4u;
157 net::HostResolver::Options options;
158 options.max_concurrent_resolves = kMaxJobs;
159 options.max_retry_attempts = kMaxRetryAttempts;
160 options.enable_caching = false;
161 scoped_ptr<net::HostResolver> resolver(
162 net::HostResolver::CreateSystemResolver(options, NULL /* NetLog */));
164 // Modify it slightly based on the experiment being run.
165 switch (experiment) {
166 case ConnectionTester::HOST_RESOLVER_EXPERIMENT_PLAIN:
167 break;
168 case ConnectionTester::HOST_RESOLVER_EXPERIMENT_DISABLE_IPV6:
169 resolver->SetDefaultAddressFamily(net::ADDRESS_FAMILY_IPV4);
170 break;
171 case ConnectionTester::HOST_RESOLVER_EXPERIMENT_IPV6_PROBE: {
172 // The system HostResolver will probe by default.
173 break;
175 default:
176 NOTREACHED();
177 return net::ERR_UNEXPECTED;
179 host_resolver->swap(resolver);
180 return net::OK;
183 // Creates a proxy service for |experiment|. On success returns net::OK
184 // and fills |experiment_proxy_service| with a new pointer. Otherwise returns
185 // a network error code.
186 int CreateProxyService(
187 ConnectionTester::ProxySettingsExperiment experiment,
188 scoped_ptr<net::ProxyConfigService>* proxy_config_service,
189 scoped_ptr<net::ProxyService>* experiment_proxy_service) {
190 if (CommandLine::ForCurrentProcess()->HasSwitch(
191 switches::kSingleProcess)) {
192 // We can't create a standard proxy resolver in single-process mode.
193 // Rather than falling-back to some other implementation, fail.
194 return net::ERR_NOT_IMPLEMENTED;
197 net::DhcpProxyScriptFetcherFactory dhcp_factory;
199 #if defined(OS_IOS)
200 experiment_proxy_service->reset(
201 net::ProxyService::CreateUsingSystemProxyResolver(
202 proxy_config_service->release(), 0u, NULL));
203 #else
204 experiment_proxy_service->reset(
205 net::CreateProxyServiceUsingV8ProxyResolver(
206 proxy_config_service->release(),
207 new net::ProxyScriptFetcherImpl(proxy_request_context_),
208 dhcp_factory.Create(proxy_request_context_),
209 host_resolver(),
210 NULL,
211 NULL));
212 #endif
214 return net::OK;
217 // Creates a proxy config service that pulls from the system proxy settings.
218 // On success returns net::OK and fills |config_service| with a new pointer.
219 // Otherwise returns a network error code.
220 int CreateSystemProxyConfigService(
221 scoped_ptr<net::ProxyConfigService>* config_service) {
222 #if defined(OS_LINUX) || defined(OS_OPENBSD)
223 // TODO(eroman): This is not supported on Linux yet, because of how
224 // construction needs ot happen on the UI thread.
225 return net::ERR_NOT_IMPLEMENTED;
226 #else
227 config_service->reset(net::ProxyService::CreateSystemProxyConfigService(
228 base::ThreadTaskRunnerHandle::Get().get(), NULL));
229 return net::OK;
230 #endif
233 #if !defined(OS_ANDROID) && !defined(OS_IOS)
234 static int FirefoxProxySettingsTask(
235 FirefoxProxySettings* firefox_settings) {
236 if (!FirefoxProxySettings::GetSettings(firefox_settings))
237 return net::ERR_FILE_NOT_FOUND;
238 return net::OK;
241 void FirefoxProxySettingsReply(
242 scoped_ptr<net::ProxyConfigService>* config_service,
243 FirefoxProxySettings* firefox_settings,
244 base::Callback<void(int)> callback,
245 int rv) {
246 if (rv == net::OK) {
247 if (FirefoxProxySettings::SYSTEM == firefox_settings->config_type()) {
248 rv = CreateSystemProxyConfigService(config_service);
249 } else {
250 net::ProxyConfig config;
251 if (firefox_settings->ToProxyConfig(&config))
252 config_service->reset(new net::ProxyConfigServiceFixed(config));
253 else
254 rv = net::ERR_FAILED;
257 callback.Run(rv);
259 #endif
261 // Creates a fixed proxy config service that is initialized using Firefox's
262 // current proxy settings. On success returns net::OK and fills
263 // |config_service| with a new pointer. Otherwise returns a network error
264 // code.
265 int CreateFirefoxProxyConfigService(
266 scoped_ptr<net::ProxyConfigService>* config_service,
267 base::Callback<void(int)> callback) {
268 #if defined(OS_ANDROID) || defined(OS_IOS)
269 // Chrome on Android and iOS do not support Firefox settings.
270 return net::ERR_NOT_IMPLEMENTED;
271 #else
272 // Fetch Firefox's proxy settings (can fail if Firefox is not installed).
273 FirefoxProxySettings* ff_settings = new FirefoxProxySettings();
274 base::Callback<int(void)> task = base::Bind(
275 &FirefoxProxySettingsTask, ff_settings);
276 base::Callback<void(int)> reply = base::Bind(
277 &ExperimentURLRequestContext::FirefoxProxySettingsReply,
278 weak_factory_.GetWeakPtr(), config_service,
279 base::Owned(ff_settings), callback);
280 if (!content::BrowserThread::PostTaskAndReplyWithResult<int>(
281 content::BrowserThread::FILE, FROM_HERE, task, reply))
282 return net::ERR_FAILED;
283 return net::ERR_IO_PENDING;
284 #endif
287 #if !defined(OS_IOS)
288 net::URLRequestContext* const proxy_request_context_;
289 #endif
290 net::URLRequestContextStorage storage_;
291 base::WeakPtrFactory<ExperimentURLRequestContext> weak_factory_;
294 } // namespace
296 // ConnectionTester::TestRunner ----------------------------------------------
298 // TestRunner is a helper class for running an individual experiment. It can
299 // be deleted any time after it is started, and this will abort the request.
300 class ConnectionTester::TestRunner : public net::URLRequest::Delegate {
301 public:
302 // |tester| must remain alive throughout the TestRunner's lifetime.
303 // |tester| will be notified of completion.
304 TestRunner(ConnectionTester* tester, net::NetLog* net_log)
305 : tester_(tester),
306 net_log_(net_log),
307 weak_factory_(this) {}
309 // Finish running |experiment| once a ProxyConfigService has been created.
310 // In the case of a FirefoxProxyConfigService, this will be called back
311 // after disk access has completed.
312 void ProxyConfigServiceCreated(
313 const Experiment& experiment,
314 scoped_ptr<net::ProxyConfigService>* proxy_config_service, int status);
316 // Starts running |experiment|. Notifies tester->OnExperimentCompleted() when
317 // it is done.
318 void Run(const Experiment& experiment);
320 // Overridden from net::URLRequest::Delegate:
321 virtual void OnResponseStarted(net::URLRequest* request) override;
322 virtual void OnReadCompleted(net::URLRequest* request,
323 int bytes_read) override;
324 // TODO(eroman): handle cases requiring authentication.
326 private:
327 // The number of bytes to read each response body chunk.
328 static const int kReadBufferSize = 1024;
330 // Starts reading the response's body (and keeps reading until an error or
331 // end of stream).
332 void ReadBody(net::URLRequest* request);
334 // Called when the request has completed (for both success and failure).
335 void OnResponseCompleted(net::URLRequest* request);
336 void OnExperimentCompletedWithResult(int result);
338 ConnectionTester* tester_;
339 scoped_ptr<ExperimentURLRequestContext> request_context_;
340 scoped_ptr<net::URLRequest> request_;
341 net::NetLog* net_log_;
343 base::WeakPtrFactory<TestRunner> weak_factory_;
345 DISALLOW_COPY_AND_ASSIGN(TestRunner);
348 void ConnectionTester::TestRunner::OnResponseStarted(net::URLRequest* request) {
349 if (!request->status().is_success()) {
350 OnResponseCompleted(request);
351 return;
354 // Start reading the body.
355 ReadBody(request);
358 void ConnectionTester::TestRunner::OnReadCompleted(net::URLRequest* request,
359 int bytes_read) {
360 if (bytes_read <= 0) {
361 OnResponseCompleted(request);
362 return;
365 // Keep reading until the stream is closed. Throw the data read away.
366 ReadBody(request);
369 void ConnectionTester::TestRunner::ReadBody(net::URLRequest* request) {
370 // Read the response body |kReadBufferSize| bytes at a time.
371 scoped_refptr<net::IOBuffer> unused_buffer(
372 new net::IOBuffer(kReadBufferSize));
373 int num_bytes;
374 if (request->Read(unused_buffer.get(), kReadBufferSize, &num_bytes)) {
375 OnReadCompleted(request, num_bytes);
376 } else if (!request->status().is_io_pending()) {
377 // Read failed synchronously.
378 OnResponseCompleted(request);
382 void ConnectionTester::TestRunner::OnResponseCompleted(
383 net::URLRequest* request) {
384 int result = net::OK;
385 if (!request->status().is_success()) {
386 DCHECK_NE(net::ERR_IO_PENDING, request->status().error());
387 result = request->status().error();
390 // Post a task to notify the parent rather than handling it right away,
391 // to avoid re-entrancy problems with URLRequest. (Don't want the caller
392 // to end up deleting the URLRequest while in the middle of processing).
393 base::MessageLoop::current()->PostTask(
394 FROM_HERE,
395 base::Bind(&TestRunner::OnExperimentCompletedWithResult,
396 weak_factory_.GetWeakPtr(), result));
399 void ConnectionTester::TestRunner::OnExperimentCompletedWithResult(int result) {
400 tester_->OnExperimentCompleted(result);
403 void ConnectionTester::TestRunner::ProxyConfigServiceCreated(
404 const Experiment& experiment,
405 scoped_ptr<net::ProxyConfigService>* proxy_config_service,
406 int status) {
407 if (status == net::OK)
408 status = request_context_->Init(experiment,
409 proxy_config_service,
410 net_log_);
411 if (status != net::OK) {
412 tester_->OnExperimentCompleted(status);
413 return;
415 // Fetch a request using the experimental context.
416 request_ = request_context_->CreateRequest(
417 experiment.url, net::DEFAULT_PRIORITY, this, NULL);
418 request_->Start();
421 void ConnectionTester::TestRunner::Run(const Experiment& experiment) {
422 // Try to create a net::URLRequestContext for this experiment.
423 request_context_.reset(
424 new ExperimentURLRequestContext(tester_->proxy_request_context_));
425 scoped_ptr<net::ProxyConfigService>* proxy_config_service =
426 new scoped_ptr<net::ProxyConfigService>();
427 base::Callback<void(int)> config_service_callback =
428 base::Bind(
429 &TestRunner::ProxyConfigServiceCreated, weak_factory_.GetWeakPtr(),
430 experiment, base::Owned(proxy_config_service));
431 int rv = request_context_->CreateProxyConfigService(
432 experiment.proxy_settings_experiment,
433 proxy_config_service, config_service_callback);
434 if (rv != net::ERR_IO_PENDING)
435 ProxyConfigServiceCreated(experiment, proxy_config_service, rv);
438 // ConnectionTester ----------------------------------------------------------
440 ConnectionTester::ConnectionTester(
441 Delegate* delegate,
442 net::URLRequestContext* proxy_request_context,
443 net::NetLog* net_log)
444 : delegate_(delegate),
445 proxy_request_context_(proxy_request_context),
446 net_log_(net_log) {
447 DCHECK(delegate);
448 DCHECK(proxy_request_context);
451 ConnectionTester::~ConnectionTester() {
452 // Cancellation happens automatically by deleting test_runner_.
455 void ConnectionTester::RunAllTests(const GURL& url) {
456 // Select all possible experiments to run. (In no particular order).
457 // It is possible that some of these experiments are actually duplicates.
458 GetAllPossibleExperimentCombinations(url, &remaining_experiments_);
460 delegate_->OnStartConnectionTestSuite();
461 StartNextExperiment();
464 // static
465 base::string16 ConnectionTester::ProxySettingsExperimentDescription(
466 ProxySettingsExperiment experiment) {
467 // TODO(eroman): Use proper string resources.
468 switch (experiment) {
469 case PROXY_EXPERIMENT_USE_DIRECT:
470 return base::ASCIIToUTF16("Don't use any proxy");
471 case PROXY_EXPERIMENT_USE_SYSTEM_SETTINGS:
472 return base::ASCIIToUTF16("Use system proxy settings");
473 case PROXY_EXPERIMENT_USE_FIREFOX_SETTINGS:
474 return base::ASCIIToUTF16("Use Firefox's proxy settings");
475 case PROXY_EXPERIMENT_USE_AUTO_DETECT:
476 return base::ASCIIToUTF16("Auto-detect proxy settings");
477 default:
478 NOTREACHED();
479 return base::string16();
483 // static
484 base::string16 ConnectionTester::HostResolverExperimentDescription(
485 HostResolverExperiment experiment) {
486 // TODO(eroman): Use proper string resources.
487 switch (experiment) {
488 case HOST_RESOLVER_EXPERIMENT_PLAIN:
489 return base::string16();
490 case HOST_RESOLVER_EXPERIMENT_DISABLE_IPV6:
491 return base::ASCIIToUTF16("Disable IPv6 host resolving");
492 case HOST_RESOLVER_EXPERIMENT_IPV6_PROBE:
493 return base::ASCIIToUTF16("Probe for IPv6 host resolving");
494 default:
495 NOTREACHED();
496 return base::string16();
500 // static
501 void ConnectionTester::GetAllPossibleExperimentCombinations(
502 const GURL& url,
503 ConnectionTester::ExperimentList* list) {
504 list->clear();
505 for (size_t resolver_experiment = 0;
506 resolver_experiment < HOST_RESOLVER_EXPERIMENT_COUNT;
507 ++resolver_experiment) {
508 for (size_t proxy_experiment = 0;
509 proxy_experiment < PROXY_EXPERIMENT_COUNT;
510 ++proxy_experiment) {
511 Experiment experiment(
512 url,
513 static_cast<ProxySettingsExperiment>(proxy_experiment),
514 static_cast<HostResolverExperiment>(resolver_experiment));
515 list->push_back(experiment);
520 void ConnectionTester::StartNextExperiment() {
521 DCHECK(!remaining_experiments_.empty());
522 DCHECK(!current_test_runner_.get());
524 delegate_->OnStartConnectionTestExperiment(current_experiment());
526 current_test_runner_.reset(new TestRunner(this, net_log_));
527 current_test_runner_->Run(current_experiment());
530 void ConnectionTester::OnExperimentCompleted(int result) {
531 Experiment current = current_experiment();
533 // Advance to the next experiment.
534 remaining_experiments_.erase(remaining_experiments_.begin());
535 current_test_runner_.reset();
537 // Notify the delegate of completion.
538 delegate_->OnCompletedConnectionTestExperiment(current, result);
540 if (remaining_experiments_.empty()) {
541 delegate_->OnCompletedConnectionTestSuite();
542 } else {
543 StartNextExperiment();