Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / net / spdy / spdy_session_pool_unittest.cc
1 // Copyright (c) 2013 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 #include "net/spdy/spdy_session_pool.h"
6
7 #include <cstddef>
8 #include <string>
9
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "net/dns/host_cache.h"
13 #include "net/http/http_network_session.h"
14 #include "net/socket/client_socket_handle.h"
15 #include "net/socket/transport_client_socket_pool.h"
16 #include "net/spdy/spdy_session.h"
17 #include "net/spdy/spdy_test_util_common.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 namespace net {
21
22 namespace {
23
24 class SpdySessionPoolTest : public ::testing::Test,
25                             public ::testing::WithParamInterface<NextProto> {
26  protected:
27   // Used by RunIPPoolingTest().
28   enum SpdyPoolCloseSessionsType {
29     SPDY_POOL_CLOSE_SESSIONS_MANUALLY,
30     SPDY_POOL_CLOSE_CURRENT_SESSIONS,
31     SPDY_POOL_CLOSE_IDLE_SESSIONS,
32   };
33
34   SpdySessionPoolTest()
35       : session_deps_(GetParam()),
36         spdy_session_pool_(NULL) {}
37
38   void CreateNetworkSession() {
39     http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
40     spdy_session_pool_ = http_session_->spdy_session_pool();
41   }
42
43   void RunIPPoolingTest(SpdyPoolCloseSessionsType close_sessions_type);
44
45   SpdySessionDependencies session_deps_;
46   scoped_refptr<HttpNetworkSession> http_session_;
47   SpdySessionPool* spdy_session_pool_;
48 };
49
50 INSTANTIATE_TEST_CASE_P(
51     NextProto,
52     SpdySessionPoolTest,
53     testing::Values(kProtoDeprecatedSPDY2,
54                     kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
55
56 // A delegate that opens a new session when it is closed.
57 class SessionOpeningDelegate : public SpdyStream::Delegate {
58  public:
59   SessionOpeningDelegate(SpdySessionPool* spdy_session_pool,
60                          const SpdySessionKey& key)
61       : spdy_session_pool_(spdy_session_pool),
62         key_(key) {}
63
64   virtual ~SessionOpeningDelegate() {}
65
66   virtual void OnRequestHeadersSent() OVERRIDE {}
67
68   virtual SpdyResponseHeadersStatus OnResponseHeadersUpdated(
69       const SpdyHeaderBlock& response_headers) OVERRIDE {
70     return RESPONSE_HEADERS_ARE_COMPLETE;
71   }
72
73   virtual void OnDataReceived(scoped_ptr<SpdyBuffer> buffer) OVERRIDE {}
74
75   virtual void OnDataSent() OVERRIDE {}
76
77   virtual void OnClose(int status) OVERRIDE {
78     ignore_result(CreateFakeSpdySession(spdy_session_pool_, key_));
79   }
80
81  private:
82   SpdySessionPool* const spdy_session_pool_;
83   const SpdySessionKey key_;
84 };
85
86 // Set up a SpdyStream to create a new session when it is closed.
87 // CloseCurrentSessions should not close the newly-created session.
88 TEST_P(SpdySessionPoolTest, CloseCurrentSessions) {
89   const char kTestHost[] = "www.foo.com";
90   const int kTestPort = 80;
91
92   session_deps_.host_resolver->set_synchronous_mode(true);
93
94   HostPortPair test_host_port_pair(kTestHost, kTestPort);
95   SpdySessionKey test_key =
96       SpdySessionKey(
97           test_host_port_pair, ProxyServer::Direct(),
98           PRIVACY_MODE_DISABLED);
99
100   MockConnect connect_data(SYNCHRONOUS, OK);
101   MockRead reads[] = {
102     MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
103   };
104
105   StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
106   data.set_connect_data(connect_data);
107   session_deps_.socket_factory->AddSocketDataProvider(&data);
108
109   SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
110   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
111
112   CreateNetworkSession();
113
114   // Setup the first session to the first host.
115   base::WeakPtr<SpdySession> session =
116       CreateInsecureSpdySession(http_session_, test_key, BoundNetLog());
117
118   // Flush the SpdySession::OnReadComplete() task.
119   base::MessageLoop::current()->RunUntilIdle();
120
121   // Verify that we have sessions for everything.
122   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
123
124   // Set the stream to create a new session when it is closed.
125   base::WeakPtr<SpdyStream> spdy_stream =
126       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
127                                 session, GURL("http://www.foo.com"),
128                                 MEDIUM, BoundNetLog());
129   SessionOpeningDelegate delegate(spdy_session_pool_, test_key);
130   spdy_stream->SetDelegate(&delegate);
131
132   // Close the current session.
133   spdy_session_pool_->CloseCurrentSessions(net::ERR_ABORTED);
134
135   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
136 }
137
138 TEST_P(SpdySessionPoolTest, CloseCurrentIdleSessions) {
139   MockConnect connect_data(SYNCHRONOUS, OK);
140   MockRead reads[] = {
141     MockRead(ASYNC, 0, 0)  // EOF
142   };
143
144   session_deps_.host_resolver->set_synchronous_mode(true);
145
146   StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
147   data.set_connect_data(connect_data);
148   session_deps_.socket_factory->AddSocketDataProvider(&data);
149
150   SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
151   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
152
153   CreateNetworkSession();
154
155   // Set up session 1
156   const std::string kTestHost1("http://www.a.com");
157   HostPortPair test_host_port_pair1(kTestHost1, 80);
158   SpdySessionKey key1(test_host_port_pair1, ProxyServer::Direct(),
159                       PRIVACY_MODE_DISABLED);
160   base::WeakPtr<SpdySession> session1 =
161       CreateInsecureSpdySession(http_session_, key1, BoundNetLog());
162   GURL url1(kTestHost1);
163   base::WeakPtr<SpdyStream> spdy_stream1 =
164       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
165                                 session1, url1, MEDIUM, BoundNetLog());
166   ASSERT_TRUE(spdy_stream1.get() != NULL);
167
168   // Set up session 2
169   session_deps_.socket_factory->AddSocketDataProvider(&data);
170   const std::string kTestHost2("http://www.b.com");
171   HostPortPair test_host_port_pair2(kTestHost2, 80);
172   SpdySessionKey key2(test_host_port_pair2, ProxyServer::Direct(),
173                       PRIVACY_MODE_DISABLED);
174   base::WeakPtr<SpdySession> session2 =
175       CreateInsecureSpdySession(http_session_, key2, BoundNetLog());
176   GURL url2(kTestHost2);
177   base::WeakPtr<SpdyStream> spdy_stream2 =
178       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
179                                 session2, url2, MEDIUM, BoundNetLog());
180   ASSERT_TRUE(spdy_stream2.get() != NULL);
181
182   // Set up session 3
183   session_deps_.socket_factory->AddSocketDataProvider(&data);
184   const std::string kTestHost3("http://www.c.com");
185   HostPortPair test_host_port_pair3(kTestHost3, 80);
186   SpdySessionKey key3(test_host_port_pair3, ProxyServer::Direct(),
187                       PRIVACY_MODE_DISABLED);
188   base::WeakPtr<SpdySession> session3 =
189       CreateInsecureSpdySession(http_session_, key3, BoundNetLog());
190   GURL url3(kTestHost3);
191   base::WeakPtr<SpdyStream> spdy_stream3 =
192       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
193                                 session3, url3, MEDIUM, BoundNetLog());
194   ASSERT_TRUE(spdy_stream3.get() != NULL);
195
196   // All sessions are active and not closed
197   EXPECT_TRUE(session1->is_active());
198   EXPECT_FALSE(session1->IsClosed());
199   EXPECT_TRUE(session2->is_active());
200   EXPECT_FALSE(session2->IsClosed());
201   EXPECT_TRUE(session3->is_active());
202   EXPECT_FALSE(session3->IsClosed());
203
204   // Should not do anything, all are active
205   spdy_session_pool_->CloseCurrentIdleSessions();
206   EXPECT_TRUE(session1->is_active());
207   EXPECT_FALSE(session1->IsClosed());
208   EXPECT_TRUE(session2->is_active());
209   EXPECT_FALSE(session2->IsClosed());
210   EXPECT_TRUE(session3->is_active());
211   EXPECT_FALSE(session3->IsClosed());
212
213   // Make sessions 1 and 3 inactive, but keep them open.
214   // Session 2 still open and active
215   session1->CloseCreatedStream(spdy_stream1, OK);
216   EXPECT_EQ(NULL, spdy_stream1.get());
217   session3->CloseCreatedStream(spdy_stream3, OK);
218   EXPECT_EQ(NULL, spdy_stream3.get());
219   EXPECT_FALSE(session1->is_active());
220   EXPECT_FALSE(session1->IsClosed());
221   EXPECT_TRUE(session2->is_active());
222   EXPECT_FALSE(session2->IsClosed());
223   EXPECT_FALSE(session3->is_active());
224   EXPECT_FALSE(session3->IsClosed());
225
226   // Should close session 1 and 3, 2 should be left open
227   spdy_session_pool_->CloseCurrentIdleSessions();
228   EXPECT_TRUE(session1 == NULL);
229   EXPECT_TRUE(session2->is_active());
230   EXPECT_FALSE(session2->IsClosed());
231   EXPECT_TRUE(session3 == NULL);
232
233   // Should not do anything
234   spdy_session_pool_->CloseCurrentIdleSessions();
235   EXPECT_TRUE(session2->is_active());
236   EXPECT_FALSE(session2->IsClosed());
237
238   // Make 2 not active
239   session2->CloseCreatedStream(spdy_stream2, OK);
240   EXPECT_EQ(NULL, spdy_stream2.get());
241   EXPECT_FALSE(session2->is_active());
242   EXPECT_FALSE(session2->IsClosed());
243
244   // This should close session 2
245   spdy_session_pool_->CloseCurrentIdleSessions();
246   EXPECT_TRUE(session2 == NULL);
247 }
248
249 // Set up a SpdyStream to create a new session when it is closed.
250 // CloseAllSessions should close the newly-created session.
251 TEST_P(SpdySessionPoolTest, CloseAllSessions) {
252   const char kTestHost[] = "www.foo.com";
253   const int kTestPort = 80;
254
255   session_deps_.host_resolver->set_synchronous_mode(true);
256
257   HostPortPair test_host_port_pair(kTestHost, kTestPort);
258   SpdySessionKey test_key =
259       SpdySessionKey(
260           test_host_port_pair, ProxyServer::Direct(),
261           PRIVACY_MODE_DISABLED);
262
263   MockConnect connect_data(SYNCHRONOUS, OK);
264   MockRead reads[] = {
265     MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
266   };
267
268   StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
269   data.set_connect_data(connect_data);
270   session_deps_.socket_factory->AddSocketDataProvider(&data);
271
272   SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
273   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
274
275   CreateNetworkSession();
276
277   // Setup the first session to the first host.
278   base::WeakPtr<SpdySession> session =
279       CreateInsecureSpdySession(http_session_, test_key, BoundNetLog());
280
281   // Flush the SpdySession::OnReadComplete() task.
282   base::MessageLoop::current()->RunUntilIdle();
283
284   // Verify that we have sessions for everything.
285   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
286
287   // Set the stream to create a new session when it is closed.
288   base::WeakPtr<SpdyStream> spdy_stream =
289       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
290                                 session, GURL("http://www.foo.com"),
291                                 MEDIUM, BoundNetLog());
292   SessionOpeningDelegate delegate(spdy_session_pool_, test_key);
293   spdy_stream->SetDelegate(&delegate);
294
295   // Close the current session.
296   spdy_session_pool_->CloseAllSessions();
297
298   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_key));
299 }
300
301 // This test has three variants, one for each style of closing the connection.
302 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_SESSIONS_MANUALLY,
303 // the sessions are closed manually, calling SpdySessionPool::Remove() directly.
304 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_CURRENT_SESSIONS,
305 // sessions are closed with SpdySessionPool::CloseCurrentSessions().
306 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_IDLE_SESSIONS,
307 // sessions are closed with SpdySessionPool::CloseIdleSessions().
308 void SpdySessionPoolTest::RunIPPoolingTest(
309     SpdyPoolCloseSessionsType close_sessions_type) {
310   const int kTestPort = 80;
311   struct TestHosts {
312     std::string url;
313     std::string name;
314     std::string iplist;
315     SpdySessionKey key;
316     AddressList addresses;
317   } test_hosts[] = {
318     { "http:://www.foo.com",
319       "www.foo.com",
320       "192.0.2.33,192.168.0.1,192.168.0.5"
321     },
322     { "http://js.foo.com",
323       "js.foo.com",
324       "192.168.0.2,192.168.0.3,192.168.0.5,192.0.2.33"
325     },
326     { "http://images.foo.com",
327       "images.foo.com",
328       "192.168.0.4,192.168.0.3"
329     },
330   };
331
332   session_deps_.host_resolver->set_synchronous_mode(true);
333   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_hosts); i++) {
334     session_deps_.host_resolver->rules()->AddIPLiteralRule(
335         test_hosts[i].name, test_hosts[i].iplist, std::string());
336
337     // This test requires that the HostResolver cache be populated.  Normal
338     // code would have done this already, but we do it manually.
339     HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort));
340     session_deps_.host_resolver->Resolve(info,
341                                          DEFAULT_PRIORITY,
342                                          &test_hosts[i].addresses,
343                                          CompletionCallback(),
344                                          NULL,
345                                          BoundNetLog());
346
347     // Setup a SpdySessionKey
348     test_hosts[i].key = SpdySessionKey(
349         HostPortPair(test_hosts[i].name, kTestPort), ProxyServer::Direct(),
350         PRIVACY_MODE_DISABLED);
351   }
352
353   MockConnect connect_data(SYNCHRONOUS, OK);
354   MockRead reads[] = {
355     MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
356   };
357
358   StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
359   data.set_connect_data(connect_data);
360   session_deps_.socket_factory->AddSocketDataProvider(&data);
361
362   SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
363   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
364
365   CreateNetworkSession();
366
367   // Setup the first session to the first host.
368   base::WeakPtr<SpdySession> session =
369       CreateInsecureSpdySession(
370           http_session_, test_hosts[0].key, BoundNetLog());
371
372   // Flush the SpdySession::OnReadComplete() task.
373   base::MessageLoop::current()->RunUntilIdle();
374
375   // The third host has no overlap with the first, so it can't pool IPs.
376   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
377
378   // The second host overlaps with the first, and should IP pool.
379   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
380
381   // Verify that the second host, through a proxy, won't share the IP.
382   SpdySessionKey proxy_key(test_hosts[1].key.host_port_pair(),
383       ProxyServer::FromPacString("HTTP http://proxy.foo.com/"),
384       PRIVACY_MODE_DISABLED);
385   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, proxy_key));
386
387   // Overlap between 2 and 3 does is not transitive to 1.
388   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
389
390   // Create a new session to host 2.
391   session_deps_.socket_factory->AddSocketDataProvider(&data);
392   base::WeakPtr<SpdySession> session2 =
393       CreateInsecureSpdySession(
394           http_session_, test_hosts[2].key, BoundNetLog());
395
396   // Verify that we have sessions for everything.
397   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[0].key));
398   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
399   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
400
401   // Grab the session to host 1 and verify that it is the same session
402   // we got with host 0, and that is a different from host 2's session.
403   base::WeakPtr<SpdySession> session1 =
404       spdy_session_pool_->FindAvailableSession(
405           test_hosts[1].key, BoundNetLog());
406   EXPECT_EQ(session.get(), session1.get());
407   EXPECT_NE(session2.get(), session1.get());
408
409   // Remove the aliases and observe that we still have a session for host1.
410   SpdySessionPoolPeer pool_peer(spdy_session_pool_);
411   pool_peer.RemoveAliases(test_hosts[0].key);
412   pool_peer.RemoveAliases(test_hosts[1].key);
413   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
414
415   // Expire the host cache
416   session_deps_.host_resolver->GetHostCache()->clear();
417   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
418
419   // Cleanup the sessions.
420   switch (close_sessions_type) {
421     case SPDY_POOL_CLOSE_SESSIONS_MANUALLY:
422       session->CloseSessionOnError(ERR_ABORTED, std::string());
423       EXPECT_TRUE(session == NULL);
424       session2->CloseSessionOnError(ERR_ABORTED, std::string());
425       EXPECT_TRUE(session2 == NULL);
426       break;
427     case SPDY_POOL_CLOSE_CURRENT_SESSIONS:
428       spdy_session_pool_->CloseCurrentSessions(ERR_ABORTED);
429       break;
430     case SPDY_POOL_CLOSE_IDLE_SESSIONS:
431       GURL url(test_hosts[0].url);
432       base::WeakPtr<SpdyStream> spdy_stream =
433           CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
434                                     session, url, MEDIUM, BoundNetLog());
435       GURL url1(test_hosts[1].url);
436       base::WeakPtr<SpdyStream> spdy_stream1 =
437           CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
438                                     session1, url1, MEDIUM, BoundNetLog());
439       GURL url2(test_hosts[2].url);
440       base::WeakPtr<SpdyStream> spdy_stream2 =
441           CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
442                                     session2, url2, MEDIUM, BoundNetLog());
443
444       // Close streams to make spdy_session and spdy_session1 inactive.
445       session->CloseCreatedStream(spdy_stream, OK);
446       EXPECT_EQ(NULL, spdy_stream.get());
447       session1->CloseCreatedStream(spdy_stream1, OK);
448       EXPECT_EQ(NULL, spdy_stream1.get());
449
450       // Check spdy_session and spdy_session1 are not closed.
451       EXPECT_FALSE(session->is_active());
452       EXPECT_FALSE(session->IsClosed());
453       EXPECT_FALSE(session1->is_active());
454       EXPECT_FALSE(session1->IsClosed());
455       EXPECT_TRUE(session2->is_active());
456       EXPECT_FALSE(session2->IsClosed());
457
458       // Test that calling CloseIdleSessions, does not cause a crash.
459       // http://crbug.com/181400
460       spdy_session_pool_->CloseCurrentIdleSessions();
461
462       // Verify spdy_session and spdy_session1 are closed.
463       EXPECT_TRUE(session == NULL);
464       EXPECT_TRUE(session1 == NULL);
465       EXPECT_TRUE(session2->is_active());
466       EXPECT_FALSE(session2->IsClosed());
467
468       spdy_stream2->Cancel();
469       EXPECT_EQ(NULL, spdy_stream.get());
470       EXPECT_EQ(NULL, spdy_stream1.get());
471       EXPECT_EQ(NULL, spdy_stream2.get());
472       session2->CloseSessionOnError(ERR_ABORTED, std::string());
473       EXPECT_TRUE(session2 == NULL);
474       break;
475   }
476
477   // Verify that the map is all cleaned up.
478   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[0].key));
479   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
480   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
481 }
482
483 TEST_P(SpdySessionPoolTest, IPPooling) {
484   RunIPPoolingTest(SPDY_POOL_CLOSE_SESSIONS_MANUALLY);
485 }
486
487 TEST_P(SpdySessionPoolTest, IPPoolingCloseCurrentSessions) {
488   RunIPPoolingTest(SPDY_POOL_CLOSE_CURRENT_SESSIONS);
489 }
490
491 TEST_P(SpdySessionPoolTest, IPPoolingCloseIdleSessions) {
492   RunIPPoolingTest(SPDY_POOL_CLOSE_IDLE_SESSIONS);
493 }
494
495 }  // namespace
496
497 }  // namespace net