// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_BROWSER_NET_CONNECTION_TESTER_H_ #define CHROME_BROWSER_NET_CONNECTION_TESTER_H_ #include <vector> #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "net/base/completion_callback.h" #include "url/gurl.h" namespace net { class NetLog; class URLRequestContext; } // namespace net // ConnectionTester runs a suite of tests (also called "experiments"), // to try and discover why loading a particular URL is failing with an error // code. // // For example, one reason why the URL might have failed, is that the // network requires the URL to be routed through a proxy, however chrome is // not configured for that. // // The above issue might be detected by running test that fetches the URL using // auto-detect and seeing if it works this time. Or even by retrieving the // settings from another installed browser and trying with those. // // USAGE: // // To run the test suite, create an instance of ConnectionTester and then call // RunAllTests(). // // This starts a sequence of tests, which will complete asynchronously. // The ConnectionTester object can be deleted at any time, and it will abort // any of the in-progress tests. // // As tests are started or completed, notification will be sent through the // "Delegate" object. class ConnectionTester { public: // This enum lists the possible proxy settings configurations. enum ProxySettingsExperiment { // Do not use any proxy. PROXY_EXPERIMENT_USE_DIRECT = 0, // Use the system proxy settings. PROXY_EXPERIMENT_USE_SYSTEM_SETTINGS, // Use Firefox's proxy settings if they are available. PROXY_EXPERIMENT_USE_FIREFOX_SETTINGS, // Use proxy auto-detect. PROXY_EXPERIMENT_USE_AUTO_DETECT, PROXY_EXPERIMENT_COUNT, }; // This enum lists the possible host resolving configurations. enum HostResolverExperiment { // Use a default host resolver implementation. HOST_RESOLVER_EXPERIMENT_PLAIN = 0, // Disable IPv6 host resolving. HOST_RESOLVER_EXPERIMENT_DISABLE_IPV6, // Probe for IPv6 support. HOST_RESOLVER_EXPERIMENT_IPV6_PROBE, HOST_RESOLVER_EXPERIMENT_COUNT, }; // The "Experiment" structure describes an individual test to run. struct Experiment { Experiment(const GURL& url, ProxySettingsExperiment proxy_settings_experiment, HostResolverExperiment host_resolver_experiment) : url(url), proxy_settings_experiment(proxy_settings_experiment), host_resolver_experiment(host_resolver_experiment) { } // The URL to try and fetch. GURL url; // The proxy settings to use. ProxySettingsExperiment proxy_settings_experiment; // The host resolver settings to use. HostResolverExperiment host_resolver_experiment; }; typedef std::vector<Experiment> ExperimentList; // "Delegate" is an interface for receiving start and completion notification // of individual tests that are run by the ConnectionTester. // // NOTE: do not delete the ConnectionTester when executing within one of the // delegate methods. class Delegate { public: // Called once the test suite is about to start. virtual void OnStartConnectionTestSuite() = 0; // Called when an individual experiment is about to be started. virtual void OnStartConnectionTestExperiment( const Experiment& experiment) = 0; // Called when an individual experiment has completed. // |experiment| - the experiment that has completed. // |result| - the net error that the experiment completed with // (or net::OK if it was success). virtual void OnCompletedConnectionTestExperiment( const Experiment& experiment, int result) = 0; // Called once ALL tests have completed. virtual void OnCompletedConnectionTestSuite() = 0; protected: virtual ~Delegate() {} }; // Constructs a ConnectionTester that notifies test progress to |delegate|. // |delegate| is owned by the caller, and must remain valid for the lifetime // of ConnectionTester. ConnectionTester(Delegate* delegate, net::URLRequestContext* proxy_request_context, net::NetLog* net_log); // Note that destruction cancels any in-progress tests. ~ConnectionTester(); // Starts running the test suite on |url|. Notification of progress is sent to // |delegate_|. void RunAllTests(const GURL& url); // Returns a text string explaining what |experiment| is testing. static base::string16 ProxySettingsExperimentDescription( ProxySettingsExperiment experiment); static base::string16 HostResolverExperimentDescription( HostResolverExperiment experiment); private: // Internally each experiment run by ConnectionTester is handled by a // "TestRunner" instance. class TestRunner; friend class TestRunner; // Fills |list| with the set of all possible experiments for |url|. static void GetAllPossibleExperimentCombinations(const GURL& url, ExperimentList* list); // Starts the next experiment from |remaining_experiments_|. void StartNextExperiment(); // Callback for when |current_test_runner_| finishes. void OnExperimentCompleted(int result); // Returns the experiment at the front of our list. const Experiment& current_experiment() const { return remaining_experiments_.front(); } // The object to notify test progress to. Delegate* delegate_; // The current in-progress test, or NULL if there is no active test. scoped_ptr<TestRunner> current_test_runner_; // The ordered list of experiments to try next. The experiment at the front // of the list is the one currently in progress. ExperimentList remaining_experiments_; net::URLRequestContext* const proxy_request_context_; net::NetLog* net_log_; DISALLOW_COPY_AND_ASSIGN(ConnectionTester); }; #endif // CHROME_BROWSER_NET_CONNECTION_TESTER_H_