• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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 NET_SOCKET_CLIENT_SOCKET_POOL_H_
6 #define NET_SOCKET_CLIENT_SOCKET_POOL_H_
7 
8 #include <memory>
9 #include <optional>
10 #include <string>
11 #include <vector>
12 
13 #include "base/memory/raw_ptr.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/time/time.h"
16 #include "base/values.h"
17 #include "net/base/completion_once_callback.h"
18 #include "net/base/load_states.h"
19 #include "net/base/net_export.h"
20 #include "net/base/network_anonymization_key.h"
21 #include "net/base/privacy_mode.h"
22 #include "net/base/request_priority.h"
23 #include "net/dns/host_resolver.h"
24 #include "net/dns/public/secure_dns_policy.h"
25 #include "net/http/http_request_info.h"
26 #include "net/log/net_log_capture_mode.h"
27 #include "net/socket/connect_job.h"
28 #include "net/socket/socket_tag.h"
29 #include "net/ssl/ssl_config.h"
30 #include "url/scheme_host_port.h"
31 
32 namespace net {
33 
34 class ClientSocketHandle;
35 class ConnectJobFactory;
36 class HttpAuthController;
37 class HttpResponseInfo;
38 class NetLogWithSource;
39 struct NetworkTrafficAnnotationTag;
40 class ProxyChain;
41 struct SSLConfig;
42 class StreamSocket;
43 
44 // ClientSocketPools are layered. This defines an interface for lower level
45 // socket pools to communicate with higher layer pools.
46 class NET_EXPORT HigherLayeredPool {
47  public:
48   virtual ~HigherLayeredPool() = default;
49 
50   // Instructs the HigherLayeredPool to close an idle connection. Return true if
51   // one was closed.  Closing an idle connection will call into the lower layer
52   // pool it came from, so must be careful of re-entrancy when using this.
53   virtual bool CloseOneIdleConnection() = 0;
54 };
55 
56 // ClientSocketPools are layered. This defines an interface for higher level
57 // socket pools to communicate with lower layer pools.
58 class NET_EXPORT LowerLayeredPool {
59  public:
60   virtual ~LowerLayeredPool() = default;
61 
62   // Returns true if a there is currently a request blocked on the per-pool
63   // (not per-host) max socket limit, either in this pool, or one that it is
64   // layered on top of.
65   virtual bool IsStalled() const = 0;
66 
67   // Called to add or remove a higher layer pool on top of |this|.  A higher
68   // layer pool may be added at most once to |this|, and must be removed prior
69   // to destruction of |this|.
70   virtual void AddHigherLayeredPool(HigherLayeredPool* higher_pool) = 0;
71   virtual void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool) = 0;
72 };
73 
74 // A ClientSocketPool is used to restrict the number of sockets open at a time.
75 // It also maintains a list of idle persistent sockets.
76 //
77 // Subclasses must also have an inner class SocketParams which is
78 // the type for the |params| argument in RequestSocket() and
79 // RequestSockets() below.
80 class NET_EXPORT ClientSocketPool : public LowerLayeredPool {
81  public:
82   // Indicates whether or not a request for a socket should respect the
83   // SocketPool's global and per-group socket limits.
84   enum class RespectLimits { DISABLED, ENABLED };
85 
86   // ProxyAuthCallback is invoked when there is an auth challenge while
87   // connecting to a tunnel. When |restart_with_auth_callback| is invoked, the
88   // corresponding socket request is guaranteed not to be completed
89   // synchronously, nor will the ProxyAuthCallback be invoked against
90   // synchronously.
91   typedef base::RepeatingCallback<void(
92       const HttpResponseInfo& response,
93       HttpAuthController* auth_controller,
94       base::OnceClosure restart_with_auth_callback)>
95       ProxyAuthCallback;
96 
97   // Group ID for a socket request. Requests with the same group ID are
98   // considered indistinguishable.
99   class NET_EXPORT GroupId {
100    public:
101     // Returns the prefix for `privacy_mode` for logging.
102     static std::string_view GetPrivacyModeGroupIdPrefix(
103         PrivacyMode privacy_mode);
104 
105     // Returns the prefix for `secure_dns_policy` for logging.
106     static std::string_view GetSecureDnsPolicyGroupIdPrefix(
107         SecureDnsPolicy secure_dns_policy);
108 
109     GroupId();
110     GroupId(url::SchemeHostPort destination,
111             PrivacyMode privacy_mode,
112             NetworkAnonymizationKey network_anonymization_key,
113             SecureDnsPolicy secure_dns_policy,
114             bool disable_cert_network_fetches);
115     GroupId(const GroupId& group_id);
116 
117     ~GroupId();
118 
119     GroupId& operator=(const GroupId& group_id);
120     GroupId& operator=(GroupId&& group_id);
121 
destination()122     const url::SchemeHostPort& destination() const { return destination_; }
123 
privacy_mode()124     PrivacyMode privacy_mode() const { return privacy_mode_; }
125 
network_anonymization_key()126     const NetworkAnonymizationKey& network_anonymization_key() const {
127       return network_anonymization_key_;
128     }
129 
secure_dns_policy()130     SecureDnsPolicy secure_dns_policy() const { return secure_dns_policy_; }
131 
disable_cert_network_fetches()132     bool disable_cert_network_fetches() const {
133       return disable_cert_network_fetches_;
134     }
135 
136     // Returns the group ID as a string, for logging.
137     std::string ToString() const;
138 
139     bool operator==(const GroupId& other) const {
140       return std::tie(destination_, privacy_mode_, network_anonymization_key_,
141                       secure_dns_policy_, disable_cert_network_fetches_) ==
142              std::tie(other.destination_, other.privacy_mode_,
143                       other.network_anonymization_key_,
144                       other.secure_dns_policy_,
145                       other.disable_cert_network_fetches_);
146     }
147 
148     bool operator<(const GroupId& other) const {
149       return std::tie(destination_, privacy_mode_, network_anonymization_key_,
150                       secure_dns_policy_, disable_cert_network_fetches_) <
151              std::tie(other.destination_, other.privacy_mode_,
152                       other.network_anonymization_key_,
153                       other.secure_dns_policy_,
154                       other.disable_cert_network_fetches_);
155     }
156 
157    private:
158     // The endpoint of the final destination (not the proxy).
159     url::SchemeHostPort destination_;
160 
161     // If this request is for a privacy mode / uncredentialed connection.
162     PrivacyMode privacy_mode_;
163 
164     // Used to separate requests made in different contexts.
165     NetworkAnonymizationKey network_anonymization_key_;
166 
167     // Controls the Secure DNS behavior to use when creating this socket.
168     SecureDnsPolicy secure_dns_policy_;
169 
170     // Whether cert validation-related network fetches are allowed. Should only
171     // be true for a very limited number of network-configuration related
172     // scripts (e.g., PAC fetches).
173     bool disable_cert_network_fetches_;
174   };
175 
176   // Parameters that, in combination with GroupId, proxy, websocket information,
177   // and global state, are sufficient to create a ConnectJob.
178   //
179   // DO NOT ADD ANY FIELDS TO THIS CLASS.
180   //
181   // TODO(crbug.com/40609237) In order to resolve longstanding issues
182   // related to pooling distinguishable sockets together, remove this class
183   // entirely.
184   class NET_EXPORT_PRIVATE SocketParams
185       : public base::RefCounted<SocketParams> {
186    public:
187     // For non-SSL requests, `allowed_bad_certs` argument will be ignored (and
188     // is likely empty, anyways).
189     explicit SocketParams(
190         const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs);
191 
192     SocketParams(const SocketParams&) = delete;
193     SocketParams& operator=(const SocketParams&) = delete;
194 
195     // Creates a SocketParams object with none of the fields populated. This
196     // works for the HTTP case only.
197     static scoped_refptr<SocketParams> CreateForHttpForTesting();
198 
allowed_bad_certs()199     const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs() const {
200       return allowed_bad_certs_;
201     }
202 
203    private:
204     friend class base::RefCounted<SocketParams>;
205     ~SocketParams();
206 
207     std::vector<SSLConfig::CertAndStatus> allowed_bad_certs_;
208   };
209 
210   ClientSocketPool(const ClientSocketPool&) = delete;
211   ClientSocketPool& operator=(const ClientSocketPool&) = delete;
212 
213   ~ClientSocketPool() override;
214 
215   // Requests a connected socket with a specified GroupId.
216   //
217   // There are five possible results from calling this function:
218   // 1) RequestSocket returns OK and initializes |handle| with a reused socket.
219   // 2) RequestSocket returns OK with a newly connected socket.
220   // 3) RequestSocket returns ERR_IO_PENDING.  The handle will be added to a
221   // wait list until a socket is available to reuse or a new socket finishes
222   // connecting.  |priority| will determine the placement into the wait list.
223   // 4) An error occurred early on, so RequestSocket returns an error code.
224   // 5) A recoverable error occurred while setting up the socket.  An error
225   // code is returned, but the |handle| is initialized with the new socket.
226   // The caller must recover from the error before using the connection, or
227   // Disconnect the socket before releasing or resetting the |handle|.
228   // The current recoverable errors are: the errors accepted by
229   // IsCertificateError(err) and HTTPS_PROXY_TUNNEL_RESPONSE when reported by
230   // HttpProxyClientSocketPool.
231   //
232   // If this function returns OK, then |handle| is initialized upon return.
233   // The |handle|'s is_initialized method will return true in this case.  If a
234   // StreamSocket was reused, then ClientSocketPool will call
235   // |handle|->set_reused(true).  In either case, the socket will have been
236   // allocated and will be connected.  A client might want to know whether or
237   // not the socket is reused in order to request a new socket if it encounters
238   // an error with the reused socket.
239   //
240   // If ERR_IO_PENDING is returned, then the callback will be used to notify the
241   // client of completion.
242   //
243   // Profiling information for the request is saved to |net_log| if non-NULL.
244   //
245   // If |respect_limits| is DISABLED, priority must be HIGHEST.
246   //
247   // |proxy_annotation_tag| is the annotation used for proxy-related reads and
248   // writes, and may be nullopt if (and only if) no proxy is in use.
249   //
250   // |proxy_auth_callback| will be invoked each time an auth challenge is seen
251   // while establishing a tunnel. It will be invoked asynchronously, once for
252   // each auth challenge seen.
253   virtual int RequestSocket(
254       const GroupId& group_id,
255       scoped_refptr<SocketParams> params,
256       const std::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
257       RequestPriority priority,
258       const SocketTag& socket_tag,
259       RespectLimits respect_limits,
260       ClientSocketHandle* handle,
261       CompletionOnceCallback callback,
262       const ProxyAuthCallback& proxy_auth_callback,
263       const NetLogWithSource& net_log) = 0;
264 
265   // RequestSockets is used to request that |num_sockets| be connected in the
266   // connection group for |group_id|.  If the connection group already has
267   // |num_sockets| idle sockets / active sockets / currently connecting sockets,
268   // then this function doesn't do anything and returns OK.  Otherwise, it will
269   // start up as many connections as necessary to reach |num_sockets| total
270   // sockets for the group and returns ERR_IO_PENDING. And |callback| will be
271   // called with OK when the connection tasks are finished.
272   // It uses |params| to control how to connect the sockets. The
273   // ClientSocketPool will assign a priority to the new connections, if any.
274   // This priority will probably be lower than all others, since this method
275   // is intended to make sure ahead of time that |num_sockets| sockets are
276   // available to talk to a host.
277   virtual int RequestSockets(
278       const GroupId& group_id,
279       scoped_refptr<SocketParams> params,
280       const std::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
281       int num_sockets,
282       CompletionOnceCallback callback,
283       const NetLogWithSource& net_log) = 0;
284 
285   // Called to change the priority of a RequestSocket call that returned
286   // ERR_IO_PENDING and has not yet asynchronously completed.  The same handle
287   // parameter must be passed to this method as was passed to the
288   // RequestSocket call being modified.
289   // This function is a no-op if |priority| is the same as the current
290   // request priority.
291   virtual void SetPriority(const GroupId& group_id,
292                            ClientSocketHandle* handle,
293                            RequestPriority priority) = 0;
294 
295   // Called to cancel a RequestSocket call that returned ERR_IO_PENDING.  The
296   // same handle parameter must be passed to this method as was passed to the
297   // RequestSocket call being cancelled.  The associated callback is not run.
298   // If |cancel_connect_job| is true, and there are more ConnectJobs than
299   // requests, a ConnectJob will be canceled. If it's false, excess ConnectJobs
300   // may be allowed to continue, just in case there are new requests to the same
301   // endpoint.
302   virtual void CancelRequest(const GroupId& group_id,
303                              ClientSocketHandle* handle,
304                              bool cancel_connect_job) = 0;
305 
306   // Called to release a socket once the socket is no longer needed.  If the
307   // socket still has an established connection, then it will be added to the
308   // set of idle sockets to be used to satisfy future RequestSocket calls.
309   // Otherwise, the StreamSocket is destroyed.  |generation| is used to
310   // differentiate between updated versions of the same pool instance.  The
311   // pool's generation will change when it flushes, so it can use this
312   // |generation| to discard sockets with mismatched ids.
313   virtual void ReleaseSocket(const GroupId& group_id,
314                              std::unique_ptr<StreamSocket> socket,
315                              int64_t generation) = 0;
316 
317   // This flushes all state from the ClientSocketPool.  Pending socket requests
318   // are failed with |error|, while |reason| is logged to the NetLog.
319   //
320   // Active sockets being held by ClientSocketPool clients will be discarded
321   // when released back to the pool, though they will be closed with an error
322   // about being of the wrong generation, rather than |net_log_reason_utf8|.
323   virtual void FlushWithError(int error, const char* net_log_reason_utf8) = 0;
324 
325   // Called to close any idle connections held by the connection manager.
326   // |reason| is logged to NetLog for debugging purposes.
327   virtual void CloseIdleSockets(const char* net_log_reason_utf8) = 0;
328 
329   // Called to close any idle connections held by the connection manager.
330   // |reason| is logged to NetLog for debugging purposes.
331   virtual void CloseIdleSocketsInGroup(const GroupId& group_id,
332                                        const char* net_log_reason_utf8) = 0;
333 
334   // The total number of idle sockets in the pool.
335   virtual int IdleSocketCount() const = 0;
336 
337   // The total number of idle sockets in a connection group.
338   virtual size_t IdleSocketCountInGroup(const GroupId& group_id) const = 0;
339 
340   // Determine the LoadState of a connecting ClientSocketHandle.
341   virtual LoadState GetLoadState(const GroupId& group_id,
342                                  const ClientSocketHandle* handle) const = 0;
343 
344   // Retrieves information on the current state of the pool as a
345   // Value.
346   // If |include_nested_pools| is true, the states of any nested
347   // ClientSocketPools will be included.
348   virtual base::Value GetInfoAsValue(const std::string& name,
349                                      const std::string& type) const = 0;
350 
351   // Returns whether a connected (idle or handed out) or connecting socket
352   // exists for the group. This method is not supported for WebSockets.
353   virtual bool HasActiveSocket(const GroupId& group_id) const = 0;
354 
355   // Returns the maximum amount of time to wait before retrying a connect.
356   static const int kMaxConnectRetryIntervalMs = 250;
357 
358   static base::TimeDelta used_idle_socket_timeout();
359   static void set_used_idle_socket_timeout(base::TimeDelta timeout);
360 
361  protected:
362   ClientSocketPool(bool is_for_websockets,
363                    const CommonConnectJobParams* common_connect_job_params,
364                    std::unique_ptr<ConnectJobFactory> connect_job_factory);
365 
366   void NetLogTcpClientSocketPoolRequestedSocket(const NetLogWithSource& net_log,
367                                                 const GroupId& group_id);
368 
369   // Utility method to log a GroupId with a NetLog event.
370   static base::Value::Dict NetLogGroupIdParams(const GroupId& group_id);
371 
372   std::unique_ptr<ConnectJob> CreateConnectJob(
373       GroupId group_id,
374       scoped_refptr<SocketParams> socket_params,
375       const ProxyChain& proxy_chain,
376       const std::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
377       RequestPriority request_priority,
378       SocketTag socket_tag,
379       ConnectJob::Delegate* delegate);
380 
381  private:
382   const bool is_for_websockets_;
383   const raw_ptr<const CommonConnectJobParams> common_connect_job_params_;
384   const std::unique_ptr<ConnectJobFactory> connect_job_factory_;
385 };
386 
387 }  // namespace net
388 
389 #endif  // NET_SOCKET_CLIENT_SOCKET_POOL_H_
390