Home | History | Annotate | Download | only in net
      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 #ifndef CHROME_BROWSER_NET_CONNECTION_TESTER_H_
      6 #define CHROME_BROWSER_NET_CONNECTION_TESTER_H_
      7 
      8 #include <vector>
      9 
     10 #include "base/basictypes.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "net/base/completion_callback.h"
     13 #include "url/gurl.h"
     14 
     15 namespace net {
     16 class NetLog;
     17 class URLRequestContext;
     18 }  // namespace net
     19 
     20 // ConnectionTester runs a suite of tests (also called "experiments"),
     21 // to try and discover why loading a particular URL is failing with an error
     22 // code.
     23 //
     24 // For example, one reason why the URL might have failed, is that the
     25 // network requires the URL to be routed through a proxy, however chrome is
     26 // not configured for that.
     27 //
     28 // The above issue might be detected by running test that fetches the URL using
     29 // auto-detect and seeing if it works this time. Or even by retrieving the
     30 // settings from another installed browser and trying with those.
     31 //
     32 // USAGE:
     33 //
     34 // To run the test suite, create an instance of ConnectionTester and then call
     35 // RunAllTests().
     36 //
     37 // This starts a sequence of tests, which will complete asynchronously.
     38 // The ConnectionTester object can be deleted at any time, and it will abort
     39 // any of the in-progress tests.
     40 //
     41 // As tests are started or completed, notification will be sent through the
     42 // "Delegate" object.
     43 
     44 class ConnectionTester {
     45  public:
     46   // This enum lists the possible proxy settings configurations.
     47   enum ProxySettingsExperiment {
     48     // Do not use any proxy.
     49     PROXY_EXPERIMENT_USE_DIRECT = 0,
     50 
     51     // Use the system proxy settings.
     52     PROXY_EXPERIMENT_USE_SYSTEM_SETTINGS,
     53 
     54     // Use Firefox's proxy settings if they are available.
     55     PROXY_EXPERIMENT_USE_FIREFOX_SETTINGS,
     56 
     57     // Use proxy auto-detect.
     58     PROXY_EXPERIMENT_USE_AUTO_DETECT,
     59 
     60     PROXY_EXPERIMENT_COUNT,
     61   };
     62 
     63   // This enum lists the possible host resolving configurations.
     64   enum HostResolverExperiment {
     65     // Use a default host resolver implementation.
     66     HOST_RESOLVER_EXPERIMENT_PLAIN = 0,
     67 
     68     // Disable IPv6 host resolving.
     69     HOST_RESOLVER_EXPERIMENT_DISABLE_IPV6,
     70 
     71     // Probe for IPv6 support.
     72     HOST_RESOLVER_EXPERIMENT_IPV6_PROBE,
     73 
     74     HOST_RESOLVER_EXPERIMENT_COUNT,
     75   };
     76 
     77   // The "Experiment" structure describes an individual test to run.
     78   struct Experiment {
     79     Experiment(const GURL& url,
     80                ProxySettingsExperiment proxy_settings_experiment,
     81                HostResolverExperiment host_resolver_experiment)
     82         : url(url),
     83           proxy_settings_experiment(proxy_settings_experiment),
     84           host_resolver_experiment(host_resolver_experiment) {
     85     }
     86 
     87     // The URL to try and fetch.
     88     GURL url;
     89 
     90     // The proxy settings to use.
     91     ProxySettingsExperiment proxy_settings_experiment;
     92 
     93     // The host resolver settings to use.
     94     HostResolverExperiment host_resolver_experiment;
     95   };
     96 
     97   typedef std::vector<Experiment> ExperimentList;
     98 
     99   // "Delegate" is an interface for receiving start and completion notification
    100   // of individual tests that are run by the ConnectionTester.
    101   //
    102   // NOTE: do not delete the ConnectionTester when executing within one of the
    103   // delegate methods.
    104   class Delegate {
    105    public:
    106     // Called once the test suite is about to start.
    107     virtual void OnStartConnectionTestSuite() = 0;
    108 
    109     // Called when an individual experiment is about to be started.
    110     virtual void OnStartConnectionTestExperiment(
    111         const Experiment& experiment) = 0;
    112 
    113     // Called when an individual experiment has completed.
    114     //   |experiment| - the experiment that has completed.
    115     //   |result| - the net error that the experiment completed with
    116     //              (or net::OK if it was success).
    117     virtual void OnCompletedConnectionTestExperiment(
    118         const Experiment& experiment,
    119         int result) = 0;
    120 
    121     // Called once ALL tests have completed.
    122     virtual void OnCompletedConnectionTestSuite() = 0;
    123 
    124    protected:
    125     virtual ~Delegate() {}
    126   };
    127 
    128   // Constructs a ConnectionTester that notifies test progress to |delegate|.
    129   // |delegate| is owned by the caller, and must remain valid for the lifetime
    130   // of ConnectionTester.
    131   ConnectionTester(Delegate* delegate,
    132                    net::URLRequestContext* proxy_request_context,
    133                    net::NetLog* net_log);
    134 
    135   // Note that destruction cancels any in-progress tests.
    136   ~ConnectionTester();
    137 
    138   // Starts running the test suite on |url|. Notification of progress is sent to
    139   // |delegate_|.
    140   void RunAllTests(const GURL& url);
    141 
    142   // Returns a text string explaining what |experiment| is testing.
    143   static base::string16 ProxySettingsExperimentDescription(
    144       ProxySettingsExperiment experiment);
    145   static base::string16 HostResolverExperimentDescription(
    146       HostResolverExperiment experiment);
    147 
    148  private:
    149   // Internally each experiment run by ConnectionTester is handled by a
    150   // "TestRunner" instance.
    151   class TestRunner;
    152   friend class TestRunner;
    153 
    154   // Fills |list| with the set of all possible experiments for |url|.
    155   static void GetAllPossibleExperimentCombinations(const GURL& url,
    156                                                    ExperimentList* list);
    157 
    158   // Starts the next experiment from |remaining_experiments_|.
    159   void StartNextExperiment();
    160 
    161   // Callback for when |current_test_runner_| finishes.
    162   void OnExperimentCompleted(int result);
    163 
    164   // Returns the experiment at the front of our list.
    165   const Experiment& current_experiment() const {
    166     return remaining_experiments_.front();
    167   }
    168 
    169   // The object to notify test progress to.
    170   Delegate* delegate_;
    171 
    172   // The current in-progress test, or NULL if there is no active test.
    173   scoped_ptr<TestRunner> current_test_runner_;
    174 
    175   // The ordered list of experiments to try next. The experiment at the front
    176   // of the list is the one currently in progress.
    177   ExperimentList remaining_experiments_;
    178 
    179   net::URLRequestContext* const proxy_request_context_;
    180 
    181   net::NetLog* net_log_;
    182 
    183   DISALLOW_COPY_AND_ASSIGN(ConnectionTester);
    184 };
    185 
    186 #endif  // CHROME_BROWSER_NET_CONNECTION_TESTER_H_
    187