1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
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_SPDY_SPDY_SESSION_POOL_H_
6#define NET_SPDY_SPDY_SESSION_POOL_H_
7#pragma once
8
9#include <map>
10#include <list>
11#include <string>
12
13#include "base/basictypes.h"
14#include "base/gtest_prod_util.h"
15#include "base/memory/ref_counted.h"
16#include "base/memory/scoped_ptr.h"
17#include "net/base/cert_database.h"
18#include "net/base/host_port_pair.h"
19#include "net/base/ip_endpoint.h"
20#include "net/base/net_errors.h"
21#include "net/base/network_change_notifier.h"
22#include "net/base/ssl_config_service.h"
23#include "net/proxy/proxy_config.h"
24#include "net/proxy/proxy_server.h"
25#include "net/spdy/spdy_settings_storage.h"
26
27namespace net {
28
29class AddressList;
30class BoundNetLog;
31class ClientSocketHandle;
32class HostResolver;
33class HttpNetworkSession;
34class SpdySession;
35
36// This is a very simple pool for open SpdySessions.
37class SpdySessionPool
38    : public NetworkChangeNotifier::IPAddressObserver,
39      public SSLConfigService::Observer,
40      public CertDatabase::Observer {
41 public:
42  explicit SpdySessionPool(HostResolver* host_resolver,
43                           SSLConfigService* ssl_config_service);
44  virtual ~SpdySessionPool();
45
46  // Either returns an existing SpdySession or creates a new SpdySession for
47  // use.
48  scoped_refptr<SpdySession> Get(
49      const HostPortProxyPair& host_port_proxy_pair,
50      const BoundNetLog& net_log);
51
52  // Set the maximum concurrent sessions per domain.
53  static void set_max_sessions_per_domain(int max) {
54    if (max >= 1)
55      g_max_sessions_per_domain = max;
56  }
57
58  // Builds a SpdySession from an existing SSL socket.  Users should try
59  // calling Get() first to use an existing SpdySession so we don't get
60  // multiple SpdySessions per domain.  Note that ownership of |connection| is
61  // transferred from the caller to the SpdySession.
62  // |certificate_error_code| is used to indicate the certificate error
63  // encountered when connecting the SSL socket.  OK means there was no error.
64  // For testing, setting is_secure to false allows Spdy to connect with a
65  // pre-existing TCP socket.
66  // Returns OK on success, and the |spdy_session| will be provided.
67  // Returns an error on failure, and |spdy_session| will be NULL.
68  net::Error GetSpdySessionFromSocket(
69      const HostPortProxyPair& host_port_proxy_pair,
70      ClientSocketHandle* connection,
71      const BoundNetLog& net_log,
72      int certificate_error_code,
73      scoped_refptr<SpdySession>* spdy_session,
74      bool is_secure);
75
76  // TODO(willchan): Consider renaming to HasReusableSession, since perhaps we
77  // should be creating a new session.
78  bool HasSession(const HostPortProxyPair& host_port_proxy_pair) const;
79
80  // Close all SpdySessions, including any new ones created in the process of
81  // closing the current ones.
82  void CloseAllSessions();
83  // Close only the currently existing SpdySessions. Let any new ones created
84  // continue to live.
85  void CloseCurrentSessions();
86  // Close only the idle SpdySessions.
87  void CloseIdleSessions();
88
89  // Removes a SpdySession from the SpdySessionPool. This should only be called
90  // by SpdySession, because otherwise session->state_ is not set to CLOSED.
91  void Remove(const scoped_refptr<SpdySession>& session);
92
93  // Creates a Value summary of the state of the spdy session pool. The caller
94  // responsible for deleting the returned value.
95  Value* SpdySessionPoolInfoToValue() const;
96
97  SpdySettingsStorage* mutable_spdy_settings() { return &spdy_settings_; }
98  const SpdySettingsStorage& spdy_settings() const { return spdy_settings_; }
99
100  // NetworkChangeNotifier::IPAddressObserver methods:
101
102  // We flush all idle sessions and release references to the active ones so
103  // they won't get re-used.  The active ones will either complete successfully
104  // or error out due to the IP address change.
105  virtual void OnIPAddressChanged();
106
107  // SSLConfigService::Observer methods:
108
109  // We perform the same flushing as described above when SSL settings change.
110  virtual void OnSSLConfigChanged();
111
112  // A debugging mode where we compress all accesses through a single domain.
113  static void ForceSingleDomain() { g_force_single_domain = true; }
114
115  // Controls whether the pool allows use of a common session for domains
116  // which share IP address resolutions.
117  static void enable_ip_pooling(bool value) { g_enable_ip_pooling = value; }
118
119  // CertDatabase::Observer methods:
120  virtual void OnUserCertAdded(const X509Certificate* cert);
121  virtual void OnCertTrustChanged(const X509Certificate* cert);
122
123 private:
124  friend class SpdySessionPoolPeer;  // For testing.
125  friend class SpdyNetworkTransactionTest;  // For testing.
126  FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionTest, WindowUpdateOverflow);
127
128  typedef std::list<scoped_refptr<SpdySession> > SpdySessionList;
129  typedef std::map<HostPortProxyPair, SpdySessionList*> SpdySessionsMap;
130  typedef std::map<IPEndPoint, HostPortProxyPair> SpdyAliasMap;
131
132  scoped_refptr<SpdySession> GetExistingSession(
133      SpdySessionList* list,
134      const BoundNetLog& net_log) const;
135  scoped_refptr<SpdySession> GetFromAlias(
136      const HostPortProxyPair& host_port_proxy_pair,
137      const BoundNetLog& net_log,
138      bool record_histograms) const;
139
140  // Helper functions for manipulating the lists.
141  const HostPortProxyPair& NormalizeListPair(
142      const HostPortProxyPair& host_port_proxy_pair) const;
143  SpdySessionList* AddSessionList(
144      const HostPortProxyPair& host_port_proxy_pair);
145  SpdySessionList* GetSessionList(
146      const HostPortProxyPair& host_port_proxy_pair) const;
147  void RemoveSessionList(const HostPortProxyPair& host_port_proxy_pair);
148
149  // Does a DNS cache lookup for |pair|, and returns the |addresses| found.
150  // Returns true if addresses found, false otherwise.
151  bool LookupAddresses(const HostPortProxyPair& pair,
152                       AddressList* addresses) const;
153
154  // Add a set of |addresses| as IP-equivalent addresses for |pair|.
155  void AddAliases(const AddressList& addresses, const HostPortProxyPair& pair);
156
157  // Remove all aliases for |pair| from the aliases table.
158  void RemoveAliases(const HostPortProxyPair& pair);
159
160  SpdySettingsStorage spdy_settings_;
161
162  // This is our weak session pool - one session per domain.
163  SpdySessionsMap sessions_;
164  // A map of IPEndPoint aliases for sessions.
165  SpdyAliasMap aliases_;
166
167  static size_t g_max_sessions_per_domain;
168  static bool g_force_single_domain;
169  static bool g_enable_ip_pooling;
170
171  const scoped_refptr<SSLConfigService> ssl_config_service_;
172  HostResolver* resolver_;
173
174  DISALLOW_COPY_AND_ASSIGN(SpdySessionPool);
175};
176
177}  // namespace net
178
179#endif  // NET_SPDY_SPDY_SESSION_POOL_H_
180