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