summaryrefslogtreecommitdiff
path: root/chromium/net/proxy_resolution/win/dhcp_pac_file_fetcher_win.h
blob: 32f83f16d2129594206304abfc0ea753a972e44b (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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
// 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 NET_PROXY_RESOLUTION_WIN_DHCP_PAC_FILE_FETCHER_WIN_H_
#define NET_PROXY_RESOLUTION_WIN_DHCP_PAC_FILE_FETCHER_WIN_H_

#include <memory>
#include <set>
#include <string>
#include <vector>

#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "net/base/completion_once_callback.h"
#include "net/base/net_export.h"
#include "net/log/net_log_with_source.h"
#include "net/proxy_resolution/dhcp_pac_file_fetcher.h"
#include "net/traffic_annotation/network_traffic_annotation.h"

namespace base {
class TaskRunner;
}

namespace net {

struct DhcpAdapterNamesLoggingInfo;
class DhcpPacFileAdapterFetcher;
class URLRequestContext;

// Windows-specific implementation.
class NET_EXPORT_PRIVATE DhcpPacFileFetcherWin
    : public DhcpPacFileFetcher,
      public base::SupportsWeakPtr<DhcpPacFileFetcherWin> {
 public:
  // Creates a DhcpPacFileFetcherWin that issues requests through
  // |url_request_context|. |url_request_context| must remain valid for
  // the lifetime of DhcpPacFileFetcherWin.
  explicit DhcpPacFileFetcherWin(URLRequestContext* url_request_context);
  ~DhcpPacFileFetcherWin() override;

  // DhcpPacFileFetcher implementation.
  int Fetch(base::string16* utf16_text,
            CompletionOnceCallback callback,
            const NetLogWithSource& net_log,
            const NetworkTrafficAnnotationTag traffic_annotation) override;
  void Cancel() override;
  void OnShutdown() override;
  const GURL& GetPacURL() const override;
  std::string GetFetcherName() const override;

  // Sets |adapter_names| to contain the name of each network adapter on
  // this machine that has DHCP enabled and is not a loop-back adapter. May
  // optionally update |info| (if non-null) with information for logging.
  // Returns false on error.
  static bool GetCandidateAdapterNames(std::set<std::string>* adapter_names,
                                       DhcpAdapterNamesLoggingInfo* info);

 protected:
  int num_pending_fetchers() const;

  URLRequestContext* url_request_context() const;

  scoped_refptr<base::TaskRunner> GetTaskRunner();

  // This inner class encapsulate work done on a worker pool thread.
  // The class calls GetCandidateAdapterNames, which can take a couple of
  // hundred milliseconds.
  class NET_EXPORT_PRIVATE AdapterQuery
      : public base::RefCountedThreadSafe<AdapterQuery> {
   public:
    AdapterQuery();

    // This is the method that runs on the worker pool thread.
    void GetCandidateAdapterNames();

    // This set is valid after GetCandidateAdapterNames has
    // been run. Its lifetime is scoped by this object.
    const std::set<std::string>& adapter_names() const;

    DhcpAdapterNamesLoggingInfo* logging_info() { return logging_info_.get(); }

   protected:
    // Virtual method introduced to allow unit testing.
    virtual bool ImplGetCandidateAdapterNames(
        std::set<std::string>* adapter_names,
        DhcpAdapterNamesLoggingInfo* info);

    friend class base::RefCountedThreadSafe<AdapterQuery>;
    virtual ~AdapterQuery();

   private:
    // These are constructed on the originating thread, then used on the
    // worker thread, then used again on the originating thread only when
    // the task has completed on the worker thread. No locking required.
    std::set<std::string> adapter_names_;
    std::unique_ptr<DhcpAdapterNamesLoggingInfo> logging_info_;

    DISALLOW_COPY_AND_ASSIGN(AdapterQuery);
  };

  // Virtual methods introduced to allow unit testing.
  virtual DhcpPacFileAdapterFetcher* ImplCreateAdapterFetcher();
  virtual AdapterQuery* ImplCreateAdapterQuery();
  virtual base::TimeDelta ImplGetMaxWait();
  virtual void ImplOnGetCandidateAdapterNamesDone() {}

 private:
  // Event/state transition handlers
  void CancelImpl();
  void OnGetCandidateAdapterNamesDone(
      scoped_refptr<AdapterQuery> query,
      const NetworkTrafficAnnotationTag traffic_annotation);
  void OnFetcherDone(size_t fetcher_i, int result);
  void OnWaitTimer();
  void TransitionToDone();

  // This is the outer state machine for fetching PAC configuration from
  // DHCP.  It relies for sub-states on the state machine of the
  // DhcpPacFileAdapterFetcher class.
  //
  // The goal of the implementation is to the following work in parallel
  // for all network adapters that are using DHCP:
  // a) Try to get the PAC URL configured in DHCP;
  // b) If one is configured, try to fetch the PAC URL.
  // c) Once this is done for all adapters, or a timeout has passed after
  //    it has completed for the fastest adapter, return the PAC file
  //    available for the most preferred network adapter, if any.
  //
  // The state machine goes from START->WAIT_ADAPTERS when it starts a
  // worker thread to get the list of adapters with DHCP enabled.
  // It then goes from WAIT_ADAPTERS->NO_RESULTS when it creates
  // and starts an DhcpPacFileAdapterFetcher for each adapter.  It goes
  // from NO_RESULTS->SOME_RESULTS when it gets the first result; at this
  // point a wait timer is started.  It goes from SOME_RESULTS->DONE in
  // two cases: All results are known, or the wait timer expired.  A call
  // to Cancel() will also go straight to DONE from any state.  Any
  // way the DONE state is entered, we will at that point cancel any
  // outstanding work and return the best known PAC script or the empty
  // string.
  //
  // The state machine is reset for each Fetch(), a call to which is
  // only valid in states START and DONE, as only one Fetch() is
  // allowed to be outstanding at any given time.
  enum State {
    STATE_START,
    STATE_WAIT_ADAPTERS,
    STATE_NO_RESULTS,
    STATE_SOME_RESULTS,
    STATE_DONE,
  };

  // Vector, in Windows' network adapter preference order, of
  // DhcpPacFileAdapterFetcher objects that are or were attempting
  // to fetch a PAC file based on DHCP configuration.
  using FetcherVector = std::vector<std::unique_ptr<DhcpPacFileAdapterFetcher>>;
  FetcherVector fetchers_;

  // Current state of this state machine.
  State state_;

  // The following members are associated with the latest call to Fetch().

  // Number of fetchers we are waiting for.
  int num_pending_fetchers_;

  // Lets our client know we're done. Not valid in states START or DONE.
  CompletionOnceCallback callback_;

  // The NetLog to use for the current Fetch().
  NetLogWithSource net_log_;

  // Pointer to string we will write results to. Not valid in states
  // START and DONE.
  base::string16* destination_string_;

  // PAC URL retrieved from DHCP, if any. Valid only in state STATE_DONE.
  GURL pac_url_;

  base::OneShotTimer wait_timer_;

  // Set to nullptr on cancellation.
  URLRequestContext* url_request_context_;

  // NULL or the AdapterQuery currently in flight.
  scoped_refptr<AdapterQuery> last_query_;

  // TaskRunner used for all DHCP lookup tasks.
  const scoped_refptr<base::TaskRunner> task_runner_;

  THREAD_CHECKER(thread_checker_);

  DISALLOW_IMPLICIT_CONSTRUCTORS(DhcpPacFileFetcherWin);
};

}  // namespace net

#endif  // NET_PROXY_RESOLUTION_WIN_DHCP_PAC_FILE_FETCHER_WIN_H_