blob: df6613457577e14e2e7c4347cfa9565dc69c9b0b [file] [log] [blame]
[email protected]e13201d82012-12-12 05:00:321// Copyright (c) 2012 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/quic/quic_stream_factory.h"
6
[email protected]e13201d82012-12-12 05:00:327#include "base/run_loop.h"
[email protected]fc9be5802013-06-11 10:56:518#include "base/strings/string_util.h"
[email protected]eed749f92013-12-23 18:57:389#include "net/base/test_data_directory.h"
[email protected]6d1b4ed2013-07-10 03:57:5410#include "net/cert/cert_verifier.h"
[email protected]f2cb3cf2013-03-21 01:40:5311#include "net/dns/mock_host_resolver.h"
[email protected]e13201d82012-12-12 05:00:3212#include "net/http/http_response_headers.h"
13#include "net/http/http_response_info.h"
14#include "net/http/http_util.h"
[email protected]080b77932014-08-04 01:22:4615#include "net/http/transport_security_state.h"
[email protected]c49ff182013-09-28 08:33:2616#include "net/quic/crypto/crypto_handshake.h"
[email protected]b694e48c2014-03-18 17:10:1317#include "net/quic/crypto/proof_verifier_chromium.h"
[email protected]4df69842013-02-27 06:32:1618#include "net/quic/crypto/quic_decrypter.h"
19#include "net/quic/crypto/quic_encrypter.h"
[email protected]e13201d82012-12-12 05:00:3220#include "net/quic/quic_http_stream.h"
[email protected]257f24f2014-04-01 09:15:3721#include "net/quic/quic_server_id.h"
[email protected]e13201d82012-12-12 05:00:3222#include "net/quic/test_tools/mock_clock.h"
[email protected]e8ff26842013-03-22 21:02:0523#include "net/quic/test_tools/mock_crypto_client_stream_factory.h"
[email protected]9558c5d32012-12-22 00:08:1424#include "net/quic/test_tools/mock_random.h"
[email protected]1e960032013-12-20 19:00:2025#include "net/quic/test_tools/quic_test_packet_maker.h"
[email protected]e13201d82012-12-12 05:00:3226#include "net/quic/test_tools/quic_test_utils.h"
27#include "net/socket/socket_test_util.h"
[email protected]6b8a3c742014-07-25 00:25:3528#include "net/ssl/channel_id_service.h"
29#include "net/ssl/default_channel_id_store.h"
[email protected]eed749f92013-12-23 18:57:3830#include "net/test/cert_test_util.h"
[email protected]e13201d82012-12-12 05:00:3231#include "testing/gtest/include/gtest/gtest.h"
32
[email protected]6e12d702013-11-13 00:17:1733using base::StringPiece;
34using std::string;
35using std::vector;
36
[email protected]e13201d82012-12-12 05:00:3237namespace net {
[email protected]e13201d82012-12-12 05:00:3238namespace test {
39
[email protected]3c772402013-12-18 21:38:1140namespace {
41const char kDefaultServerHostName[] = "www.google.com";
42const int kDefaultServerPort = 443;
43} // namespace anonymous
44
[email protected]c49ff182013-09-28 08:33:2645class QuicStreamFactoryPeer {
46 public:
[email protected]59c0bbd2014-03-22 04:08:1247 static QuicCryptoClientConfig* GetCryptoConfig(QuicStreamFactory* factory) {
48 return &factory->crypto_config_;
[email protected]c49ff182013-09-28 08:33:2649 }
[email protected]4d283b32013-10-17 12:57:2750
51 static bool HasActiveSession(QuicStreamFactory* factory,
[email protected]bf4ea2f2014-03-10 22:57:5352 const HostPortPair& host_port_pair,
[email protected]df157d9d2014-03-10 07:27:2753 bool is_https) {
[email protected]257f24f2014-04-01 09:15:3754 QuicServerId server_id(host_port_pair, is_https, PRIVACY_MODE_DISABLED);
55 return factory->HasActiveSession(server_id);
[email protected]4d283b32013-10-17 12:57:2756 }
57
58 static QuicClientSession* GetActiveSession(
59 QuicStreamFactory* factory,
[email protected]bf4ea2f2014-03-10 22:57:5360 const HostPortPair& host_port_pair,
[email protected]df157d9d2014-03-10 07:27:2761 bool is_https) {
[email protected]257f24f2014-04-01 09:15:3762 QuicServerId server_id(host_port_pair, is_https, PRIVACY_MODE_DISABLED);
63 DCHECK(factory->HasActiveSession(server_id));
64 return factory->active_sessions_[server_id];
[email protected]df157d9d2014-03-10 07:27:2765 }
66
67 static scoped_ptr<QuicHttpStream> CreateIfSessionExists(
68 QuicStreamFactory* factory,
[email protected]bf4ea2f2014-03-10 22:57:5369 const HostPortPair& host_port_pair,
[email protected]df157d9d2014-03-10 07:27:2770 bool is_https,
71 const BoundNetLog& net_log) {
[email protected]257f24f2014-04-01 09:15:3772 QuicServerId server_id(host_port_pair, is_https, PRIVACY_MODE_DISABLED);
73 return factory->CreateIfSessionExists(server_id, net_log);
[email protected]4d283b32013-10-17 12:57:2774 }
75
76 static bool IsLiveSession(QuicStreamFactory* factory,
77 QuicClientSession* session) {
[email protected]4d590c9c2014-05-02 05:14:3378 for (QuicStreamFactory::SessionIdMap::iterator it =
[email protected]4d283b32013-10-17 12:57:2779 factory->all_sessions_.begin();
80 it != factory->all_sessions_.end(); ++it) {
[email protected]4d590c9c2014-05-02 05:14:3381 if (it->first == session)
[email protected]4d283b32013-10-17 12:57:2782 return true;
83 }
84 return false;
85 }
[email protected]c49ff182013-09-28 08:33:2686};
87
[email protected]1e960032013-12-20 19:00:2088class QuicStreamFactoryTest : public ::testing::TestWithParam<QuicVersion> {
[email protected]e13201d82012-12-12 05:00:3289 protected:
90 QuicStreamFactoryTest()
[email protected]457d6952013-12-13 09:24:5891 : random_generator_(0),
[email protected]1e960032013-12-20 19:00:2092 maker_(GetParam(), 0),
[email protected]457d6952013-12-13 09:24:5893 clock_(new MockClock()),
[email protected]59c0bbd2014-03-22 04:08:1294 cert_verifier_(CertVerifier::CreateDefault()),
[email protected]6b8a3c742014-07-25 00:25:3595 channel_id_service_(new ChannelIDService(
96 new DefaultChannelIDStore(NULL),
[email protected]0cceb922014-07-01 02:00:5697 base::MessageLoopProxy::current())),
[email protected]872edd9e2013-01-16 08:51:1598 factory_(&host_resolver_, &socket_factory_,
[email protected]0c4017ca2014-06-06 03:30:4599 base::WeakPtr<HttpServerProperties>(), cert_verifier_.get(),
[email protected]080b77932014-08-04 01:22:46100 channel_id_service_.get(), &transport_security_state_,
[email protected]0c4017ca2014-06-06 03:30:45101 &crypto_client_stream_factory_, &random_generator_, clock_,
102 kDefaultMaxPacketSize, std::string(),
[email protected]488a0e252014-06-25 04:37:44103 SupportedVersions(GetParam()), true, true, true,
104 QuicTagVector()),
[email protected]bf4ea2f2014-03-10 22:57:53105 host_port_pair_(kDefaultServerHostName, kDefaultServerPort),
[email protected]9dd3ff0f2014-03-26 09:51:28106 is_https_(false),
[email protected]314b03992014-04-01 01:28:53107 privacy_mode_(PRIVACY_MODE_DISABLED) {
[email protected]11c05872013-08-20 02:04:12108 factory_.set_require_confirmation(false);
[email protected]e13201d82012-12-12 05:00:32109 }
110
[email protected]df157d9d2014-03-10 07:27:27111 scoped_ptr<QuicHttpStream> CreateIfSessionExists(
[email protected]bf4ea2f2014-03-10 22:57:53112 const HostPortPair& host_port_pair,
[email protected]df157d9d2014-03-10 07:27:27113 const BoundNetLog& net_log) {
114 return QuicStreamFactoryPeer::CreateIfSessionExists(
[email protected]bf4ea2f2014-03-10 22:57:53115 &factory_, host_port_pair, false, net_log_);
[email protected]df157d9d2014-03-10 07:27:27116 }
[email protected]e13201d82012-12-12 05:00:32117
[email protected]bf4ea2f2014-03-10 22:57:53118 int GetSourcePortForNewSession(const HostPortPair& destination) {
[email protected]d8e2abf82014-03-06 10:30:10119 return GetSourcePortForNewSessionInner(destination, false);
120 }
121
122 int GetSourcePortForNewSessionAndGoAway(
[email protected]bf4ea2f2014-03-10 22:57:53123 const HostPortPair& destination) {
[email protected]d8e2abf82014-03-06 10:30:10124 return GetSourcePortForNewSessionInner(destination, true);
125 }
126
[email protected]bf4ea2f2014-03-10 22:57:53127 int GetSourcePortForNewSessionInner(const HostPortPair& destination,
[email protected]d8e2abf82014-03-06 10:30:10128 bool goaway_received) {
[email protected]3c772402013-12-18 21:38:11129 // Should only be called if there is no active session for this destination.
[email protected]df157d9d2014-03-10 07:27:27130 EXPECT_EQ(NULL, CreateIfSessionExists(destination, net_log_).get());
[email protected]3c772402013-12-18 21:38:11131 size_t socket_count = socket_factory_.udp_client_sockets().size();
132
133 MockRead reads[] = {
134 MockRead(ASYNC, OK, 0) // EOF
135 };
136 DeterministicSocketData socket_data(reads, arraysize(reads), NULL, 0);
137 socket_data.StopAfter(1);
138 socket_factory_.AddSocketDataProvider(&socket_data);
139
140 QuicStreamRequest request(&factory_);
[email protected]974849d2014-02-06 01:32:59141 EXPECT_EQ(ERR_IO_PENDING,
142 request.Request(destination,
143 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28144 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59145 "GET",
[email protected]974849d2014-02-06 01:32:59146 net_log_,
147 callback_.callback()));
[email protected]3c772402013-12-18 21:38:11148
149 EXPECT_EQ(OK, callback_.WaitForResult());
150 scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
151 EXPECT_TRUE(stream.get());
152 stream.reset();
153
154 QuicClientSession* session = QuicStreamFactoryPeer::GetActiveSession(
[email protected]df157d9d2014-03-10 07:27:27155 &factory_, destination, is_https_);
[email protected]3c772402013-12-18 21:38:11156
157 if (socket_count + 1 != socket_factory_.udp_client_sockets().size()) {
158 EXPECT_TRUE(false);
159 return 0;
160 }
161
162 IPEndPoint endpoint;
163 socket_factory_.
164 udp_client_sockets()[socket_count]->GetLocalAddress(&endpoint);
165 int port = endpoint.port();
[email protected]d8e2abf82014-03-06 10:30:10166 if (goaway_received) {
167 QuicGoAwayFrame goaway(QUIC_NO_ERROR, 1, "");
168 session->OnGoAway(goaway);
169 }
[email protected]3c772402013-12-18 21:38:11170
171 factory_.OnSessionClosed(session);
[email protected]df157d9d2014-03-10 07:27:27172 EXPECT_EQ(NULL, CreateIfSessionExists(destination, net_log_).get());
[email protected]3c772402013-12-18 21:38:11173 EXPECT_TRUE(socket_data.at_read_eof());
174 EXPECT_TRUE(socket_data.at_write_eof());
175 return port;
176 }
177
[email protected]459a7402014-02-10 12:58:52178 scoped_ptr<QuicEncryptedPacket> ConstructRstPacket() {
[email protected]66ae5962014-05-22 11:13:05179 QuicStreamId stream_id = kClientDataStreamId1;
[email protected]51cc1342014-04-18 23:44:37180 return maker_.MakeRstPacket(
181 1, true, stream_id,
182 AdjustErrorForVersion(QUIC_RST_FLOW_CONTROL_ACCOUNTING, GetParam()));
[email protected]459a7402014-02-10 12:58:52183 }
184
[email protected]e13201d82012-12-12 05:00:32185 MockHostResolver host_resolver_;
[email protected]0edce6a2013-05-08 18:02:40186 DeterministicMockClientSocketFactory socket_factory_;
[email protected]e8ff26842013-03-22 21:02:05187 MockCryptoClientStreamFactory crypto_client_stream_factory_;
[email protected]9558c5d32012-12-22 00:08:14188 MockRandom random_generator_;
[email protected]1e960032013-12-20 19:00:20189 QuicTestPacketMaker maker_;
[email protected]872edd9e2013-01-16 08:51:15190 MockClock* clock_; // Owned by factory_.
[email protected]59c0bbd2014-03-22 04:08:12191 scoped_ptr<CertVerifier> cert_verifier_;
[email protected]6b8a3c742014-07-25 00:25:35192 scoped_ptr<ChannelIDService> channel_id_service_;
[email protected]080b77932014-08-04 01:22:46193 TransportSecurityState transport_security_state_;
[email protected]e13201d82012-12-12 05:00:32194 QuicStreamFactory factory_;
[email protected]bf4ea2f2014-03-10 22:57:53195 HostPortPair host_port_pair_;
[email protected]6d1b4ed2013-07-10 03:57:54196 bool is_https_;
[email protected]9dd3ff0f2014-03-26 09:51:28197 PrivacyMode privacy_mode_;
[email protected]e13201d82012-12-12 05:00:32198 BoundNetLog net_log_;
199 TestCompletionCallback callback_;
[email protected]e13201d82012-12-12 05:00:32200};
201
[email protected]1e960032013-12-20 19:00:20202INSTANTIATE_TEST_CASE_P(Version, QuicStreamFactoryTest,
203 ::testing::ValuesIn(QuicSupportedVersions()));
204
205TEST_P(QuicStreamFactoryTest, CreateIfSessionExists) {
[email protected]bf4ea2f2014-03-10 22:57:53206 EXPECT_EQ(NULL, CreateIfSessionExists(host_port_pair_, net_log_).get());
[email protected]e13201d82012-12-12 05:00:32207}
208
[email protected]1e960032013-12-20 19:00:20209TEST_P(QuicStreamFactoryTest, Create) {
[email protected]69dfd1b2013-06-04 22:20:12210 MockRead reads[] = {
[email protected]25c31dc2013-06-05 17:56:04211 MockRead(ASYNC, OK, 0) // EOF
[email protected]69dfd1b2013-06-04 22:20:12212 };
[email protected]25c31dc2013-06-05 17:56:04213 DeterministicSocketData socket_data(reads, arraysize(reads), NULL, 0);
[email protected]e13201d82012-12-12 05:00:32214 socket_factory_.AddSocketDataProvider(&socket_data);
[email protected]25c31dc2013-06-05 17:56:04215 socket_data.StopAfter(1);
[email protected]e13201d82012-12-12 05:00:32216
217 QuicStreamRequest request(&factory_);
[email protected]974849d2014-02-06 01:32:59218 EXPECT_EQ(ERR_IO_PENDING,
[email protected]bf4ea2f2014-03-10 22:57:53219 request.Request(host_port_pair_,
[email protected]974849d2014-02-06 01:32:59220 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28221 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59222 "GET",
[email protected]974849d2014-02-06 01:32:59223 net_log_,
224 callback_.callback()));
[email protected]e13201d82012-12-12 05:00:32225
226 EXPECT_EQ(OK, callback_.WaitForResult());
227 scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
[email protected]0edce6a2013-05-08 18:02:40228 EXPECT_TRUE(stream.get());
[email protected]e13201d82012-12-12 05:00:32229
230 // Will reset stream 3.
[email protected]bf4ea2f2014-03-10 22:57:53231 stream = CreateIfSessionExists(host_port_pair_, net_log_);
[email protected]e13201d82012-12-12 05:00:32232 EXPECT_TRUE(stream.get());
233
[email protected]6d1b4ed2013-07-10 03:57:54234 // TODO(rtenneti): We should probably have a tests that HTTP and HTTPS result
235 // in streams on different sessions.
[email protected]e13201d82012-12-12 05:00:32236 QuicStreamRequest request2(&factory_);
[email protected]974849d2014-02-06 01:32:59237 EXPECT_EQ(OK,
[email protected]bf4ea2f2014-03-10 22:57:53238 request2.Request(host_port_pair_,
[email protected]974849d2014-02-06 01:32:59239 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28240 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59241 "GET",
[email protected]974849d2014-02-06 01:32:59242 net_log_,
243 callback_.callback()));
[email protected]e13201d82012-12-12 05:00:32244 stream = request2.ReleaseStream(); // Will reset stream 5.
245 stream.reset(); // Will reset stream 7.
246
247 EXPECT_TRUE(socket_data.at_read_eof());
248 EXPECT_TRUE(socket_data.at_write_eof());
249}
250
[email protected]8bd2b812014-03-26 04:01:17251TEST_P(QuicStreamFactoryTest, CreateZeroRtt) {
252 MockRead reads[] = {
253 MockRead(ASYNC, OK, 0) // EOF
254 };
255 DeterministicSocketData socket_data(reads, arraysize(reads), NULL, 0);
256 socket_factory_.AddSocketDataProvider(&socket_data);
257 socket_data.StopAfter(1);
258
259 crypto_client_stream_factory_.set_handshake_mode(
260 MockCryptoClientStream::ZERO_RTT);
261 host_resolver_.set_synchronous_mode(true);
262 host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
263 "192.168.0.1", "");
264
265 QuicStreamRequest request(&factory_);
266 EXPECT_EQ(OK,
267 request.Request(host_port_pair_,
268 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28269 privacy_mode_,
[email protected]8bd2b812014-03-26 04:01:17270 "GET",
271 net_log_,
272 callback_.callback()));
273
274 scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
275 EXPECT_TRUE(stream.get());
276 EXPECT_TRUE(socket_data.at_read_eof());
277 EXPECT_TRUE(socket_data.at_write_eof());
278}
279
280TEST_P(QuicStreamFactoryTest, CreateZeroRttPost) {
281 MockRead reads[] = {
282 MockRead(ASYNC, OK, 0) // EOF
283 };
284 DeterministicSocketData socket_data(reads, arraysize(reads), NULL, 0);
285 socket_factory_.AddSocketDataProvider(&socket_data);
286 socket_data.StopAfter(1);
287
288 crypto_client_stream_factory_.set_handshake_mode(
289 MockCryptoClientStream::ZERO_RTT);
290 host_resolver_.set_synchronous_mode(true);
291 host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
292 "192.168.0.1", "");
293
294 QuicStreamRequest request(&factory_);
295 // Posts require handshake confirmation, so this will return asynchronously.
296 EXPECT_EQ(ERR_IO_PENDING,
297 request.Request(host_port_pair_,
298 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28299 privacy_mode_,
[email protected]8bd2b812014-03-26 04:01:17300 "POST",
301 net_log_,
302 callback_.callback()));
303
304 // Confirm the handshake and verify that the stream is created.
305 crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
306 QuicSession::HANDSHAKE_CONFIRMED);
307
308 EXPECT_EQ(OK, callback_.WaitForResult());
309 scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
310 EXPECT_TRUE(stream.get());
311 EXPECT_TRUE(socket_data.at_read_eof());
312 EXPECT_TRUE(socket_data.at_write_eof());
313}
314
[email protected]df157d9d2014-03-10 07:27:27315TEST_P(QuicStreamFactoryTest, CreateHttpVsHttps) {
316 MockRead reads[] = {
317 MockRead(ASYNC, OK, 0) // EOF
318 };
319 DeterministicSocketData socket_data1(reads, arraysize(reads), NULL, 0);
320 DeterministicSocketData socket_data2(reads, arraysize(reads), NULL, 0);
321 socket_factory_.AddSocketDataProvider(&socket_data1);
322 socket_factory_.AddSocketDataProvider(&socket_data2);
323 socket_data1.StopAfter(1);
324 socket_data2.StopAfter(1);
325
326 QuicStreamRequest request(&factory_);
327 EXPECT_EQ(ERR_IO_PENDING,
[email protected]bf4ea2f2014-03-10 22:57:53328 request.Request(host_port_pair_,
[email protected]df157d9d2014-03-10 07:27:27329 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28330 privacy_mode_,
[email protected]df157d9d2014-03-10 07:27:27331 "GET",
[email protected]df157d9d2014-03-10 07:27:27332 net_log_,
333 callback_.callback()));
334
335 EXPECT_EQ(OK, callback_.WaitForResult());
336 scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
337 EXPECT_TRUE(stream.get());
338
339 QuicStreamRequest request2(&factory_);
340 EXPECT_EQ(ERR_IO_PENDING,
[email protected]bf4ea2f2014-03-10 22:57:53341 request2.Request(host_port_pair_,
[email protected]df157d9d2014-03-10 07:27:27342 !is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28343 privacy_mode_,
[email protected]df157d9d2014-03-10 07:27:27344 "GET",
[email protected]df157d9d2014-03-10 07:27:27345 net_log_,
346 callback_.callback()));
347 EXPECT_EQ(OK, callback_.WaitForResult());
348 stream = request2.ReleaseStream();
349 EXPECT_TRUE(stream.get());
350 stream.reset();
351
352 EXPECT_NE(QuicStreamFactoryPeer::GetActiveSession(
[email protected]bf4ea2f2014-03-10 22:57:53353 &factory_, host_port_pair_, is_https_),
[email protected]df157d9d2014-03-10 07:27:27354 QuicStreamFactoryPeer::GetActiveSession(
[email protected]bf4ea2f2014-03-10 22:57:53355 &factory_, host_port_pair_, !is_https_));
[email protected]df157d9d2014-03-10 07:27:27356
357 EXPECT_TRUE(socket_data1.at_read_eof());
358 EXPECT_TRUE(socket_data1.at_write_eof());
359 EXPECT_TRUE(socket_data2.at_read_eof());
360 EXPECT_TRUE(socket_data2.at_write_eof());
361}
362
[email protected]d7a70762014-07-30 21:25:27363// TODO(rch): re-enable this.
364TEST_P(QuicStreamFactoryTest, DISABLED_Pooling) {
[email protected]eed749f92013-12-23 18:57:38365 MockRead reads[] = {
366 MockRead(ASYNC, OK, 0) // EOF
367 };
368 DeterministicSocketData socket_data(reads, arraysize(reads), NULL, 0);
369 socket_factory_.AddSocketDataProvider(&socket_data);
370 socket_data.StopAfter(1);
371
[email protected]bf4ea2f2014-03-10 22:57:53372 HostPortPair server2("mail.google.com", kDefaultServerPort);
[email protected]eed749f92013-12-23 18:57:38373 host_resolver_.set_synchronous_mode(true);
374 host_resolver_.rules()->AddIPLiteralRule(
375 kDefaultServerHostName, "192.168.0.1", "");
376 host_resolver_.rules()->AddIPLiteralRule(
377 "mail.google.com", "192.168.0.1", "");
378
379 QuicStreamRequest request(&factory_);
[email protected]974849d2014-02-06 01:32:59380 EXPECT_EQ(OK,
[email protected]bf4ea2f2014-03-10 22:57:53381 request.Request(host_port_pair_,
[email protected]974849d2014-02-06 01:32:59382 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28383 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59384 "GET",
[email protected]974849d2014-02-06 01:32:59385 net_log_,
386 callback_.callback()));
[email protected]eed749f92013-12-23 18:57:38387 scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
388 EXPECT_TRUE(stream.get());
389
390 TestCompletionCallback callback;
391 QuicStreamRequest request2(&factory_);
[email protected]974849d2014-02-06 01:32:59392 EXPECT_EQ(OK,
393 request2.Request(server2,
394 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28395 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59396 "GET",
[email protected]974849d2014-02-06 01:32:59397 net_log_,
398 callback.callback()));
[email protected]eed749f92013-12-23 18:57:38399 scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
400 EXPECT_TRUE(stream2.get());
401
402 EXPECT_EQ(
[email protected]df157d9d2014-03-10 07:27:27403 QuicStreamFactoryPeer::GetActiveSession(
[email protected]bf4ea2f2014-03-10 22:57:53404 &factory_, host_port_pair_, is_https_),
[email protected]df157d9d2014-03-10 07:27:27405 QuicStreamFactoryPeer::GetActiveSession(&factory_, server2, is_https_));
[email protected]eed749f92013-12-23 18:57:38406
407 EXPECT_TRUE(socket_data.at_read_eof());
408 EXPECT_TRUE(socket_data.at_write_eof());
409}
410
411TEST_P(QuicStreamFactoryTest, NoPoolingAfterGoAway) {
412 MockRead reads[] = {
413 MockRead(ASYNC, OK, 0) // EOF
414 };
415 DeterministicSocketData socket_data1(reads, arraysize(reads), NULL, 0);
416 DeterministicSocketData socket_data2(reads, arraysize(reads), NULL, 0);
417 socket_factory_.AddSocketDataProvider(&socket_data1);
418 socket_factory_.AddSocketDataProvider(&socket_data2);
419 socket_data1.StopAfter(1);
420 socket_data2.StopAfter(1);
421
[email protected]bf4ea2f2014-03-10 22:57:53422 HostPortPair server2("mail.google.com", kDefaultServerPort);
[email protected]eed749f92013-12-23 18:57:38423 host_resolver_.set_synchronous_mode(true);
424 host_resolver_.rules()->AddIPLiteralRule(
425 kDefaultServerHostName, "192.168.0.1", "");
426 host_resolver_.rules()->AddIPLiteralRule(
427 "mail.google.com", "192.168.0.1", "");
428
429 QuicStreamRequest request(&factory_);
[email protected]974849d2014-02-06 01:32:59430 EXPECT_EQ(OK,
[email protected]bf4ea2f2014-03-10 22:57:53431 request.Request(host_port_pair_,
[email protected]974849d2014-02-06 01:32:59432 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28433 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59434 "GET",
[email protected]974849d2014-02-06 01:32:59435 net_log_,
436 callback_.callback()));
[email protected]eed749f92013-12-23 18:57:38437 scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
438 EXPECT_TRUE(stream.get());
439
440 TestCompletionCallback callback;
441 QuicStreamRequest request2(&factory_);
[email protected]974849d2014-02-06 01:32:59442 EXPECT_EQ(OK,
443 request2.Request(server2,
444 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28445 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59446 "GET",
[email protected]974849d2014-02-06 01:32:59447 net_log_,
448 callback.callback()));
[email protected]eed749f92013-12-23 18:57:38449 scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
450 EXPECT_TRUE(stream2.get());
451
[email protected]df157d9d2014-03-10 07:27:27452 factory_.OnSessionGoingAway(QuicStreamFactoryPeer::GetActiveSession(
[email protected]bf4ea2f2014-03-10 22:57:53453 &factory_, host_port_pair_, is_https_));
[email protected]df157d9d2014-03-10 07:27:27454 EXPECT_FALSE(QuicStreamFactoryPeer::HasActiveSession(
[email protected]bf4ea2f2014-03-10 22:57:53455 &factory_, host_port_pair_, is_https_));
[email protected]df157d9d2014-03-10 07:27:27456 EXPECT_FALSE(QuicStreamFactoryPeer::HasActiveSession(
457 &factory_, server2, is_https_));
[email protected]eed749f92013-12-23 18:57:38458
459 TestCompletionCallback callback3;
460 QuicStreamRequest request3(&factory_);
[email protected]974849d2014-02-06 01:32:59461 EXPECT_EQ(OK,
462 request3.Request(server2,
463 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28464 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59465 "GET",
[email protected]974849d2014-02-06 01:32:59466 net_log_,
467 callback3.callback()));
[email protected]eed749f92013-12-23 18:57:38468 scoped_ptr<QuicHttpStream> stream3 = request3.ReleaseStream();
469 EXPECT_TRUE(stream3.get());
470
[email protected]df157d9d2014-03-10 07:27:27471 EXPECT_TRUE(QuicStreamFactoryPeer::HasActiveSession(
472 &factory_, server2, is_https_));
[email protected]eed749f92013-12-23 18:57:38473
474 EXPECT_TRUE(socket_data1.at_read_eof());
475 EXPECT_TRUE(socket_data1.at_write_eof());
476 EXPECT_TRUE(socket_data2.at_read_eof());
477 EXPECT_TRUE(socket_data2.at_write_eof());
478}
479
[email protected]d7a70762014-07-30 21:25:27480// TODO(rch): re-enable this.
481TEST_P(QuicStreamFactoryTest, DISABLED_HttpsPooling) {
[email protected]eed749f92013-12-23 18:57:38482 MockRead reads[] = {
483 MockRead(ASYNC, OK, 0) // EOF
484 };
485 DeterministicSocketData socket_data(reads, arraysize(reads), NULL, 0);
486 socket_factory_.AddSocketDataProvider(&socket_data);
487 socket_data.StopAfter(1);
488
[email protected]bf4ea2f2014-03-10 22:57:53489 HostPortPair server1("www.example.org", 443);
490 HostPortPair server2("mail.example.org", 443);
[email protected]eed749f92013-12-23 18:57:38491
492 // Load a cert that is valid for:
493 // www.example.org (server1)
494 // mail.example.org (server2)
495 // www.example.com
496 base::FilePath certs_dir = GetTestCertsDirectory();
497 scoped_refptr<X509Certificate> test_cert(
498 ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
499 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert);
[email protected]b694e48c2014-03-18 17:10:13500 ProofVerifyDetailsChromium verify_details;
501 verify_details.cert_verify_result.verified_cert = test_cert;
502 crypto_client_stream_factory_.set_proof_verify_details(&verify_details);
[email protected]eed749f92013-12-23 18:57:38503
504 host_resolver_.set_synchronous_mode(true);
[email protected]bf4ea2f2014-03-10 22:57:53505 host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
506 host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
[email protected]eed749f92013-12-23 18:57:38507
508 QuicStreamRequest request(&factory_);
509 is_https_ = true;
[email protected]974849d2014-02-06 01:32:59510 EXPECT_EQ(OK,
511 request.Request(server1,
512 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28513 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59514 "GET",
[email protected]974849d2014-02-06 01:32:59515 net_log_,
516 callback_.callback()));
[email protected]eed749f92013-12-23 18:57:38517 scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
518 EXPECT_TRUE(stream.get());
519
520 TestCompletionCallback callback;
521 QuicStreamRequest request2(&factory_);
[email protected]974849d2014-02-06 01:32:59522 EXPECT_EQ(OK,
523 request2.Request(server2,
524 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28525 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59526 "GET",
[email protected]974849d2014-02-06 01:32:59527 net_log_,
528 callback_.callback()));
[email protected]eed749f92013-12-23 18:57:38529 scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
530 EXPECT_TRUE(stream2.get());
531
[email protected]df157d9d2014-03-10 07:27:27532 EXPECT_EQ(QuicStreamFactoryPeer::GetActiveSession(
533 &factory_, server1, is_https_),
534 QuicStreamFactoryPeer::GetActiveSession(
535 &factory_, server2, is_https_));
[email protected]eed749f92013-12-23 18:57:38536
537 EXPECT_TRUE(socket_data.at_read_eof());
538 EXPECT_TRUE(socket_data.at_write_eof());
539}
540
541TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithCertMismatch) {
542 MockRead reads[] = {
543 MockRead(ASYNC, OK, 0) // EOF
544 };
545 DeterministicSocketData socket_data1(reads, arraysize(reads), NULL, 0);
546 DeterministicSocketData socket_data2(reads, arraysize(reads), NULL, 0);
547 socket_factory_.AddSocketDataProvider(&socket_data1);
548 socket_factory_.AddSocketDataProvider(&socket_data2);
549 socket_data1.StopAfter(1);
550 socket_data2.StopAfter(1);
551
[email protected]bf4ea2f2014-03-10 22:57:53552 HostPortPair server1("www.example.org", 443);
553 HostPortPair server2("mail.google.com", 443);
[email protected]eed749f92013-12-23 18:57:38554
555 // Load a cert that is valid for:
556 // www.example.org (server1)
557 // mail.example.org
558 // www.example.com
559 // But is not valid for mail.google.com (server2).
560 base::FilePath certs_dir = GetTestCertsDirectory();
561 scoped_refptr<X509Certificate> test_cert(
562 ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
563 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert);
[email protected]b694e48c2014-03-18 17:10:13564 ProofVerifyDetailsChromium verify_details;
565 verify_details.cert_verify_result.verified_cert = test_cert;
566 crypto_client_stream_factory_.set_proof_verify_details(&verify_details);
567
[email protected]eed749f92013-12-23 18:57:38568
569 host_resolver_.set_synchronous_mode(true);
[email protected]bf4ea2f2014-03-10 22:57:53570 host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
571 host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
[email protected]eed749f92013-12-23 18:57:38572
573 QuicStreamRequest request(&factory_);
574 is_https_ = true;
[email protected]974849d2014-02-06 01:32:59575 EXPECT_EQ(OK,
576 request.Request(server1,
577 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28578 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59579 "GET",
[email protected]974849d2014-02-06 01:32:59580 net_log_,
581 callback_.callback()));
[email protected]eed749f92013-12-23 18:57:38582 scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
583 EXPECT_TRUE(stream.get());
584
585 TestCompletionCallback callback;
586 QuicStreamRequest request2(&factory_);
[email protected]974849d2014-02-06 01:32:59587 EXPECT_EQ(OK,
588 request2.Request(server2,
589 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28590 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59591 "GET",
[email protected]974849d2014-02-06 01:32:59592 net_log_,
593 callback_.callback()));
[email protected]eed749f92013-12-23 18:57:38594 scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
595 EXPECT_TRUE(stream2.get());
596
[email protected]df157d9d2014-03-10 07:27:27597 EXPECT_NE(QuicStreamFactoryPeer::GetActiveSession(
598 &factory_, server1, is_https_),
599 QuicStreamFactoryPeer::GetActiveSession(
600 &factory_, server2, is_https_));
[email protected]eed749f92013-12-23 18:57:38601
602 EXPECT_TRUE(socket_data1.at_read_eof());
603 EXPECT_TRUE(socket_data1.at_write_eof());
604 EXPECT_TRUE(socket_data2.at_read_eof());
605 EXPECT_TRUE(socket_data2.at_write_eof());
606}
607
[email protected]1e960032013-12-20 19:00:20608TEST_P(QuicStreamFactoryTest, Goaway) {
[email protected]4d283b32013-10-17 12:57:27609 MockRead reads[] = {
610 MockRead(ASYNC, OK, 0) // EOF
611 };
612 DeterministicSocketData socket_data(reads, arraysize(reads), NULL, 0);
613 socket_data.StopAfter(1);
614 socket_factory_.AddSocketDataProvider(&socket_data);
615 DeterministicSocketData socket_data2(reads, arraysize(reads), NULL, 0);
616 socket_data2.StopAfter(1);
617 socket_factory_.AddSocketDataProvider(&socket_data2);
618
619 QuicStreamRequest request(&factory_);
[email protected]974849d2014-02-06 01:32:59620 EXPECT_EQ(ERR_IO_PENDING,
[email protected]bf4ea2f2014-03-10 22:57:53621 request.Request(host_port_pair_,
[email protected]974849d2014-02-06 01:32:59622 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28623 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59624 "GET",
[email protected]974849d2014-02-06 01:32:59625 net_log_,
626 callback_.callback()));
[email protected]4d283b32013-10-17 12:57:27627
628 EXPECT_EQ(OK, callback_.WaitForResult());
629 scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
630 EXPECT_TRUE(stream.get());
631
632 // Mark the session as going away. Ensure that while it is still alive
633 // that it is no longer active.
634 QuicClientSession* session = QuicStreamFactoryPeer::GetActiveSession(
[email protected]bf4ea2f2014-03-10 22:57:53635 &factory_, host_port_pair_, is_https_);
[email protected]4d283b32013-10-17 12:57:27636 factory_.OnSessionGoingAway(session);
637 EXPECT_EQ(true, QuicStreamFactoryPeer::IsLiveSession(&factory_, session));
[email protected]df157d9d2014-03-10 07:27:27638 EXPECT_FALSE(QuicStreamFactoryPeer::HasActiveSession(
[email protected]bf4ea2f2014-03-10 22:57:53639 &factory_, host_port_pair_, is_https_));
640 EXPECT_EQ(NULL, CreateIfSessionExists(host_port_pair_, net_log_).get());
[email protected]4d283b32013-10-17 12:57:27641
642 // Create a new request for the same destination and verify that a
643 // new session is created.
644 QuicStreamRequest request2(&factory_);
[email protected]974849d2014-02-06 01:32:59645 EXPECT_EQ(ERR_IO_PENDING,
[email protected]bf4ea2f2014-03-10 22:57:53646 request2.Request(host_port_pair_,
[email protected]974849d2014-02-06 01:32:59647 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28648 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59649 "GET",
[email protected]974849d2014-02-06 01:32:59650 net_log_,
651 callback_.callback()));
[email protected]4d283b32013-10-17 12:57:27652 EXPECT_EQ(OK, callback_.WaitForResult());
653 scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
654 EXPECT_TRUE(stream2.get());
655
656 EXPECT_TRUE(QuicStreamFactoryPeer::HasActiveSession(&factory_,
[email protected]bf4ea2f2014-03-10 22:57:53657 host_port_pair_,
[email protected]df157d9d2014-03-10 07:27:27658 is_https_));
[email protected]4d283b32013-10-17 12:57:27659 EXPECT_NE(session,
660 QuicStreamFactoryPeer::GetActiveSession(
[email protected]bf4ea2f2014-03-10 22:57:53661 &factory_, host_port_pair_, is_https_));
[email protected]4d283b32013-10-17 12:57:27662 EXPECT_EQ(true, QuicStreamFactoryPeer::IsLiveSession(&factory_, session));
663
664 stream2.reset();
665 stream.reset();
666
667 EXPECT_TRUE(socket_data.at_read_eof());
668 EXPECT_TRUE(socket_data.at_write_eof());
[email protected]3c772402013-12-18 21:38:11669 EXPECT_TRUE(socket_data2.at_read_eof());
670 EXPECT_TRUE(socket_data2.at_write_eof());
[email protected]4d283b32013-10-17 12:57:27671}
672
[email protected]1e960032013-12-20 19:00:20673TEST_P(QuicStreamFactoryTest, MaxOpenStream) {
[email protected]0b2294d32013-08-02 00:46:36674 MockRead reads[] = {
675 MockRead(ASYNC, OK, 0) // EOF
676 };
[email protected]66ae5962014-05-22 11:13:05677 QuicStreamId stream_id = kClientDataStreamId1;
[email protected]1e960032013-12-20 19:00:20678 scoped_ptr<QuicEncryptedPacket> rst(
679 maker_.MakeRstPacket(1, true, stream_id, QUIC_STREAM_CANCELLED));
[email protected]06ff5152013-08-29 01:03:05680 MockWrite writes[] = {
681 MockWrite(ASYNC, rst->data(), rst->length(), 1),
682 };
683 DeterministicSocketData socket_data(reads, arraysize(reads),
684 writes, arraysize(writes));
[email protected]0b2294d32013-08-02 00:46:36685 socket_factory_.AddSocketDataProvider(&socket_data);
686 socket_data.StopAfter(1);
687
688 HttpRequestInfo request_info;
689 std::vector<QuicHttpStream*> streams;
690 // The MockCryptoClientStream sets max_open_streams to be
691 // 2 * kDefaultMaxStreamsPerConnection.
692 for (size_t i = 0; i < 2 * kDefaultMaxStreamsPerConnection; i++) {
693 QuicStreamRequest request(&factory_);
[email protected]bf4ea2f2014-03-10 22:57:53694 int rv = request.Request(host_port_pair_,
[email protected]974849d2014-02-06 01:32:59695 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28696 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59697 "GET",
[email protected]974849d2014-02-06 01:32:59698 net_log_,
[email protected]0b2294d32013-08-02 00:46:36699 callback_.callback());
700 if (i == 0) {
701 EXPECT_EQ(ERR_IO_PENDING, rv);
702 EXPECT_EQ(OK, callback_.WaitForResult());
703 } else {
704 EXPECT_EQ(OK, rv);
705 }
706 scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
707 EXPECT_TRUE(stream);
708 EXPECT_EQ(OK, stream->InitializeStream(
709 &request_info, DEFAULT_PRIORITY, net_log_, CompletionCallback()));
710 streams.push_back(stream.release());
711 }
712
713 QuicStreamRequest request(&factory_);
[email protected]974849d2014-02-06 01:32:59714 EXPECT_EQ(OK,
[email protected]bf4ea2f2014-03-10 22:57:53715 request.Request(host_port_pair_,
[email protected]974849d2014-02-06 01:32:59716 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28717 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59718 "GET",
[email protected]974849d2014-02-06 01:32:59719 net_log_,
720 CompletionCallback()));
[email protected]0b2294d32013-08-02 00:46:36721 scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
722 EXPECT_TRUE(stream);
723 EXPECT_EQ(ERR_IO_PENDING, stream->InitializeStream(
724 &request_info, DEFAULT_PRIORITY, net_log_, callback_.callback()));
725
726 // Close the first stream.
727 streams.front()->Close(false);
728
729 ASSERT_TRUE(callback_.have_result());
730
731 EXPECT_EQ(OK, callback_.WaitForResult());
732
733 EXPECT_TRUE(socket_data.at_read_eof());
734 EXPECT_TRUE(socket_data.at_write_eof());
735 STLDeleteElements(&streams);
736}
737
[email protected]1e960032013-12-20 19:00:20738TEST_P(QuicStreamFactoryTest, ResolutionErrorInCreate) {
[email protected]0edce6a2013-05-08 18:02:40739 DeterministicSocketData socket_data(NULL, 0, NULL, 0);
[email protected]e13201d82012-12-12 05:00:32740 socket_factory_.AddSocketDataProvider(&socket_data);
741
[email protected]3c772402013-12-18 21:38:11742 host_resolver_.rules()->AddSimulatedFailure(kDefaultServerHostName);
[email protected]e13201d82012-12-12 05:00:32743
744 QuicStreamRequest request(&factory_);
[email protected]974849d2014-02-06 01:32:59745 EXPECT_EQ(ERR_IO_PENDING,
[email protected]bf4ea2f2014-03-10 22:57:53746 request.Request(host_port_pair_,
[email protected]974849d2014-02-06 01:32:59747 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28748 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59749 "GET",
[email protected]974849d2014-02-06 01:32:59750 net_log_,
751 callback_.callback()));
[email protected]e13201d82012-12-12 05:00:32752
753 EXPECT_EQ(ERR_NAME_NOT_RESOLVED, callback_.WaitForResult());
754
755 EXPECT_TRUE(socket_data.at_read_eof());
756 EXPECT_TRUE(socket_data.at_write_eof());
757}
758
[email protected]1e960032013-12-20 19:00:20759TEST_P(QuicStreamFactoryTest, ConnectErrorInCreate) {
[email protected]3c772402013-12-18 21:38:11760 MockConnect connect(SYNCHRONOUS, ERR_ADDRESS_IN_USE);
761 DeterministicSocketData socket_data(NULL, 0, NULL, 0);
762 socket_data.set_connect_data(connect);
763 socket_factory_.AddSocketDataProvider(&socket_data);
764 socket_data.StopAfter(1);
765
766 QuicStreamRequest request(&factory_);
[email protected]974849d2014-02-06 01:32:59767 EXPECT_EQ(ERR_IO_PENDING,
[email protected]bf4ea2f2014-03-10 22:57:53768 request.Request(host_port_pair_,
[email protected]974849d2014-02-06 01:32:59769 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28770 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59771 "GET",
[email protected]974849d2014-02-06 01:32:59772 net_log_,
773 callback_.callback()));
[email protected]3c772402013-12-18 21:38:11774
775 EXPECT_EQ(ERR_ADDRESS_IN_USE, callback_.WaitForResult());
776
777 EXPECT_TRUE(socket_data.at_read_eof());
778 EXPECT_TRUE(socket_data.at_write_eof());
779}
780
[email protected]1e960032013-12-20 19:00:20781TEST_P(QuicStreamFactoryTest, CancelCreate) {
[email protected]69dfd1b2013-06-04 22:20:12782 MockRead reads[] = {
[email protected]25c31dc2013-06-05 17:56:04783 MockRead(ASYNC, OK, 0) // EOF
[email protected]69dfd1b2013-06-04 22:20:12784 };
[email protected]25c31dc2013-06-05 17:56:04785 DeterministicSocketData socket_data(reads, arraysize(reads), NULL, 0);
[email protected]e13201d82012-12-12 05:00:32786 socket_factory_.AddSocketDataProvider(&socket_data);
787 {
788 QuicStreamRequest request(&factory_);
[email protected]974849d2014-02-06 01:32:59789 EXPECT_EQ(ERR_IO_PENDING,
[email protected]bf4ea2f2014-03-10 22:57:53790 request.Request(host_port_pair_,
[email protected]974849d2014-02-06 01:32:59791 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28792 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59793 "GET",
[email protected]974849d2014-02-06 01:32:59794 net_log_,
795 callback_.callback()));
[email protected]e13201d82012-12-12 05:00:32796 }
797
[email protected]25c31dc2013-06-05 17:56:04798 socket_data.StopAfter(1);
[email protected]e13201d82012-12-12 05:00:32799 base::RunLoop run_loop;
800 run_loop.RunUntilIdle();
801
802 scoped_ptr<QuicHttpStream> stream(
[email protected]bf4ea2f2014-03-10 22:57:53803 CreateIfSessionExists(host_port_pair_, net_log_));
[email protected]e13201d82012-12-12 05:00:32804 EXPECT_TRUE(stream.get());
805 stream.reset();
806
807 EXPECT_TRUE(socket_data.at_read_eof());
808 EXPECT_TRUE(socket_data.at_write_eof());
809}
810
[email protected]1e960032013-12-20 19:00:20811TEST_P(QuicStreamFactoryTest, CreateConsistentEphemeralPort) {
[email protected]3c772402013-12-18 21:38:11812 // Sequentially connect to the default host, then another host, and then the
813 // default host. Verify that the default host gets a consistent ephemeral
814 // port, that is different from the other host's connection.
815
816 std::string other_server_name = "other.google.com";
817 EXPECT_NE(kDefaultServerHostName, other_server_name);
818 HostPortPair host_port_pair2(other_server_name, kDefaultServerPort);
[email protected]3c772402013-12-18 21:38:11819
[email protected]bf4ea2f2014-03-10 22:57:53820 int original_port = GetSourcePortForNewSession(host_port_pair_);
821 EXPECT_NE(original_port, GetSourcePortForNewSession(host_port_pair2));
822 EXPECT_EQ(original_port, GetSourcePortForNewSession(host_port_pair_));
[email protected]3c772402013-12-18 21:38:11823}
824
[email protected]d8e2abf82014-03-06 10:30:10825TEST_P(QuicStreamFactoryTest, GoAwayDisablesConsistentEphemeralPort) {
826 // Get a session to the host using the port suggester.
827 int original_port =
[email protected]bf4ea2f2014-03-10 22:57:53828 GetSourcePortForNewSessionAndGoAway(host_port_pair_);
[email protected]d8e2abf82014-03-06 10:30:10829 // Verify that the port is different after the goaway.
[email protected]bf4ea2f2014-03-10 22:57:53830 EXPECT_NE(original_port, GetSourcePortForNewSession(host_port_pair_));
[email protected]d8e2abf82014-03-06 10:30:10831 // Since the previous session did not goaway we should see the original port.
[email protected]bf4ea2f2014-03-10 22:57:53832 EXPECT_EQ(original_port, GetSourcePortForNewSession(host_port_pair_));
[email protected]d8e2abf82014-03-06 10:30:10833}
834
[email protected]1e960032013-12-20 19:00:20835TEST_P(QuicStreamFactoryTest, CloseAllSessions) {
[email protected]56dfb902013-01-03 23:17:55836 MockRead reads[] = {
[email protected]0edce6a2013-05-08 18:02:40837 MockRead(ASYNC, 0, 0) // EOF
[email protected]56dfb902013-01-03 23:17:55838 };
[email protected]459a7402014-02-10 12:58:52839 scoped_ptr<QuicEncryptedPacket> rst(ConstructRstPacket());
840 std::vector<MockWrite> writes;
[email protected]08da9adb2014-04-24 08:33:31841 writes.push_back(MockWrite(ASYNC, rst->data(), rst->length(), 1));
[email protected]459a7402014-02-10 12:58:52842 DeterministicSocketData socket_data(reads, arraysize(reads),
843 writes.empty() ? NULL : &writes[0],
844 writes.size());
[email protected]56dfb902013-01-03 23:17:55845 socket_factory_.AddSocketDataProvider(&socket_data);
[email protected]0edce6a2013-05-08 18:02:40846 socket_data.StopAfter(1);
[email protected]56dfb902013-01-03 23:17:55847
[email protected]69dfd1b2013-06-04 22:20:12848 MockRead reads2[] = {
[email protected]25c31dc2013-06-05 17:56:04849 MockRead(ASYNC, 0, 0) // EOF
[email protected]69dfd1b2013-06-04 22:20:12850 };
[email protected]25c31dc2013-06-05 17:56:04851 DeterministicSocketData socket_data2(reads2, arraysize(reads2), NULL, 0);
[email protected]56dfb902013-01-03 23:17:55852 socket_factory_.AddSocketDataProvider(&socket_data2);
[email protected]0edce6a2013-05-08 18:02:40853 socket_data2.StopAfter(1);
[email protected]56dfb902013-01-03 23:17:55854
855 QuicStreamRequest request(&factory_);
[email protected]974849d2014-02-06 01:32:59856 EXPECT_EQ(ERR_IO_PENDING,
[email protected]bf4ea2f2014-03-10 22:57:53857 request.Request(host_port_pair_,
[email protected]974849d2014-02-06 01:32:59858 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28859 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59860 "GET",
[email protected]974849d2014-02-06 01:32:59861 net_log_,
862 callback_.callback()));
[email protected]56dfb902013-01-03 23:17:55863
864 EXPECT_EQ(OK, callback_.WaitForResult());
865 scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
[email protected]0b2294d32013-08-02 00:46:36866 HttpRequestInfo request_info;
867 EXPECT_EQ(OK, stream->InitializeStream(&request_info,
868 DEFAULT_PRIORITY,
869 net_log_, CompletionCallback()));
[email protected]56dfb902013-01-03 23:17:55870
871 // Close the session and verify that stream saw the error.
872 factory_.CloseAllSessions(ERR_INTERNET_DISCONNECTED);
873 EXPECT_EQ(ERR_INTERNET_DISCONNECTED,
874 stream->ReadResponseHeaders(callback_.callback()));
875
876 // Now attempting to request a stream to the same origin should create
877 // a new session.
878
879 QuicStreamRequest request2(&factory_);
[email protected]974849d2014-02-06 01:32:59880 EXPECT_EQ(ERR_IO_PENDING,
[email protected]bf4ea2f2014-03-10 22:57:53881 request2.Request(host_port_pair_,
[email protected]974849d2014-02-06 01:32:59882 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28883 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59884 "GET",
[email protected]974849d2014-02-06 01:32:59885 net_log_,
886 callback_.callback()));
[email protected]56dfb902013-01-03 23:17:55887
888 EXPECT_EQ(OK, callback_.WaitForResult());
889 stream = request2.ReleaseStream();
890 stream.reset(); // Will reset stream 3.
891
892 EXPECT_TRUE(socket_data.at_read_eof());
893 EXPECT_TRUE(socket_data.at_write_eof());
894 EXPECT_TRUE(socket_data2.at_read_eof());
895 EXPECT_TRUE(socket_data2.at_write_eof());
896}
897
[email protected]1e960032013-12-20 19:00:20898TEST_P(QuicStreamFactoryTest, OnIPAddressChanged) {
[email protected]f698a012013-05-06 20:18:59899 MockRead reads[] = {
[email protected]0edce6a2013-05-08 18:02:40900 MockRead(ASYNC, 0, 0) // EOF
[email protected]f698a012013-05-06 20:18:59901 };
[email protected]459a7402014-02-10 12:58:52902 scoped_ptr<QuicEncryptedPacket> rst(ConstructRstPacket());
903 std::vector<MockWrite> writes;
[email protected]08da9adb2014-04-24 08:33:31904 writes.push_back(MockWrite(ASYNC, rst->data(), rst->length(), 1));
[email protected]459a7402014-02-10 12:58:52905 DeterministicSocketData socket_data(reads, arraysize(reads),
906 writes.empty() ? NULL : &writes[0],
907 writes.size());
[email protected]f698a012013-05-06 20:18:59908 socket_factory_.AddSocketDataProvider(&socket_data);
[email protected]0edce6a2013-05-08 18:02:40909 socket_data.StopAfter(1);
[email protected]f698a012013-05-06 20:18:59910
[email protected]69dfd1b2013-06-04 22:20:12911 MockRead reads2[] = {
[email protected]25c31dc2013-06-05 17:56:04912 MockRead(ASYNC, 0, 0) // EOF
[email protected]69dfd1b2013-06-04 22:20:12913 };
[email protected]25c31dc2013-06-05 17:56:04914 DeterministicSocketData socket_data2(reads2, arraysize(reads2), NULL, 0);
[email protected]f698a012013-05-06 20:18:59915 socket_factory_.AddSocketDataProvider(&socket_data2);
[email protected]0edce6a2013-05-08 18:02:40916 socket_data2.StopAfter(1);
[email protected]f698a012013-05-06 20:18:59917
918 QuicStreamRequest request(&factory_);
[email protected]974849d2014-02-06 01:32:59919 EXPECT_EQ(ERR_IO_PENDING,
[email protected]bf4ea2f2014-03-10 22:57:53920 request.Request(host_port_pair_,
[email protected]974849d2014-02-06 01:32:59921 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28922 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59923 "GET",
[email protected]974849d2014-02-06 01:32:59924 net_log_,
925 callback_.callback()));
[email protected]f698a012013-05-06 20:18:59926
927 EXPECT_EQ(OK, callback_.WaitForResult());
928 scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
[email protected]0b2294d32013-08-02 00:46:36929 HttpRequestInfo request_info;
930 EXPECT_EQ(OK, stream->InitializeStream(&request_info,
931 DEFAULT_PRIORITY,
932 net_log_, CompletionCallback()));
[email protected]f698a012013-05-06 20:18:59933
934 // Change the IP address and verify that stream saw the error.
935 factory_.OnIPAddressChanged();
936 EXPECT_EQ(ERR_NETWORK_CHANGED,
937 stream->ReadResponseHeaders(callback_.callback()));
[email protected]11c05872013-08-20 02:04:12938 EXPECT_TRUE(factory_.require_confirmation());
[email protected]f698a012013-05-06 20:18:59939
940 // Now attempting to request a stream to the same origin should create
941 // a new session.
942
943 QuicStreamRequest request2(&factory_);
[email protected]974849d2014-02-06 01:32:59944 EXPECT_EQ(ERR_IO_PENDING,
[email protected]bf4ea2f2014-03-10 22:57:53945 request2.Request(host_port_pair_,
[email protected]974849d2014-02-06 01:32:59946 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28947 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59948 "GET",
[email protected]974849d2014-02-06 01:32:59949 net_log_,
950 callback_.callback()));
[email protected]f698a012013-05-06 20:18:59951
952 EXPECT_EQ(OK, callback_.WaitForResult());
953 stream = request2.ReleaseStream();
954 stream.reset(); // Will reset stream 3.
955
956 EXPECT_TRUE(socket_data.at_read_eof());
957 EXPECT_TRUE(socket_data.at_write_eof());
958 EXPECT_TRUE(socket_data2.at_read_eof());
959 EXPECT_TRUE(socket_data2.at_write_eof());
960}
961
[email protected]1e960032013-12-20 19:00:20962TEST_P(QuicStreamFactoryTest, OnCertAdded) {
[email protected]d7d1e50b2013-11-25 22:08:09963 MockRead reads[] = {
964 MockRead(ASYNC, 0, 0) // EOF
965 };
[email protected]459a7402014-02-10 12:58:52966 scoped_ptr<QuicEncryptedPacket> rst(ConstructRstPacket());
967 std::vector<MockWrite> writes;
[email protected]08da9adb2014-04-24 08:33:31968 writes.push_back(MockWrite(ASYNC, rst->data(), rst->length(), 1));
[email protected]459a7402014-02-10 12:58:52969 DeterministicSocketData socket_data(reads, arraysize(reads),
970 writes.empty() ? NULL : &writes[0],
971 writes.size());
[email protected]d7d1e50b2013-11-25 22:08:09972 socket_factory_.AddSocketDataProvider(&socket_data);
973 socket_data.StopAfter(1);
974
975 MockRead reads2[] = {
976 MockRead(ASYNC, 0, 0) // EOF
977 };
978 DeterministicSocketData socket_data2(reads2, arraysize(reads2), NULL, 0);
979 socket_factory_.AddSocketDataProvider(&socket_data2);
980 socket_data2.StopAfter(1);
981
982 QuicStreamRequest request(&factory_);
[email protected]974849d2014-02-06 01:32:59983 EXPECT_EQ(ERR_IO_PENDING,
[email protected]bf4ea2f2014-03-10 22:57:53984 request.Request(host_port_pair_,
[email protected]974849d2014-02-06 01:32:59985 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:28986 privacy_mode_,
[email protected]974849d2014-02-06 01:32:59987 "GET",
[email protected]974849d2014-02-06 01:32:59988 net_log_,
989 callback_.callback()));
[email protected]d7d1e50b2013-11-25 22:08:09990
991 EXPECT_EQ(OK, callback_.WaitForResult());
992 scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
993 HttpRequestInfo request_info;
994 EXPECT_EQ(OK, stream->InitializeStream(&request_info,
995 DEFAULT_PRIORITY,
996 net_log_, CompletionCallback()));
997
998 // Add a cert and verify that stream saw the event.
999 factory_.OnCertAdded(NULL);
1000 EXPECT_EQ(ERR_CERT_DATABASE_CHANGED,
1001 stream->ReadResponseHeaders(callback_.callback()));
1002 EXPECT_FALSE(factory_.require_confirmation());
1003
1004 // Now attempting to request a stream to the same origin should create
1005 // a new session.
1006
1007 QuicStreamRequest request2(&factory_);
[email protected]974849d2014-02-06 01:32:591008 EXPECT_EQ(ERR_IO_PENDING,
[email protected]bf4ea2f2014-03-10 22:57:531009 request2.Request(host_port_pair_,
[email protected]974849d2014-02-06 01:32:591010 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:281011 privacy_mode_,
[email protected]974849d2014-02-06 01:32:591012 "GET",
[email protected]974849d2014-02-06 01:32:591013 net_log_,
1014 callback_.callback()));
[email protected]d7d1e50b2013-11-25 22:08:091015
1016 EXPECT_EQ(OK, callback_.WaitForResult());
1017 stream = request2.ReleaseStream();
1018 stream.reset(); // Will reset stream 3.
1019
1020 EXPECT_TRUE(socket_data.at_read_eof());
1021 EXPECT_TRUE(socket_data.at_write_eof());
1022 EXPECT_TRUE(socket_data2.at_read_eof());
1023 EXPECT_TRUE(socket_data2.at_write_eof());
1024}
1025
[email protected]1e960032013-12-20 19:00:201026TEST_P(QuicStreamFactoryTest, OnCACertChanged) {
[email protected]d7d1e50b2013-11-25 22:08:091027 MockRead reads[] = {
1028 MockRead(ASYNC, 0, 0) // EOF
1029 };
[email protected]459a7402014-02-10 12:58:521030 scoped_ptr<QuicEncryptedPacket> rst(ConstructRstPacket());
1031 std::vector<MockWrite> writes;
[email protected]08da9adb2014-04-24 08:33:311032 writes.push_back(MockWrite(ASYNC, rst->data(), rst->length(), 1));
[email protected]459a7402014-02-10 12:58:521033 DeterministicSocketData socket_data(reads, arraysize(reads),
1034 writes.empty() ? NULL : &writes[0],
1035 writes.size());
[email protected]d7d1e50b2013-11-25 22:08:091036 socket_factory_.AddSocketDataProvider(&socket_data);
1037 socket_data.StopAfter(1);
1038
1039 MockRead reads2[] = {
1040 MockRead(ASYNC, 0, 0) // EOF
1041 };
1042 DeterministicSocketData socket_data2(reads2, arraysize(reads2), NULL, 0);
1043 socket_factory_.AddSocketDataProvider(&socket_data2);
1044 socket_data2.StopAfter(1);
1045
1046 QuicStreamRequest request(&factory_);
[email protected]974849d2014-02-06 01:32:591047 EXPECT_EQ(ERR_IO_PENDING,
[email protected]bf4ea2f2014-03-10 22:57:531048 request.Request(host_port_pair_,
[email protected]974849d2014-02-06 01:32:591049 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:281050 privacy_mode_,
[email protected]974849d2014-02-06 01:32:591051 "GET",
[email protected]974849d2014-02-06 01:32:591052 net_log_,
1053 callback_.callback()));
[email protected]d7d1e50b2013-11-25 22:08:091054
1055 EXPECT_EQ(OK, callback_.WaitForResult());
1056 scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
1057 HttpRequestInfo request_info;
1058 EXPECT_EQ(OK, stream->InitializeStream(&request_info,
1059 DEFAULT_PRIORITY,
1060 net_log_, CompletionCallback()));
1061
1062 // Change the CA cert and verify that stream saw the event.
1063 factory_.OnCACertChanged(NULL);
1064 EXPECT_EQ(ERR_CERT_DATABASE_CHANGED,
1065 stream->ReadResponseHeaders(callback_.callback()));
1066 EXPECT_FALSE(factory_.require_confirmation());
1067
1068 // Now attempting to request a stream to the same origin should create
1069 // a new session.
1070
1071 QuicStreamRequest request2(&factory_);
[email protected]974849d2014-02-06 01:32:591072 EXPECT_EQ(ERR_IO_PENDING,
[email protected]bf4ea2f2014-03-10 22:57:531073 request2.Request(host_port_pair_,
[email protected]974849d2014-02-06 01:32:591074 is_https_,
[email protected]9dd3ff0f2014-03-26 09:51:281075 privacy_mode_,
[email protected]974849d2014-02-06 01:32:591076 "GET",
[email protected]974849d2014-02-06 01:32:591077 net_log_,
1078 callback_.callback()));
[email protected]d7d1e50b2013-11-25 22:08:091079
1080 EXPECT_EQ(OK, callback_.WaitForResult());
1081 stream = request2.ReleaseStream();
1082 stream.reset(); // Will reset stream 3.
1083
1084 EXPECT_TRUE(socket_data.at_read_eof());
1085 EXPECT_TRUE(socket_data.at_write_eof());
1086 EXPECT_TRUE(socket_data2.at_read_eof());
1087 EXPECT_TRUE(socket_data2.at_write_eof());
1088}
1089
[email protected]1e960032013-12-20 19:00:201090TEST_P(QuicStreamFactoryTest, SharedCryptoConfig) {
[email protected]6e12d702013-11-13 00:17:171091 vector<string> cannoncial_suffixes;
1092 cannoncial_suffixes.push_back(string(".c.youtube.com"));
1093 cannoncial_suffixes.push_back(string(".googlevideo.com"));
[email protected]c49ff182013-09-28 08:33:261094
[email protected]6e12d702013-11-13 00:17:171095 for (unsigned i = 0; i < cannoncial_suffixes.size(); ++i) {
1096 string r1_host_name("r1");
1097 string r2_host_name("r2");
1098 r1_host_name.append(cannoncial_suffixes[i]);
1099 r2_host_name.append(cannoncial_suffixes[i]);
[email protected]b70fdb792013-10-25 19:04:141100
[email protected]bf4ea2f2014-03-10 22:57:531101 HostPortPair host_port_pair1(r1_host_name, 80);
[email protected]59c0bbd2014-03-22 04:08:121102 QuicCryptoClientConfig* crypto_config =
1103 QuicStreamFactoryPeer::GetCryptoConfig(&factory_);
[email protected]257f24f2014-04-01 09:15:371104 QuicServerId server_id1(host_port_pair1, is_https_, privacy_mode_);
[email protected]6e12d702013-11-13 00:17:171105 QuicCryptoClientConfig::CachedState* cached1 =
[email protected]257f24f2014-04-01 09:15:371106 crypto_config->LookupOrCreate(server_id1);
[email protected]6e12d702013-11-13 00:17:171107 EXPECT_FALSE(cached1->proof_valid());
1108 EXPECT_TRUE(cached1->source_address_token().empty());
1109
1110 // Mutate the cached1 to have different data.
1111 // TODO(rtenneti): mutate other members of CachedState.
1112 cached1->set_source_address_token(r1_host_name);
1113 cached1->SetProofValid();
1114
[email protected]bf4ea2f2014-03-10 22:57:531115 HostPortPair host_port_pair2(r2_host_name, 80);
[email protected]257f24f2014-04-01 09:15:371116 QuicServerId server_id2(host_port_pair2, is_https_, privacy_mode_);
[email protected]6e12d702013-11-13 00:17:171117 QuicCryptoClientConfig::CachedState* cached2 =
[email protected]257f24f2014-04-01 09:15:371118 crypto_config->LookupOrCreate(server_id2);
[email protected]6e12d702013-11-13 00:17:171119 EXPECT_EQ(cached1->source_address_token(), cached2->source_address_token());
1120 EXPECT_TRUE(cached2->proof_valid());
1121 }
[email protected]b70fdb792013-10-25 19:04:141122}
1123
[email protected]1e960032013-12-20 19:00:201124TEST_P(QuicStreamFactoryTest, CryptoConfigWhenProofIsInvalid) {
[email protected]6e12d702013-11-13 00:17:171125 vector<string> cannoncial_suffixes;
1126 cannoncial_suffixes.push_back(string(".c.youtube.com"));
1127 cannoncial_suffixes.push_back(string(".googlevideo.com"));
[email protected]b70fdb792013-10-25 19:04:141128
[email protected]6e12d702013-11-13 00:17:171129 for (unsigned i = 0; i < cannoncial_suffixes.size(); ++i) {
1130 string r3_host_name("r3");
1131 string r4_host_name("r4");
1132 r3_host_name.append(cannoncial_suffixes[i]);
1133 r4_host_name.append(cannoncial_suffixes[i]);
[email protected]b70fdb792013-10-25 19:04:141134
[email protected]bf4ea2f2014-03-10 22:57:531135 HostPortPair host_port_pair1(r3_host_name, 80);
[email protected]59c0bbd2014-03-22 04:08:121136 QuicCryptoClientConfig* crypto_config =
1137 QuicStreamFactoryPeer::GetCryptoConfig(&factory_);
[email protected]257f24f2014-04-01 09:15:371138 QuicServerId server_id1(host_port_pair1, is_https_, privacy_mode_);
[email protected]6e12d702013-11-13 00:17:171139 QuicCryptoClientConfig::CachedState* cached1 =
[email protected]257f24f2014-04-01 09:15:371140 crypto_config->LookupOrCreate(server_id1);
[email protected]6e12d702013-11-13 00:17:171141 EXPECT_FALSE(cached1->proof_valid());
1142 EXPECT_TRUE(cached1->source_address_token().empty());
1143
1144 // Mutate the cached1 to have different data.
1145 // TODO(rtenneti): mutate other members of CachedState.
1146 cached1->set_source_address_token(r3_host_name);
1147 cached1->SetProofInvalid();
1148
[email protected]bf4ea2f2014-03-10 22:57:531149 HostPortPair host_port_pair2(r4_host_name, 80);
[email protected]257f24f2014-04-01 09:15:371150 QuicServerId server_id2(host_port_pair2, is_https_, privacy_mode_);
[email protected]6e12d702013-11-13 00:17:171151 QuicCryptoClientConfig::CachedState* cached2 =
[email protected]257f24f2014-04-01 09:15:371152 crypto_config->LookupOrCreate(server_id2);
[email protected]6e12d702013-11-13 00:17:171153 EXPECT_NE(cached1->source_address_token(), cached2->source_address_token());
1154 EXPECT_TRUE(cached2->source_address_token().empty());
1155 EXPECT_FALSE(cached2->proof_valid());
1156 }
[email protected]c49ff182013-09-28 08:33:261157}
1158
[email protected]e13201d82012-12-12 05:00:321159} // namespace test
[email protected]e13201d82012-12-12 05:00:321160} // namespace net