summaryrefslogtreecommitdiffstats
path: root/net/spdy/spdy_session_pool.h
blob: 33e2db1aa028627400df3862f2b1c0e0fdc037f7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
// 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_
#pragma once

#include <map>
#include <list>
#include <string>

#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "net/base/cert_database.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/ssl_config_service.h"
#include "net/proxy/proxy_config.h"
#include "net/proxy/proxy_server.h"
#include "net/spdy/spdy_settings_storage.h"

namespace net {

class AddressList;
class BoundNetLog;
class ClientSocketHandle;
class HostResolver;
class HttpServerProperties;
class SpdySession;

namespace test_spdy2 {
class SpdySessionPoolPeer;
}  // namespace test_spdy

namespace test_spdy3 {
class SpdySessionPoolPeer;
}  // namespace test_spdy

// This is a very simple pool for open SpdySessions.
class NET_EXPORT SpdySessionPool
    : public NetworkChangeNotifier::IPAddressObserver,
      public SSLConfigService::Observer,
      public CertDatabase::Observer {
 public:
  SpdySessionPool(HostResolver* host_resolver,
                  SSLConfigService* ssl_config_service,
                  HttpServerProperties* http_server_properties);
  virtual ~SpdySessionPool();

  // Either returns an existing SpdySession or creates a new SpdySession for
  // use.
  scoped_refptr<SpdySession> Get(
      const HostPortProxyPair& host_port_proxy_pair,
      const BoundNetLog& net_log);

  // Only returns a SpdySession if it already exists.
  scoped_refptr<SpdySession> GetIfExists(
      const HostPortProxyPair& host_port_proxy_pair,
      const BoundNetLog& net_log);

  // Set the maximum concurrent sessions per domain.
  static void set_max_sessions_per_domain(int max) {
    if (max >= 1)
      g_max_sessions_per_domain = max;
  }

  // Builds a SpdySession from an existing SSL socket.  Users should try
  // calling Get() first to use an existing SpdySession so we don't get
  // multiple SpdySessions per domain.  Note that ownership of |connection| is
  // transferred from the caller to the SpdySession.
  // |certificate_error_code| is used to indicate the certificate error
  // encountered when connecting the SSL socket.  OK means there was no error.
  // For testing, setting is_secure to false allows Spdy to connect with a
  // pre-existing TCP socket.
  // Returns OK on success, and the |spdy_session| will be provided.
  // Returns an error on failure, and |spdy_session| will be NULL.
  net::Error GetSpdySessionFromSocket(
      const HostPortProxyPair& host_port_proxy_pair,
      ClientSocketHandle* connection,
      const BoundNetLog& net_log,
      int certificate_error_code,
      scoped_refptr<SpdySession>* spdy_session,
      bool is_secure);

  // TODO(willchan): Consider renaming to HasReusableSession, since perhaps we
  // should be creating a new session. WARNING: Because of IP connection pooling
  // using the HostCache, if HasSession() returns true at one point, it does not
  // imply the SpdySessionPool will still have a matching session in the near
  // future, since the HostCache's entry may have expired.
  bool HasSession(const HostPortProxyPair& host_port_proxy_pair) const;

  // Close all SpdySessions, including any new ones created in the process of
  // closing the current ones.
  void CloseAllSessions();
  // Close only the currently existing SpdySessions. Let any new ones created
  // continue to live.
  void CloseCurrentSessions();
  // Close only the idle SpdySessions.
  void CloseIdleSessions();

  // Removes a SpdySession from the SpdySessionPool. This should only be called
  // by SpdySession, because otherwise session->state_ is not set to CLOSED.
  void Remove(const scoped_refptr<SpdySession>& session);

  // Creates a Value summary of the state of the spdy session pool. The caller
  // responsible for deleting the returned value.
  base::Value* SpdySessionPoolInfoToValue() const;

  SpdySettingsStorage* mutable_spdy_settings() { return &spdy_settings_; }
  const SpdySettingsStorage& spdy_settings() const { return spdy_settings_; }

  HttpServerProperties* http_server_properties() {
    return http_server_properties_;
  }

  // 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.
  virtual void OnIPAddressChanged() OVERRIDE;

  // SSLConfigService::Observer methods:

  // We perform the same flushing as described above when SSL settings change.
  virtual void OnSSLConfigChanged() OVERRIDE;

  // A debugging mode where we compress all accesses through a single domain.
  static void ForceSingleDomain() { g_force_single_domain = true; }

  // Controls whether the pool allows use of a common session for domains
  // which share IP address resolutions.
  static void enable_ip_pooling(bool value) { g_enable_ip_pooling = value; }

  // CertDatabase::Observer methods:
  virtual void OnUserCertAdded(const X509Certificate* cert) OVERRIDE;
  virtual void OnCertTrustChanged(const X509Certificate* cert) OVERRIDE;

 private:
  friend class test_spdy2::SpdySessionPoolPeer;  // For testing.
  friend class test_spdy3::SpdySessionPoolPeer;  // For testing.
  friend class SpdyNetworkTransactionSpdy2Test;  // For testing.
  friend class SpdyNetworkTransactionSpdy21Test;  // For testing.
  friend class SpdyNetworkTransactionSpdy3Test;  // For testing.
  FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionSpdy2Test,
                           WindowUpdateOverflow);
  FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionSpdy21Test,
                           WindowUpdateOverflow);
  FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionSpdy3Test,
                           WindowUpdateOverflow);

  typedef std::list<scoped_refptr<SpdySession> > SpdySessionList;
  typedef std::map<HostPortProxyPair, SpdySessionList*> SpdySessionsMap;
  typedef std::map<IPEndPoint, HostPortProxyPair> SpdyAliasMap;


  scoped_refptr<SpdySession> GetInternal(
      const HostPortProxyPair& host_port_proxy_pair,
      const BoundNetLog& net_log,
      bool only_use_existing_sessions);
  scoped_refptr<SpdySession> GetExistingSession(
      SpdySessionList* list,
      const BoundNetLog& net_log) const;
  scoped_refptr<SpdySession> GetFromAlias(
      const HostPortProxyPair& host_port_proxy_pair,
      const BoundNetLog& net_log,
      bool record_histograms) const;

  // Helper functions for manipulating the lists.
  const HostPortProxyPair& NormalizeListPair(
      const HostPortProxyPair& host_port_proxy_pair) const;
  SpdySessionList* AddSessionList(
      const HostPortProxyPair& host_port_proxy_pair);
  SpdySessionList* GetSessionList(
      const HostPortProxyPair& host_port_proxy_pair) const;
  void RemoveSessionList(const HostPortProxyPair& host_port_proxy_pair);

  // Does a DNS cache lookup for |pair|, and returns the |addresses| found.
  // Returns true if addresses found, false otherwise.
  bool LookupAddresses(const HostPortProxyPair& pair,
                       const BoundNetLog& net_log,
                       AddressList* addresses) const;

  // Add |address| as an IP-equivalent address for |pair|.
  void AddAlias(const addrinfo* address, const HostPortProxyPair& pair);

  // Remove all aliases for |pair| from the aliases table.
  void RemoveAliases(const HostPortProxyPair& pair);

  SpdySettingsStorage spdy_settings_;
  HttpServerProperties* const http_server_properties_;

  // This is our weak session pool - one session per domain.
  SpdySessionsMap sessions_;
  // A map of IPEndPoint aliases for sessions.
  SpdyAliasMap aliases_;

  static size_t g_max_sessions_per_domain;
  static bool g_force_single_domain;
  static bool g_enable_ip_pooling;

  const scoped_refptr<SSLConfigService> ssl_config_service_;
  HostResolver* const resolver_;

  // Defaults to true. May be controlled via SpdySessionPoolPeer for tests.
  bool verify_domain_authentication_;

  DISALLOW_COPY_AND_ASSIGN(SpdySessionPool);
};

}  // namespace net

#endif  // NET_SPDY_SPDY_SESSION_POOL_H_