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 GroupId(); 102 GroupId(url::SchemeHostPort destination, 103 PrivacyMode privacy_mode, 104 NetworkAnonymizationKey network_anonymization_key, 105 SecureDnsPolicy secure_dns_policy, 106 bool disable_cert_network_fetches); 107 GroupId(const GroupId& group_id); 108 109 ~GroupId(); 110 111 GroupId& operator=(const GroupId& group_id); 112 GroupId& operator=(GroupId&& group_id); 113 destination()114 const url::SchemeHostPort& destination() const { return destination_; } 115 privacy_mode()116 PrivacyMode privacy_mode() const { return privacy_mode_; } 117 network_anonymization_key()118 const NetworkAnonymizationKey& network_anonymization_key() const { 119 return network_anonymization_key_; 120 } 121 secure_dns_policy()122 SecureDnsPolicy secure_dns_policy() const { return secure_dns_policy_; } 123 disable_cert_network_fetches()124 bool disable_cert_network_fetches() const { 125 return disable_cert_network_fetches_; 126 } 127 128 // Returns the group ID as a string, for logging. 129 std::string ToString() const; 130 131 bool operator==(const GroupId& other) const { 132 return std::tie(destination_, privacy_mode_, network_anonymization_key_, 133 secure_dns_policy_, disable_cert_network_fetches_) == 134 std::tie(other.destination_, other.privacy_mode_, 135 other.network_anonymization_key_, 136 other.secure_dns_policy_, 137 other.disable_cert_network_fetches_); 138 } 139 140 bool operator<(const GroupId& other) const { 141 return std::tie(destination_, privacy_mode_, network_anonymization_key_, 142 secure_dns_policy_, disable_cert_network_fetches_) < 143 std::tie(other.destination_, other.privacy_mode_, 144 other.network_anonymization_key_, 145 other.secure_dns_policy_, 146 other.disable_cert_network_fetches_); 147 } 148 149 private: 150 // The endpoint of the final destination (not the proxy). 151 url::SchemeHostPort destination_; 152 153 // If this request is for a privacy mode / uncredentialed connection. 154 PrivacyMode privacy_mode_; 155 156 // Used to separate requests made in different contexts. 157 NetworkAnonymizationKey network_anonymization_key_; 158 159 // Controls the Secure DNS behavior to use when creating this socket. 160 SecureDnsPolicy secure_dns_policy_; 161 162 // Whether cert validation-related network fetches are allowed. Should only 163 // be true for a very limited number of network-configuration related 164 // scripts (e.g., PAC fetches). 165 bool disable_cert_network_fetches_; 166 }; 167 168 // Parameters that, in combination with GroupId, proxy, websocket information, 169 // and global state, are sufficient to create a ConnectJob. 170 // 171 // DO NOT ADD ANY FIELDS TO THIS CLASS. 172 // 173 // TODO(https://crbug.com/921369) In order to resolve longstanding issues 174 // related to pooling distinguishable sockets together, remove this class 175 // entirely. 176 class NET_EXPORT_PRIVATE SocketParams 177 : public base::RefCounted<SocketParams> { 178 public: 179 // For non-SSL requests, `allowed_bad_certs` argument will be ignored (and 180 // is likely empty, anyways). 181 explicit SocketParams( 182 const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs); 183 184 SocketParams(const SocketParams&) = delete; 185 SocketParams& operator=(const SocketParams&) = delete; 186 187 // Creates a SocketParams object with none of the fields populated. This 188 // works for the HTTP case only. 189 static scoped_refptr<SocketParams> CreateForHttpForTesting(); 190 allowed_bad_certs()191 const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs() const { 192 return allowed_bad_certs_; 193 } 194 195 private: 196 friend class base::RefCounted<SocketParams>; 197 ~SocketParams(); 198 199 std::vector<SSLConfig::CertAndStatus> allowed_bad_certs_; 200 }; 201 202 ClientSocketPool(const ClientSocketPool&) = delete; 203 ClientSocketPool& operator=(const ClientSocketPool&) = delete; 204 205 ~ClientSocketPool() override; 206 207 // Requests a connected socket with a specified GroupId. 208 // 209 // There are five possible results from calling this function: 210 // 1) RequestSocket returns OK and initializes |handle| with a reused socket. 211 // 2) RequestSocket returns OK with a newly connected socket. 212 // 3) RequestSocket returns ERR_IO_PENDING. The handle will be added to a 213 // wait list until a socket is available to reuse or a new socket finishes 214 // connecting. |priority| will determine the placement into the wait list. 215 // 4) An error occurred early on, so RequestSocket returns an error code. 216 // 5) A recoverable error occurred while setting up the socket. An error 217 // code is returned, but the |handle| is initialized with the new socket. 218 // The caller must recover from the error before using the connection, or 219 // Disconnect the socket before releasing or resetting the |handle|. 220 // The current recoverable errors are: the errors accepted by 221 // IsCertificateError(err) and HTTPS_PROXY_TUNNEL_RESPONSE when reported by 222 // HttpProxyClientSocketPool. 223 // 224 // If this function returns OK, then |handle| is initialized upon return. 225 // The |handle|'s is_initialized method will return true in this case. If a 226 // StreamSocket was reused, then ClientSocketPool will call 227 // |handle|->set_reused(true). In either case, the socket will have been 228 // allocated and will be connected. A client might want to know whether or 229 // not the socket is reused in order to request a new socket if it encounters 230 // an error with the reused socket. 231 // 232 // If ERR_IO_PENDING is returned, then the callback will be used to notify the 233 // client of completion. 234 // 235 // Profiling information for the request is saved to |net_log| if non-NULL. 236 // 237 // If |respect_limits| is DISABLED, priority must be HIGHEST. 238 // 239 // |proxy_annotation_tag| is the annotation used for proxy-related reads and 240 // writes, and may be nullopt if (and only if) no proxy is in use. 241 // 242 // |proxy_auth_callback| will be invoked each time an auth challenge is seen 243 // while establishing a tunnel. It will be invoked asynchronously, once for 244 // each auth challenge seen. 245 virtual int RequestSocket( 246 const GroupId& group_id, 247 scoped_refptr<SocketParams> params, 248 const std::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag, 249 RequestPriority priority, 250 const SocketTag& socket_tag, 251 RespectLimits respect_limits, 252 ClientSocketHandle* handle, 253 CompletionOnceCallback callback, 254 const ProxyAuthCallback& proxy_auth_callback, 255 const NetLogWithSource& net_log) = 0; 256 257 // RequestSockets is used to request that |num_sockets| be connected in the 258 // connection group for |group_id|. If the connection group already has 259 // |num_sockets| idle sockets / active sockets / currently connecting sockets, 260 // then this function doesn't do anything and returns OK. Otherwise, it will 261 // start up as many connections as necessary to reach |num_sockets| total 262 // sockets for the group and returns ERR_IO_PENDING. And |callback| will be 263 // called with OK when the connection tasks are finished. 264 // It uses |params| to control how to connect the sockets. The 265 // ClientSocketPool will assign a priority to the new connections, if any. 266 // This priority will probably be lower than all others, since this method 267 // is intended to make sure ahead of time that |num_sockets| sockets are 268 // available to talk to a host. 269 virtual int RequestSockets( 270 const GroupId& group_id, 271 scoped_refptr<SocketParams> params, 272 const std::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag, 273 int num_sockets, 274 CompletionOnceCallback callback, 275 const NetLogWithSource& net_log) = 0; 276 277 // Called to change the priority of a RequestSocket call that returned 278 // ERR_IO_PENDING and has not yet asynchronously completed. The same handle 279 // parameter must be passed to this method as was passed to the 280 // RequestSocket call being modified. 281 // This function is a no-op if |priority| is the same as the current 282 // request priority. 283 virtual void SetPriority(const GroupId& group_id, 284 ClientSocketHandle* handle, 285 RequestPriority priority) = 0; 286 287 // Called to cancel a RequestSocket call that returned ERR_IO_PENDING. The 288 // same handle parameter must be passed to this method as was passed to the 289 // RequestSocket call being cancelled. The associated callback is not run. 290 // If |cancel_connect_job| is true, and there are more ConnectJobs than 291 // requests, a ConnectJob will be canceled. If it's false, excess ConnectJobs 292 // may be allowed to continue, just in case there are new requests to the same 293 // endpoint. 294 virtual void CancelRequest(const GroupId& group_id, 295 ClientSocketHandle* handle, 296 bool cancel_connect_job) = 0; 297 298 // Called to release a socket once the socket is no longer needed. If the 299 // socket still has an established connection, then it will be added to the 300 // set of idle sockets to be used to satisfy future RequestSocket calls. 301 // Otherwise, the StreamSocket is destroyed. |generation| is used to 302 // differentiate between updated versions of the same pool instance. The 303 // pool's generation will change when it flushes, so it can use this 304 // |generation| to discard sockets with mismatched ids. 305 virtual void ReleaseSocket(const GroupId& group_id, 306 std::unique_ptr<StreamSocket> socket, 307 int64_t generation) = 0; 308 309 // This flushes all state from the ClientSocketPool. Pending socket requests 310 // are failed with |error|, while |reason| is logged to the NetLog. 311 // 312 // Active sockets being held by ClientSocketPool clients will be discarded 313 // when released back to the pool, though they will be closed with an error 314 // about being of the wrong generation, rather than |net_log_reason_utf8|. 315 virtual void FlushWithError(int error, const char* net_log_reason_utf8) = 0; 316 317 // Called to close any idle connections held by the connection manager. 318 // |reason| is logged to NetLog for debugging purposes. 319 virtual void CloseIdleSockets(const char* net_log_reason_utf8) = 0; 320 321 // Called to close any idle connections held by the connection manager. 322 // |reason| is logged to NetLog for debugging purposes. 323 virtual void CloseIdleSocketsInGroup(const GroupId& group_id, 324 const char* net_log_reason_utf8) = 0; 325 326 // The total number of idle sockets in the pool. 327 virtual int IdleSocketCount() const = 0; 328 329 // The total number of idle sockets in a connection group. 330 virtual size_t IdleSocketCountInGroup(const GroupId& group_id) const = 0; 331 332 // Determine the LoadState of a connecting ClientSocketHandle. 333 virtual LoadState GetLoadState(const GroupId& group_id, 334 const ClientSocketHandle* handle) const = 0; 335 336 // Retrieves information on the current state of the pool as a 337 // Value. 338 // If |include_nested_pools| is true, the states of any nested 339 // ClientSocketPools will be included. 340 virtual base::Value GetInfoAsValue(const std::string& name, 341 const std::string& type) const = 0; 342 343 // Returns whether a connected (idle or handed out) or connecting socket 344 // exists for the group. This method is not supported for WebSockets. 345 virtual bool HasActiveSocket(const GroupId& group_id) const = 0; 346 347 // Returns the maximum amount of time to wait before retrying a connect. 348 static const int kMaxConnectRetryIntervalMs = 250; 349 350 static base::TimeDelta used_idle_socket_timeout(); 351 static void set_used_idle_socket_timeout(base::TimeDelta timeout); 352 353 protected: 354 ClientSocketPool(bool is_for_websockets, 355 const CommonConnectJobParams* common_connect_job_params, 356 std::unique_ptr<ConnectJobFactory> connect_job_factory); 357 358 void NetLogTcpClientSocketPoolRequestedSocket(const NetLogWithSource& net_log, 359 const GroupId& group_id); 360 361 // Utility method to log a GroupId with a NetLog event. 362 static base::Value::Dict NetLogGroupIdParams(const GroupId& group_id); 363 364 std::unique_ptr<ConnectJob> CreateConnectJob( 365 GroupId group_id, 366 scoped_refptr<SocketParams> socket_params, 367 const ProxyChain& proxy_chain, 368 const std::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag, 369 RequestPriority request_priority, 370 SocketTag socket_tag, 371 ConnectJob::Delegate* delegate); 372 373 private: 374 const bool is_for_websockets_; 375 const raw_ptr<const CommonConnectJobParams> common_connect_job_params_; 376 const std::unique_ptr<ConnectJobFactory> connect_job_factory_; 377 }; 378 379 } // namespace net 380 381 #endif // NET_SOCKET_CLIENT_SOCKET_POOL_H_ 382