summaryrefslogtreecommitdiff
path: root/chromium/net/proxy_resolution/configured_proxy_resolution_service.h
blob: b640467a1c9e244e3ac82da3c9e986d61692ab93 (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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
// 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_CONFIGURED_PROXY_RESOLUTION_SERVICE_H_
#define NET_PROXY_RESOLUTION_CONFIGURED_PROXY_RESOLUTION_SERVICE_H_

#include <stddef.h>

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

#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread_checker.h"
#include "net/base/completion_once_callback.h"
#include "net/base/load_states.h"
#include "net/base/net_errors.h"
#include "net/base/net_export.h"
#include "net/base/network_change_notifier.h"
#include "net/log/net_log_with_source.h"
#include "net/proxy_resolution/proxy_config_service.h"
#include "net/proxy_resolution/proxy_config_with_annotation.h"
#include "net/proxy_resolution/proxy_info.h"
#include "net/proxy_resolution/proxy_resolution_request.h"
#include "net/proxy_resolution/proxy_resolution_service.h"
#include "net/proxy_resolution/proxy_resolver.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"

namespace base {
class TimeDelta;
}  // namespace base

namespace net {

class ConfiguredProxyResolutionRequest;
class DhcpPacFileFetcher;
class NetLog;
class PacFileFetcher;
class ProxyDelegate;
class ProxyResolverFactory;
struct PacFileDataWithSource;

// This class decides which proxy server(s) to use for a particular URL request.
// It uses the given ProxyResolver to evaluate a PAC file, which the
// ConfiguredProxyResolutionService then uses to resolve a proxy.  All proxy
// resolution in this class is based on first getting proxy configurations (ex:
// a PAC URL) from some source and then using these configurations to attempt to
// resolve that proxy.
class NET_EXPORT ConfiguredProxyResolutionService
    : public ProxyResolutionService,
      public NetworkChangeNotifier::IPAddressObserver,
      public NetworkChangeNotifier::DNSObserver,
      public ProxyConfigService::Observer {
 public:
  // This interface defines the set of policies for when to poll the PAC
  // script for changes.
  //
  // The polling policy decides what the next poll delay should be in
  // milliseconds. It also decides how to wait for this delay -- either
  // by starting a timer to do the poll at exactly |next_delay_ms|
  // (MODE_USE_TIMER) or by waiting for the first network request issued after
  // |next_delay_ms| (MODE_START_AFTER_ACTIVITY).
  //
  // The timer method is more precise and guarantees that polling happens when
  // it was requested. However it has the disadvantage of causing spurious CPU
  // and network activity. It is a reasonable choice to use for short poll
  // intervals which only happen a couple times.
  //
  // However for repeated timers this will prevent the browser from going
  // idle. MODE_START_AFTER_ACTIVITY solves this problem by only polling in
  // direct response to network activity. The drawback to
  // MODE_START_AFTER_ACTIVITY is since the poll is initiated only after the
  // request is received, the first couple requests initiated after a long
  // period of inactivity will likely see a stale version of the PAC script
  // until the background polling gets a chance to update things.
  class NET_EXPORT_PRIVATE PacPollPolicy {
   public:
    enum Mode {
      MODE_USE_TIMER,
      MODE_START_AFTER_ACTIVITY,
    };

    virtual ~PacPollPolicy() = default;

    // Decides the next poll delay. |current_delay| is the delay used
    // by the preceding poll, or a negative TimeDelta value if determining
    // the delay for the initial poll. |initial_error| is the network error
    // code that the last PAC fetch (or WPAD initialization) failed with,
    // or OK if it completed successfully. Implementations must set
    // |next_delay| to a non-negative value.
    virtual Mode GetNextDelay(int initial_error,
                              base::TimeDelta current_delay,
                              base::TimeDelta* next_delay) const = 0;
  };

  // |net_log| is a possibly nullptr destination to send log events to. It must
  // remain alive for the lifetime of this ConfiguredProxyResolutionService.
  ConfiguredProxyResolutionService(
      std::unique_ptr<ProxyConfigService> config_service,
      std::unique_ptr<ProxyResolverFactory> resolver_factory,
      NetLog* net_log,
      bool quick_check_enabled);

  ConfiguredProxyResolutionService(const ConfiguredProxyResolutionService&) =
      delete;
  ConfiguredProxyResolutionService& operator=(
      const ConfiguredProxyResolutionService&) = delete;

  ~ConfiguredProxyResolutionService() override;

  // ProxyResolutionService
  //
  // We use the three possible proxy access types in the following order,
  // doing fallback if one doesn't work.  See "pac_script_decider.h"
  // for the specifics.
  //   1.  WPAD auto-detection
  //   2.  PAC URL
  //   3.  named proxy
  int ResolveProxy(const GURL& url,
                   const std::string& method,
                   const NetworkIsolationKey& network_isolation_key,
                   ProxyInfo* results,
                   CompletionOnceCallback callback,
                   std::unique_ptr<ProxyResolutionRequest>* request,
                   const NetLogWithSource& net_log) override;

  // ProxyResolutionService
  bool MarkProxiesAsBadUntil(
      const ProxyInfo& results,
      base::TimeDelta retry_delay,
      const std::vector<ProxyServer>& additional_bad_proxies,
      const NetLogWithSource& net_log) override;

  // ProxyResolutionService
  void ReportSuccess(const ProxyInfo& proxy_info) override;

  // Sets the PacFileFetcher and DhcpPacFileFetcher dependencies. This
  // is needed if the ProxyResolver is of type ProxyResolverWithoutFetch.
  void SetPacFileFetchers(
      std::unique_ptr<PacFileFetcher> pac_file_fetcher,
      std::unique_ptr<DhcpPacFileFetcher> dhcp_pac_file_fetcher);
  PacFileFetcher* GetPacFileFetcher() const;

  // ProxyResolutionService
  void SetProxyDelegate(ProxyDelegate* delegate) override;

  // ProxyResolutionService
  void OnShutdown() override;

  // Returns the last configuration fetched from ProxyConfigService.
  const absl::optional<ProxyConfigWithAnnotation>& fetched_config() const {
    return fetched_config_;
  }

  // Returns the current configuration being used by ProxyConfigService.
  const absl::optional<ProxyConfigWithAnnotation>& config() const {
    return config_;
  }

  // ProxyResolutionService
  const ProxyRetryInfoMap& proxy_retry_info() const override;

  // ProxyResolutionService
  void ClearBadProxiesCache() override;

  // Forces refetching the proxy configuration, and applying it.
  // This re-does everything from fetching the system configuration,
  // to downloading and testing the PAC files.
  void ForceReloadProxyConfig();

  // ProxyResolutionService
  base::Value::Dict GetProxyNetLogValues() override;

  // ProxyResolutionService
  [[nodiscard]] bool CastToConfiguredProxyResolutionService(
      ConfiguredProxyResolutionService** configured_proxy_resolution_service)
      override;

  // Same as CreateProxyResolutionServiceUsingV8ProxyResolver, except it uses
  // system libraries for evaluating the PAC script if available, otherwise
  // skips proxy autoconfig.
  static std::unique_ptr<ConfiguredProxyResolutionService>
  CreateUsingSystemProxyResolver(
      std::unique_ptr<ProxyConfigService> proxy_config_service,
      NetLog* net_log,
      bool quick_check_enabled);

  // Creates a ConfiguredProxyResolutionService without support for proxy
  // autoconfig.
  static std::unique_ptr<ConfiguredProxyResolutionService>
  CreateWithoutProxyResolver(
      std::unique_ptr<ProxyConfigService> proxy_config_service,
      NetLog* net_log);

  // Convenience methods that creates a proxy service using the
  // specified fixed settings.
  static std::unique_ptr<ConfiguredProxyResolutionService> CreateFixedForTest(
      const ProxyConfigWithAnnotation& pc);
  static std::unique_ptr<ConfiguredProxyResolutionService> CreateFixedForTest(
      const std::string& proxy,
      const NetworkTrafficAnnotationTag& traffic_annotation);

  // Creates a proxy service that uses a DIRECT connection for all requests.
  static std::unique_ptr<ConfiguredProxyResolutionService> CreateDirect();

  // This method is used by tests to create a ConfiguredProxyResolutionService
  // that returns a hardcoded proxy fallback list (|pac_string|) for every URL.
  //
  // |pac_string| is a list of proxy servers, in the format that a PAC script
  // would return it. For example, "PROXY foobar:99; SOCKS fml:2; DIRECT"
  static std::unique_ptr<ConfiguredProxyResolutionService>
  CreateFixedFromPacResultForTest(
      const std::string& pac_string,
      const NetworkTrafficAnnotationTag& traffic_annotation);

  // Same as CreateFixedFromPacResultForTest(), except the resulting ProxyInfo
  // from resolutions will be tagged as having been auto-detected.
  static std::unique_ptr<ConfiguredProxyResolutionService>
  CreateFixedFromAutoDetectedPacResultForTest(
      const std::string& pac_string,
      const NetworkTrafficAnnotationTag& traffic_annotation);

  // This method should only be used by unit tests.
  void set_stall_proxy_auto_config_delay(base::TimeDelta delay) {
    stall_proxy_auto_config_delay_ = delay;
  }

  // This method should only be used by unit tests. Returns the previously
  // active policy.
  static const PacPollPolicy* set_pac_script_poll_policy(
      const PacPollPolicy* policy);

  // This method should only be used by unit tests. Creates an instance
  // of the default internal PacPollPolicy used by
  // ConfiguredProxyResolutionService.
  static std::unique_ptr<PacPollPolicy> CreateDefaultPacPollPolicy();

  bool quick_check_enabled_for_testing() const { return quick_check_enabled_; }

 private:
  friend class ConfiguredProxyResolutionRequest;
  FRIEND_TEST_ALL_PREFIXES(ProxyResolutionServiceTest,
                           UpdateConfigAfterFailedAutodetect);
  FRIEND_TEST_ALL_PREFIXES(ProxyResolutionServiceTest,
                           UpdateConfigFromPACToDirect);
  class InitProxyResolver;
  class PacFileDeciderPoller;

  typedef std::set<ConfiguredProxyResolutionRequest*> PendingRequests;

  enum State {
    STATE_NONE,
    STATE_WAITING_FOR_PROXY_CONFIG,
    STATE_WAITING_FOR_INIT_PROXY_RESOLVER,
    STATE_READY,
  };

  // We won't always be able to return a good LoadState. For example, the
  // ConfiguredProxyResolutionService can only get this information from the
  // InitProxyResolver, which is not always available.
  bool GetLoadStateIfAvailable(LoadState* load_state) const;

  ProxyResolver* GetProxyResolver() const;

  // Resets all the variables associated with the current proxy configuration,
  // and rewinds the current state to |STATE_NONE|. Returns the previous value
  // of |current_state_|.  If |reset_fetched_config| is true then
  // |fetched_config_| will also be reset, otherwise it will be left as-is.
  // Resetting it means that we will have to re-fetch the configuration from
  // the ProxyConfigService later.
  State ResetProxyConfig(bool reset_fetched_config);

  // Retrieves the current proxy configuration from the ProxyConfigService, and
  // starts initializing for it.
  void ApplyProxyConfigIfAvailable();

  // Callback for when the proxy resolver has been initialized with a
  // PAC script.
  void OnInitProxyResolverComplete(int result);

  // Returns ERR_IO_PENDING if the request cannot be completed synchronously.
  // Otherwise it fills |result| with the proxy information for |url|.
  // Completing synchronously means we don't need to query ProxyResolver.
  int TryToCompleteSynchronously(const GURL& url, ProxyInfo* result);

  // Cancels all of the requests sent to the ProxyResolver. These will be
  // restarted when calling SetReady().
  void SuspendAllPendingRequests();

  // Advances the current state to |STATE_READY|, and resumes any pending
  // requests which had been stalled waiting for initialization to complete.
  void SetReady();

  // Returns true if |pending_requests_| contains |req|.
  bool ContainsPendingRequest(ConfiguredProxyResolutionRequest* req);

  // Removes |req| from the list of pending requests.
  void RemovePendingRequest(ConfiguredProxyResolutionRequest* req);

  // Called when proxy resolution has completed (either synchronously or
  // asynchronously). Handles logging the result, and cleaning out
  // bad entries from the results list.
  int DidFinishResolvingProxy(const GURL& url,
                              const std::string& method,
                              ProxyInfo* result,
                              int result_code,
                              const NetLogWithSource& net_log);

  // Start initialization using |fetched_config_|.
  void InitializeUsingLastFetchedConfig();

  // Start the initialization skipping past the "decision" phase.
  void InitializeUsingDecidedConfig(
      int decider_result,
      const PacFileDataWithSource& script_data,
      const ProxyConfigWithAnnotation& effective_config);

  // NetworkChangeNotifier::IPAddressObserver
  // When this is called, we re-fetch PAC scripts and re-run WPAD.
  void OnIPAddressChanged() override;

  // NetworkChangeNotifier::DNSObserver
  // We respond as above.
  void OnDNSChanged() override;

  // ProxyConfigService::Observer
  void OnProxyConfigChanged(
      const ProxyConfigWithAnnotation& config,
      ProxyConfigService::ConfigAvailability availability) override;

  // When using a PAC script there isn't a user-configurable ProxyBypassRules to
  // check, as the one from manual settings doesn't apply. However we
  // still check for matches against the implicit bypass rules, to prevent PAC
  // scripts from being able to proxy localhost.
  bool ApplyPacBypassRules(const GURL& url, ProxyInfo* results);

  std::unique_ptr<ProxyConfigService> config_service_;
  std::unique_ptr<ProxyResolverFactory> resolver_factory_;

  // If non-null, the initialized ProxyResolver to use for requests.
  std::unique_ptr<ProxyResolver> resolver_;

  // We store the proxy configuration that was last fetched from the
  // ProxyConfigService, as well as the resulting "effective" configuration.
  // The effective configuration is what we condense the original fetched
  // settings to after testing the various automatic settings (auto-detect
  // and custom PAC url).
  //
  // These are "optional" as their value remains unset while being calculated.
  absl::optional<ProxyConfigWithAnnotation> fetched_config_;
  absl::optional<ProxyConfigWithAnnotation> config_;

  // Map of the known bad proxies and the information about the retry time.
  ProxyRetryInfoMap proxy_retry_info_;

  // Set of pending/inprogress requests.
  PendingRequests pending_requests_;

  // The fetcher to use when downloading PAC scripts for the ProxyResolver.
  // This dependency can be nullptr if our ProxyResolver has no need for
  // external PAC script fetching.
  std::unique_ptr<PacFileFetcher> pac_file_fetcher_;

  // The fetcher to use when attempting to download the most appropriate PAC
  // script configured in DHCP, if any. Can be nullptr if the ProxyResolver has
  // no need for DHCP PAC script fetching.
  std::unique_ptr<DhcpPacFileFetcher> dhcp_pac_file_fetcher_;

  // Helper to download the PAC script (wpad + custom) and apply fallback rules.
  //
  // Note that the declaration is important here: |pac_file_fetcher_| and
  // |proxy_resolver_| must outlive |init_proxy_resolver_|.
  std::unique_ptr<InitProxyResolver> init_proxy_resolver_;

  // Helper to poll the PAC script for changes.
  std::unique_ptr<PacFileDeciderPoller> script_poller_;

  State current_state_ = STATE_NONE;

  // Either OK or an ERR_* value indicating that a permanent error (e.g.
  // failed to fetch the PAC script) prevents proxy resolution.
  int permanent_error_ = OK;

  // This is the log where any events generated by |init_proxy_resolver_| are
  // sent to.
  raw_ptr<NetLog> net_log_;

  // The earliest time at which we should run any proxy auto-config. (Used to
  // stall re-configuration following an IP address change).
  base::TimeTicks stall_proxy_autoconfig_until_;

  // The amount of time to stall requests following IP address changes.
  base::TimeDelta stall_proxy_auto_config_delay_;

  // Whether child PacFileDeciders should use QuickCheck
  bool quick_check_enabled_;

  THREAD_CHECKER(thread_checker_);

  raw_ptr<ProxyDelegate> proxy_delegate_ = nullptr;

  // Flag used by |SetReady()| to check if |this| has been deleted by a
  // synchronous callback.
  base::WeakPtrFactory<ConfiguredProxyResolutionService> weak_ptr_factory_{
      this};
};

}  // namespace net

#endif  // NET_PROXY_RESOLUTION_CONFIGURED_PROXY_RESOLUTION_SERVICE_H_