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