// 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_SPDY_SPDY_SESSION_POOL_H_ #define NET_SPDY_SPDY_SESSION_POOL_H_ #include #include #include #include #include #include #include #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "net/base/host_port_pair.h" #include "net/base/ip_endpoint.h" #include "net/base/net_errors.h" #include "net/base/net_export.h" #include "net/base/network_change_notifier.h" #include "net/base/proxy_server.h" #include "net/cert/cert_database.h" #include "net/proxy_resolution/proxy_config.h" #include "net/spdy/http2_push_promise_index.h" #include "net/spdy/server_push_delegate.h" #include "net/spdy/spdy_session_key.h" #include "net/ssl/ssl_config_service.h" #include "net/third_party/quic/core/quic_versions.h" #include "net/third_party/spdy/core/spdy_protocol.h" namespace base { namespace trace_event { class ProcessMemoryDump; } } namespace net { class ClientSocketHandle; class HostResolver; class HttpServerProperties; class HttpStreamRequest; class NetLogWithSource; class SpdySession; class TransportSecurityState; // This is a very simple pool for open SpdySessions. class NET_EXPORT SpdySessionPool : public NetworkChangeNotifier::IPAddressObserver, public SSLConfigService::Observer, public CertDatabase::Observer { public: typedef base::TimeTicks (*TimeFunc)(void); SpdySessionPool(HostResolver* host_resolver, SSLConfigService* ssl_config_service, HttpServerProperties* http_server_properties, TransportSecurityState* transport_security_state, const QuicTransportVersionVector& quic_supported_versions, bool enable_ping_based_connection_checking, bool support_ietf_format_quic_altsvc, size_t session_max_recv_window_size, const spdy::SettingsMap& initial_settings, SpdySessionPool::TimeFunc time_func); ~SpdySessionPool() override; // In the functions below, a session is "available" if this pool has // a reference to it and there is some SpdySessionKey for which // FindAvailableSession() will return it. A session is "unavailable" // if this pool has a reference to it but it won't be returned by // FindAvailableSession() for any SpdySessionKey; for example, this // can happen when a session receives a GOAWAY frame and is still // processing existing streams. // Create a new SPDY session from an existing socket. There must // not already be a session for the given key. // // Returns the new SpdySession. Note that the SpdySession begins reading from // |connection| on a subsequent event loop iteration, so it may be closed // immediately afterwards if the first read of |connection| fails. base::WeakPtr CreateAvailableSessionFromSocket( const SpdySessionKey& key, bool is_trusted_proxy, std::unique_ptr connection, const NetLogWithSource& net_log); // If there is an available session for |key|, return it. // Otherwise if there is a session to pool to based on IP address: // * if |enable_ip_based_pooling == true|, // then mark it as available for |key| and return it; // * if |enable_ip_based_pooling == false|, // then remove it from the available sessions, and return nullptr. // Otherwise return nullptr. base::WeakPtr FindAvailableSession( const SpdySessionKey& key, bool enable_ip_based_pooling, bool is_websocket, const NetLogWithSource& net_log); // Remove all mappings and aliases for the given session, which must // still be available. Except for in tests, this must be called by // the given session itself. void MakeSessionUnavailable( const base::WeakPtr& available_session); // Removes an unavailable session from the pool. Except for in // tests, this must be called by the given session itself. void RemoveUnavailableSession( const base::WeakPtr& unavailable_session); // Note that the next three methods close sessions, potentially notifing // delegates of error or synchronously invoking callbacks, which might trigger // retries, thus opening new sessions. // Close only the currently existing SpdySessions with |error|. // Let any new ones created while this method is running continue to // live. void CloseCurrentSessions(Error error); // Close only the currently existing SpdySessions that are idle. // Let any new ones created while this method is running continue to // live. void CloseCurrentIdleSessions(); // Repeatedly close all SpdySessions until all of them (including new ones // created in the process of closing the current ones, and new ones created in // the process of closing those new ones, etc.) are unavailable. void CloseAllSessions(); // Creates a Value summary of the state of the spdy session pool. std::unique_ptr SpdySessionPoolInfoToValue() const; HttpServerProperties* http_server_properties() { return http_server_properties_; } Http2PushPromiseIndex* push_promise_index() { return &push_promise_index_; } void set_server_push_delegate(ServerPushDelegate* push_delegate) { push_delegate_ = push_delegate; } // NetworkChangeNotifier::IPAddressObserver methods: // We flush all idle sessions and release references to the active ones so // they won't get re-used. The active ones will either complete successfully // or error out due to the IP address change. void OnIPAddressChanged() override; // SSLConfigService::Observer methods: // We perform the same flushing as described above when SSL settings change. void OnSSLConfigChanged() override; // CertDatabase::Observer methods: // We perform the same flushing as described above when certificate database // is changed. void OnCertDBChanged() override; void DumpMemoryStats(base::trace_event::ProcessMemoryDump* pmd, const std::string& parent_dump_absolute_name) const; // Called when a SpdySession is ready. It will find appropriate Requests and // fulfill them. void OnNewSpdySessionReady(const base::WeakPtr& spdy_session, const SSLConfig& used_ssl_config, const ProxyInfo& used_proxy_info, bool was_alpn_negotiated, NextProto negotiated_protocol, bool using_spdy, NetLogSource source_dependency); // Called when a HttpStreamRequest is started with |spdy_session_key|. // Returns true if the request should continue. Returns false if the request // should wait until |callback| is invoked before continuing. bool StartRequest(const SpdySessionKey& spdy_session_key, const base::Closure& callback); // Resumes pending requests with |spdy_session_key|. void ResumePendingRequests(const SpdySessionKey& spdy_session_key); // Adds |request| to |spdy_session_request_map_| under |spdy_session_key| Key. // Sets |spdy_session_key| as |request|'s SpdySessionKey. void AddRequestToSpdySessionRequestMap(const SpdySessionKey& spdy_session_key, HttpStreamRequest* request); // Removes |request| from |spdy_session_request_map_|. No-op if |request| does // not have a SpdySessionKey. void RemoveRequestFromSpdySessionRequestMap(HttpStreamRequest* request); private: friend class SpdySessionPoolPeer; // For testing. typedef std::set RequestSet; typedef std::map SpdySessionRequestMap; typedef std::set SessionSet; typedef std::vector > WeakSessionList; typedef std::map > AvailableSessionMap; typedef std::multimap AliasMap; // Returns true iff |session| is in |available_sessions_|. bool IsSessionAvailable(const base::WeakPtr& session) const; // Map the given key to the given session. There must not already be // a mapping for |key|. void MapKeyToAvailableSession(const SpdySessionKey& key, const base::WeakPtr& session); // Returns an iterator into |available_sessions_| for the given key, // which may be equal to |available_sessions_.end()|. AvailableSessionMap::iterator LookupAvailableSessionByKey( const SpdySessionKey& key); // Remove the mapping of the given key, which must exist. void UnmapKey(const SpdySessionKey& key); // Remove all aliases for |key| from the aliases table. void RemoveAliases(const SpdySessionKey& key); // Get a copy of the current sessions as a list of WeakPtrs. Used by // CloseCurrentSessionsHelper() below. WeakSessionList GetCurrentSessions() const; // Close only the currently existing SpdySessions with |error|. Let // any new ones created while this method is running continue to // live. If |idle_only| is true only idle sessions are closed. void CloseCurrentSessionsHelper(Error error, const std::string& description, bool idle_only); HttpServerProperties* http_server_properties_; TransportSecurityState* transport_security_state_; // The set of all sessions. This is a superset of the sessions in // |available_sessions_|. // // |sessions_| owns all its SpdySession objects. SessionSet sessions_; // This is a map of available sessions by key. A session may appear // more than once in this map if it has aliases. AvailableSessionMap available_sessions_; // A map of IPEndPoint aliases for sessions. AliasMap aliases_; // The index of all unclaimed pushed streams of all SpdySessions in this pool. Http2PushPromiseIndex push_promise_index_; const scoped_refptr ssl_config_service_; HostResolver* const resolver_; // Versions of QUIC which may be used. const QuicTransportVersionVector quic_supported_versions_; // Defaults to true. May be controlled via SpdySessionPoolPeer for tests. bool enable_sending_initial_data_; bool enable_ping_based_connection_checking_; // If true, alt-svc headers advertising QUIC in IETF format will be supported. bool support_ietf_format_quic_altsvc_; size_t session_max_recv_window_size_; // Settings that are sent in the initial SETTINGS frame // (if |enable_sending_initial_data_| is true), // and also control SpdySession parameters like initial receive window size // and maximum HPACK dynamic table size. const spdy::SettingsMap initial_settings_; // TODO(xunjieli): Merge these two. SpdySessionRequestMap spdy_session_request_map_; typedef std::map> SpdySessionPendingRequestMap; SpdySessionPendingRequestMap spdy_session_pending_request_map_; TimeFunc time_func_; ServerPushDelegate* push_delegate_; DISALLOW_COPY_AND_ASSIGN(SpdySessionPool); }; } // namespace net #endif // NET_SPDY_SPDY_SESSION_POOL_H_