summaryrefslogtreecommitdiffstats
path: root/chrome/browser/net/connection_tester.h
blob: d25c266b691b4c7a113b122a2d38dfe3998491d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// 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 "googleurl/src/gurl.h"
#include "net/base/completion_callback.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 string16 ProxySettingsExperimentDescription(
      ProxySettingsExperiment experiment);
  static 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_