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
|
// Copyright 2012 The Chromium Authors
// 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_ADAPTER_FETCHER_WIN_H_
#define NET_PROXY_RESOLUTION_WIN_DHCP_PAC_FILE_ADAPTER_FETCHER_WIN_H_
#include <stddef.h>
#include <memory>
#include <string>
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "base/timer/timer.h"
#include "net/base/completion_once_callback.h"
#include "net/base/net_errors.h"
#include "net/base/net_export.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "url/gurl.h"
namespace base {
class TaskRunner;
}
namespace net {
class PacFileFetcher;
class URLRequestContext;
// For a given adapter, this class takes care of first doing a DHCP lookup
// to get the PAC URL, then if there is one, trying to fetch it.
class NET_EXPORT_PRIVATE DhcpPacFileAdapterFetcher {
public:
DhcpPacFileAdapterFetcher() = delete;
// |url_request_context| must outlive DhcpPacFileAdapterFetcher.
// |task_runner| will be used to post tasks to a thread.
DhcpPacFileAdapterFetcher(URLRequestContext* url_request_context,
scoped_refptr<base::TaskRunner> task_runner);
DhcpPacFileAdapterFetcher(const DhcpPacFileAdapterFetcher&) = delete;
DhcpPacFileAdapterFetcher& operator=(const DhcpPacFileAdapterFetcher&) =
delete;
virtual ~DhcpPacFileAdapterFetcher();
// Starts a fetch. On completion (but not cancellation), |callback|
// will be invoked with the network error indicating success or failure
// of fetching a DHCP-configured PAC file on this adapter.
//
// On completion, results can be obtained via |GetPacScript()|, |GetPacURL()|.
//
// You may only call Fetch() once on a given instance of
// DhcpPacFileAdapterFetcher.
virtual void Fetch(const std::string& adapter_name,
CompletionOnceCallback callback,
const NetworkTrafficAnnotationTag traffic_annotation);
// Cancels the fetch on this adapter.
virtual void Cancel();
// Returns true if in the FINISH state (not CANCEL).
virtual bool DidFinish() const;
// Returns the network error indicating the result of the fetch. Will
// return IO_PENDING until the fetch is complete or cancelled. This is
// the same network error passed to the |callback| provided to |Fetch()|.
virtual int GetResult() const;
// Returns the contents of the PAC file retrieved. Only valid if
// |IsComplete()| is true. Returns the empty string if |GetResult()|
// returns anything other than OK.
virtual std::u16string GetPacScript() const;
// Returns the PAC URL retrieved from DHCP. Only guaranteed to be
// valid if |IsComplete()| is true. Returns an empty URL if no URL was
// configured in DHCP. May return a valid URL even if |result()| does
// not return OK (this would indicate that we found a URL configured in
// DHCP but failed to download it).
virtual GURL GetPacURL() const;
// Returns the PAC URL configured in DHCP for the given |adapter_name|, or
// the empty string if none is configured.
//
// This function executes synchronously due to limitations of the Windows
// DHCP client API.
static std::string GetPacURLFromDhcp(const std::string& adapter_name);
// Sanitizes a string returned via the DHCP API.
static std::string SanitizeDhcpApiString(const char* data,
size_t count_bytes);
protected:
// This is the state machine for fetching from a given adapter.
//
// The state machine goes from START->WAIT_DHCP when it starts
// a worker thread to fetch the PAC URL from DHCP.
//
// In state WAIT_DHCP, if the DHCP query finishes and has no URL, it
// moves to state FINISH. If there is a URL, it starts a
// PacFileFetcher to fetch it and moves to state WAIT_URL.
//
// It goes from WAIT_URL->FINISH when the PacFileFetcher completes.
//
// In state FINISH, completion is indicated to the outer class, with
// the results of the fetch if a PAC script was successfully fetched.
//
// In state WAIT_DHCP, our timeout occurring can push us to FINISH.
//
// In any state except FINISH, a call to Cancel() will move to state
// CANCEL and cause all outstanding work to be cancelled or its
// results ignored when available.
enum State {
STATE_START,
STATE_WAIT_DHCP,
STATE_WAIT_URL,
STATE_FINISH,
STATE_CANCEL,
};
State state() const;
// This inner class encapsulates work done on a worker pool thread.
// By using a separate object, we can keep the main object completely
// thread safe and let it be non-refcounted.
class NET_EXPORT_PRIVATE DhcpQuery
: public base::RefCountedThreadSafe<DhcpQuery> {
public:
DhcpQuery();
DhcpQuery(const DhcpQuery&) = delete;
DhcpQuery& operator=(const DhcpQuery&) = delete;
// This method should run on a worker pool thread, via PostTaskAndReply.
// After it has run, the |url()| method on this object will return the
// URL retrieved.
void GetPacURLForAdapter(const std::string& adapter_name);
// Returns the URL retrieved for the given adapter, once the task has run.
const std::string& url() const;
protected:
// Virtual method introduced to allow unit testing.
virtual std::string ImplGetPacURLFromDhcp(const std::string& adapter_name);
friend class base::RefCountedThreadSafe<DhcpQuery>;
virtual ~DhcpQuery();
private:
// The URL retrieved for the given adapter.
std::string url_;
};
// Virtual methods introduced to allow unit testing.
virtual std::unique_ptr<PacFileFetcher> ImplCreateScriptFetcher();
virtual scoped_refptr<DhcpQuery> ImplCreateDhcpQuery();
virtual base::TimeDelta ImplGetTimeout() const;
private:
// Event/state transition handlers
void OnDhcpQueryDone(scoped_refptr<DhcpQuery> dhcp_query,
const NetworkTrafficAnnotationTag traffic_annotation);
void OnTimeout();
void OnFetcherDone(int result);
void TransitionToFinish();
// TaskRunner for posting tasks to a worker thread.
scoped_refptr<base::TaskRunner> task_runner_;
// Current state of this state machine.
State state_ = STATE_START;
// A network error indicating result of operation.
int result_ = ERR_IO_PENDING;
// Empty string or the PAC script downloaded.
std::u16string pac_script_;
// Empty URL or the PAC URL configured in DHCP.
GURL pac_url_;
// Callback to let our client know we're done. Invalid in states
// START, FINISH and CANCEL.
CompletionOnceCallback callback_;
// Fetcher to retrieve PAC files once URL is known.
std::unique_ptr<PacFileFetcher> script_fetcher_;
// Implements a timeout on the call to the Win32 DHCP API.
base::OneShotTimer wait_timer_;
const raw_ptr<URLRequestContext> url_request_context_;
THREAD_CHECKER(thread_checker_);
base::WeakPtrFactory<DhcpPacFileAdapterFetcher> weak_ptr_factory_{this};
};
} // namespace net
#endif // NET_PROXY_RESOLUTION_WIN_DHCP_PAC_FILE_ADAPTER_FETCHER_WIN_H_
|