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
15namespace net {
16class NetLog;
17class 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
44class 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