1 // 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.
8 #include "base/memory/scoped_ptr.h"
9 #include "base/memory/singleton.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/synchronization/waitable_event.h"
12 #include "base/threading/simple_thread.h"
13 #include "net/base/ip_endpoint.h"
14 #include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
15 #include "net/quic/crypto/null_encrypter.h"
16 #include "net/quic/quic_framer.h"
17 #include "net/quic/quic_packet_creator.h"
18 #include "net/quic/quic_protocol.h"
19 #include "net/quic/test_tools/quic_connection_peer.h"
20 #include "net/quic/test_tools/quic_session_peer.h"
21 #include "net/quic/test_tools/reliable_quic_stream_peer.h"
22 #include "net/tools/quic/quic_epoll_connection_helper.h"
23 #include "net/tools/quic/quic_in_memory_cache.h"
24 #include "net/tools/quic/quic_server.h"
25 #include "net/tools/quic/quic_socket_utils.h"
26 #include "net/tools/quic/test_tools/http_message_test_utils.h"
27 #include "net/tools/quic/test_tools/quic_client_peer.h"
28 #include "net/tools/quic/test_tools/quic_epoll_connection_helper_peer.h"
29 #include "net/tools/quic/test_tools/quic_test_client.h"
30 #include "testing/gtest/include/gtest/gtest.h"
32 using base::StringPiece
;
33 using base::WaitableEvent
;
34 using net::test::QuicConnectionPeer
;
35 using net::test::QuicSessionPeer
;
36 using net::test::ReliableQuicStreamPeer
;
44 const char* kFooResponseBody
= "Artichoke hearts make me happy.";
45 const char* kBarResponseBody
= "Palm hearts are pretty delicious, also.";
46 const size_t kCongestionFeedbackFrameSize
= 25;
47 // If kCongestionFeedbackFrameSize increase we need to expand this string
49 const char* kLargeRequest
=
50 "https://www.google.com/foo/test/a/request/string/longer/than/25/bytes";
52 void GenerateBody(string
* body
, int length
) {
54 body
->reserve(length
);
55 for (int i
= 0; i
< length
; ++i
) {
56 body
->append(1, static_cast<char>(32 + i
% (126 - 32)));
61 // Simple wrapper class to run server in a thread.
62 class ServerThread
: public base::SimpleThread
{
64 explicit ServerThread(IPEndPoint address
, const QuicConfig
& config
)
65 : SimpleThread("server_thread"),
66 listening_(true, false),
72 virtual ~ServerThread() {
75 virtual void Run() OVERRIDE
{
76 server_
.Listen(address_
);
79 port_
= server_
.port();
83 while (!quit_
.IsSignaled()) {
84 server_
.WaitForEvents();
96 WaitableEvent
* listening() { return &listening_
; }
97 WaitableEvent
* quit() { return &quit_
; }
100 WaitableEvent listening_
;
102 base::Lock port_lock_
;
107 DISALLOW_COPY_AND_ASSIGN(ServerThread
);
110 class EndToEndTest
: public ::testing::TestWithParam
<QuicVersion
> {
112 static void SetUpTestCase() {
113 QuicInMemoryCache::GetInstance()->ResetForTests();
118 : server_hostname_("example.com"),
119 server_started_(false) {
120 net::IPAddressNumber ip
;
121 CHECK(net::ParseIPLiteralToNumber("127.0.0.1", &ip
));
122 server_address_
= IPEndPoint(ip
, 0);
123 client_config_
.SetDefaults();
124 server_config_
.SetDefaults();
126 AddToCache("GET", kLargeRequest
, "HTTP/1.1", "200", "OK", kFooResponseBody
);
127 AddToCache("GET", "https://www.google.com/foo",
128 "HTTP/1.1", "200", "OK", kFooResponseBody
);
129 AddToCache("GET", "https://www.google.com/bar",
130 "HTTP/1.1", "200", "OK", kBarResponseBody
);
131 version_
= GetParam();
134 virtual QuicTestClient
* CreateQuicClient() {
135 QuicTestClient
* client
= new QuicTestClient(server_address_
,
144 virtual bool Initialize() {
145 // Start the server first, because CreateQuicClient() attempts
146 // to connect to the server.
148 client_
.reset(CreateQuicClient());
149 return client_
->client()->connected();
152 virtual void TearDown() {
157 server_thread_
.reset(new ServerThread(server_address_
, server_config_
));
158 server_thread_
->Start();
159 server_thread_
->listening()->Wait();
160 server_address_
= IPEndPoint(server_address_
.address(),
161 server_thread_
->GetPort());
162 server_started_
= true;
166 if (!server_started_
)
168 if (server_thread_
.get()) {
169 server_thread_
->quit()->Signal();
170 server_thread_
->Join();
174 void AddToCache(const StringPiece
& method
,
175 const StringPiece
& path
,
176 const StringPiece
& version
,
177 const StringPiece
& response_code
,
178 const StringPiece
& response_detail
,
179 const StringPiece
& body
) {
180 BalsaHeaders request_headers
, response_headers
;
181 request_headers
.SetRequestFirstlineFromStringPieces(method
,
184 response_headers
.SetRequestFirstlineFromStringPieces(version
,
187 response_headers
.AppendHeader("content-length",
188 base::IntToString(body
.length()));
190 // Check if response already exists and matches.
191 QuicInMemoryCache
* cache
= QuicInMemoryCache::GetInstance();
192 const QuicInMemoryCache::Response
* cached_response
=
193 cache
->GetResponse(request_headers
);
194 if (cached_response
!= NULL
) {
195 string cached_response_headers_str
, response_headers_str
;
196 cached_response
->headers().DumpToString(&cached_response_headers_str
);
197 response_headers
.DumpToString(&response_headers_str
);
198 CHECK_EQ(cached_response_headers_str
, response_headers_str
);
199 CHECK_EQ(cached_response
->body(), body
);
202 cache
->AddResponse(request_headers
, response_headers
, body
);
205 IPEndPoint server_address_
;
206 string server_hostname_
;
207 scoped_ptr
<ServerThread
> server_thread_
;
208 scoped_ptr
<QuicTestClient
> client_
;
209 bool server_started_
;
210 QuicConfig client_config_
;
211 QuicConfig server_config_
;
212 QuicVersion version_
;
215 // Run all end to end tests with all supported versions.
216 INSTANTIATE_TEST_CASE_P(EndToEndTests
,
218 ::testing::ValuesIn(kSupportedQuicVersions
));
220 TEST_P(EndToEndTest
, SimpleRequestResponse
) {
221 // TODO(rtenneti): Delete this when NSS is supported.
222 if (!Aes128Gcm12Encrypter::IsSupported()) {
223 LOG(INFO
) << "AES GCM not supported. Test skipped.";
227 ASSERT_TRUE(Initialize());
229 EXPECT_EQ(kFooResponseBody
, client_
->SendSynchronousRequest("/foo"));
230 EXPECT_EQ(200u, client_
->response_headers()->parsed_response_code());
233 // TODO(rch): figure out how to detect missing v6 supprt (like on the linux
234 // try bots) and selectively disable this test.
235 TEST_P(EndToEndTest
, DISABLED_SimpleRequestResponsev6
) {
236 // TODO(rtenneti): Delete this when NSS is supported.
237 if (!Aes128Gcm12Encrypter::IsSupported()) {
238 LOG(INFO
) << "AES GCM not supported. Test skipped.";
243 CHECK(net::ParseIPLiteralToNumber("::1", &ip
));
244 server_address_
= IPEndPoint(ip
, server_address_
.port());
245 ASSERT_TRUE(Initialize());
247 EXPECT_EQ(kFooResponseBody
, client_
->SendSynchronousRequest("/foo"));
248 EXPECT_EQ(200u, client_
->response_headers()->parsed_response_code());
251 TEST_P(EndToEndTest
, SeparateFinPacket
) {
252 // TODO(rtenneti): Delete this when NSS is supported.
253 if (!Aes128Gcm12Encrypter::IsSupported()) {
254 LOG(INFO
) << "AES GCM not supported. Test skipped.";
258 ASSERT_TRUE(Initialize());
260 HTTPMessage
request(HttpConstants::HTTP_1_1
,
261 HttpConstants::POST
, "/foo");
262 request
.set_has_complete_message(false);
264 client_
->SendMessage(request
);
266 client_
->SendData(string(), true);
268 client_
->WaitForResponse();
269 EXPECT_EQ(kFooResponseBody
, client_
->response_body());
270 EXPECT_EQ(200u, client_
->response_headers()->parsed_response_code());
272 request
.AddBody("foo", true);
274 client_
->SendMessage(request
);
275 client_
->SendData(string(), true);
276 client_
->WaitForResponse();
277 EXPECT_EQ(kFooResponseBody
, client_
->response_body());
278 EXPECT_EQ(200u, client_
->response_headers()->parsed_response_code());
281 TEST_P(EndToEndTest
, MultipleRequestResponse
) {
282 // TODO(rtenneti): Delete this when NSS is supported.
283 if (!Aes128Gcm12Encrypter::IsSupported()) {
284 LOG(INFO
) << "AES GCM not supported. Test skipped.";
288 ASSERT_TRUE(Initialize());
290 EXPECT_EQ(kFooResponseBody
, client_
->SendSynchronousRequest("/foo"));
291 EXPECT_EQ(200u, client_
->response_headers()->parsed_response_code());
292 EXPECT_EQ(kBarResponseBody
, client_
->SendSynchronousRequest("/bar"));
293 EXPECT_EQ(200u, client_
->response_headers()->parsed_response_code());
296 TEST_P(EndToEndTest
, MultipleClients
) {
297 // TODO(rtenneti): Delete this when NSS is supported.
298 if (!Aes128Gcm12Encrypter::IsSupported()) {
299 LOG(INFO
) << "AES GCM not supported. Test skipped.";
303 ASSERT_TRUE(Initialize());
304 scoped_ptr
<QuicTestClient
> client2(CreateQuicClient());
306 HTTPMessage
request(HttpConstants::HTTP_1_1
,
307 HttpConstants::POST
, "/foo");
308 request
.AddHeader("content-length", "3");
309 request
.set_has_complete_message(false);
311 client_
->SendMessage(request
);
312 client2
->SendMessage(request
);
314 client_
->SendData("bar", true);
315 client_
->WaitForResponse();
316 EXPECT_EQ(kFooResponseBody
, client_
->response_body());
317 EXPECT_EQ(200u, client_
->response_headers()->parsed_response_code());
319 client2
->SendData("eep", true);
320 client2
->WaitForResponse();
321 EXPECT_EQ(kFooResponseBody
, client2
->response_body());
322 EXPECT_EQ(200u, client2
->response_headers()->parsed_response_code());
325 TEST_P(EndToEndTest
, RequestOverMultiplePackets
) {
326 // TODO(rtenneti): Delete this when NSS is supported.
327 if (!Aes128Gcm12Encrypter::IsSupported()) {
328 LOG(INFO
) << "AES GCM not supported. Test skipped.";
332 ASSERT_TRUE(Initialize());
333 // Set things up so we have a small payload, to guarantee fragmentation.
334 // A congestion feedback frame can't be split into multiple packets, make sure
335 // that our packet have room for at least this amount after the normal headers
338 // TODO(rch) handle this better when we have different encryption options.
339 const size_t kStreamDataLength
= 3;
340 const QuicStreamId kStreamId
= 1u;
341 const QuicStreamOffset kStreamOffset
= 0u;
342 size_t stream_payload_size
=
343 QuicFramer::GetMinStreamFrameSize(
344 GetParam(), kStreamId
, kStreamOffset
, true) + kStreamDataLength
;
345 size_t min_payload_size
=
346 std::max(kCongestionFeedbackFrameSize
, stream_payload_size
);
347 size_t ciphertext_size
= NullEncrypter().GetCiphertextSize(min_payload_size
);
348 // TODO(satyashekhar): Fix this when versioning is implemented.
349 client_
->options()->max_packet_length
=
350 GetPacketHeaderSize(PACKET_8BYTE_GUID
, !kIncludeVersion
,
351 PACKET_6BYTE_SEQUENCE_NUMBER
, NOT_IN_FEC_GROUP
) +
354 // Make sure our request is too large to fit in one packet.
355 EXPECT_GT(strlen(kLargeRequest
), min_payload_size
);
356 EXPECT_EQ(kFooResponseBody
, client_
->SendSynchronousRequest(kLargeRequest
));
357 EXPECT_EQ(200u, client_
->response_headers()->parsed_response_code());
360 TEST_P(EndToEndTest
, MultipleFramesRandomOrder
) {
361 // TODO(rtenneti): Delete this when NSS is supported.
362 if (!Aes128Gcm12Encrypter::IsSupported()) {
363 LOG(INFO
) << "AES GCM not supported. Test skipped.";
367 ASSERT_TRUE(Initialize());
368 // Set things up so we have a small payload, to guarantee fragmentation.
369 // A congestion feedback frame can't be split into multiple packets, make sure
370 // that our packet have room for at least this amount after the normal headers
373 // TODO(rch) handle this better when we have different encryption options.
374 const size_t kStreamDataLength
= 3;
375 const QuicStreamId kStreamId
= 1u;
376 const QuicStreamOffset kStreamOffset
= 0u;
377 size_t stream_payload_size
=
378 QuicFramer::GetMinStreamFrameSize(
379 GetParam(), kStreamId
, kStreamOffset
, true) + kStreamDataLength
;
380 size_t min_payload_size
=
381 std::max(kCongestionFeedbackFrameSize
, stream_payload_size
);
382 size_t ciphertext_size
= NullEncrypter().GetCiphertextSize(min_payload_size
);
383 // TODO(satyashekhar): Fix this when versioning is implemented.
384 client_
->options()->max_packet_length
=
385 GetPacketHeaderSize(PACKET_8BYTE_GUID
, !kIncludeVersion
,
386 PACKET_6BYTE_SEQUENCE_NUMBER
, NOT_IN_FEC_GROUP
) +
388 client_
->options()->random_reorder
= true;
390 // Make sure our request is too large to fit in one packet.
391 EXPECT_GT(strlen(kLargeRequest
), min_payload_size
);
392 EXPECT_EQ(kFooResponseBody
, client_
->SendSynchronousRequest(kLargeRequest
));
393 EXPECT_EQ(200u, client_
->response_headers()->parsed_response_code());
396 TEST_P(EndToEndTest
, PostMissingBytes
) {
397 // TODO(rtenneti): Delete this when NSS is supported.
398 if (!Aes128Gcm12Encrypter::IsSupported()) {
399 LOG(INFO
) << "AES GCM not supported. Test skipped.";
403 ASSERT_TRUE(Initialize());
405 // Add a content length header with no body.
406 HTTPMessage
request(HttpConstants::HTTP_1_1
,
407 HttpConstants::POST
, "/foo");
408 request
.AddHeader("content-length", "3");
409 request
.set_skip_message_validation(true);
411 // This should be detected as stream fin without complete request,
412 // triggering an error response.
413 client_
->SendCustomSynchronousRequest(request
);
414 EXPECT_EQ("bad", client_
->response_body());
415 EXPECT_EQ(500u, client_
->response_headers()->parsed_response_code());
418 TEST_P(EndToEndTest
, LargePost
) {
419 // TODO(rtenneti): Delete this when NSS is supported.
420 if (!Aes128Gcm12Encrypter::IsSupported()) {
421 LOG(INFO
) << "AES GCM not supported. Test skipped.";
425 // Connect with lower fake packet loss than we'd like to test. Until
426 // b/10126687 is fixed, losing handshake packets is pretty brutal.
427 // FLAGS_fake_packet_loss_percentage = 5;
428 ASSERT_TRUE(Initialize());
430 // Wait for the server SHLO before upping the packet loss.
431 client_
->client()->WaitForCryptoHandshakeConfirmed();
432 // FLAGS_fake_packet_loss_percentage = 30;
435 GenerateBody(&body
, 10240);
437 HTTPMessage
request(HttpConstants::HTTP_1_1
,
438 HttpConstants::POST
, "/foo");
439 request
.AddBody(body
, true);
441 EXPECT_EQ(kFooResponseBody
, client_
->SendCustomSynchronousRequest(request
));
444 // TODO(ianswett): Enable once b/9295090 is fixed.
445 TEST_P(EndToEndTest
, DISABLED_LargePostFEC
) {
446 // FLAGS_fake_packet_loss_percentage = 30;
447 ASSERT_TRUE(Initialize());
448 client_
->options()->max_packets_per_fec_group
= 6;
450 // TODO(rtenneti): Delete this when NSS is supported.
451 if (!Aes128Gcm12Encrypter::IsSupported()) {
452 LOG(INFO
) << "AES GCM not supported. Test skipped.";
456 // FLAGS_fake_packet_loss_percentage = 30;
457 ASSERT_TRUE(Initialize());
458 client_
->options()->max_packets_per_fec_group
= 6;
461 GenerateBody(&body
, 10240);
463 HTTPMessage
request(HttpConstants::HTTP_1_1
,
464 HttpConstants::POST
, "/foo");
465 request
.AddBody(body
, true);
467 EXPECT_EQ(kFooResponseBody
, client_
->SendCustomSynchronousRequest(request
));
470 /*TEST_P(EndToEndTest, PacketTooLarge) {
471 FLAGS_quic_allow_oversized_packets_for_test = true;
472 ASSERT_TRUE(Initialize());
475 GenerateBody(&body, kMaxPacketSize);
477 HTTPMessage request(HttpConstants::HTTP_1_1,
478 HttpConstants::POST, "/foo");
479 request.AddBody(body, true);
480 client_->options()->max_packet_length = 20480;
482 EXPECT_EQ("", client_->SendCustomSynchronousRequest(request));
483 EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error());
484 EXPECT_EQ(QUIC_PACKET_TOO_LARGE, client_->connection_error());
487 TEST_P(EndToEndTest
, InvalidStream
) {
488 // TODO(rtenneti): Delete this when NSS is supported.
489 if (!Aes128Gcm12Encrypter::IsSupported()) {
490 LOG(INFO
) << "AES GCM not supported. Test skipped.";
494 ASSERT_TRUE(Initialize());
497 GenerateBody(&body
, kMaxPacketSize
);
499 HTTPMessage
request(HttpConstants::HTTP_1_1
,
500 HttpConstants::POST
, "/foo");
501 request
.AddBody(body
, true);
502 // Force the client to write with a stream ID belonging to a nonexistent
503 // server-side stream.
504 QuicSessionPeer::SetNextStreamId(client_
->client()->session(), 2);
506 client_
->SendCustomSynchronousRequest(request
);
507 // EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error());
508 EXPECT_EQ(QUIC_PACKET_FOR_NONEXISTENT_STREAM
, client_
->connection_error());
511 // TODO(rch): this test seems to cause net_unittests timeouts :|
512 TEST_P(EndToEndTest
, DISABLED_MultipleTermination
) {
513 // TODO(rtenneti): Delete this when NSS is supported.
514 if (!Aes128Gcm12Encrypter::IsSupported()) {
515 LOG(INFO
) << "AES GCM not supported. Test skipped.";
519 ASSERT_TRUE(Initialize());
520 scoped_ptr
<QuicTestClient
> client2(CreateQuicClient());
522 HTTPMessage
request(HttpConstants::HTTP_1_1
,
523 HttpConstants::POST
, "/foo");
524 request
.AddHeader("content-length", "3");
525 request
.set_has_complete_message(false);
527 // Set the offset so we won't frame. Otherwise when we pick up termination
528 // before HTTP framing is complete, we send an error and close the stream,
529 // and the second write is picked up as writing on a closed stream.
530 QuicReliableClientStream
* stream
= client_
->GetOrCreateStream();
531 ASSERT_TRUE(stream
!= NULL
);
532 ReliableQuicStreamPeer::SetStreamBytesWritten(3, stream
);
534 client_
->SendData("bar", true);
536 // By default the stream protects itself from writes after terminte is set.
537 // Override this to test the server handling buggy clients.
538 ReliableQuicStreamPeer::SetWriteSideClosed(
539 false, client_
->GetOrCreateStream());
541 #if !defined(WIN32) && defined(GTEST_HAS_DEATH_TEST)
542 #if !defined(DCHECK_ALWAYS_ON)
544 client_
->SendData("eep", true);
545 client_
->WaitForResponse();
546 EXPECT_EQ(QUIC_MULTIPLE_TERMINATION_OFFSETS
, client_
->stream_error());
548 "Check failed: !fin_buffered_");
551 client_
->SendData("eep", true);
552 client_
->WaitForResponse();
553 EXPECT_EQ(QUIC_MULTIPLE_TERMINATION_OFFSETS
, client_
->stream_error());
555 "Check failed: !fin_buffered_");
560 TEST_P(EndToEndTest
, Timeout
) {
561 client_config_
.set_idle_connection_state_lifetime(
562 QuicTime::Delta::FromMicroseconds(500),
563 QuicTime::Delta::FromMicroseconds(500));
564 // Note: we do NOT ASSERT_TRUE: we may time out during initial handshake:
565 // that's enough to validate timeout in this case.
567 while (client_
->client()->connected()) {
568 client_
->client()->WaitForEvents();
572 TEST_P(EndToEndTest
, LimitMaxOpenStreams
) {
573 // Server limits the number of max streams to 2.
574 server_config_
.set_max_streams_per_connection(2, 2);
575 // Client tries to negotiate for 10.
576 client_config_
.set_max_streams_per_connection(10, 5);
578 ASSERT_TRUE(Initialize());
579 client_
->client()->WaitForCryptoHandshakeConfirmed();
580 QuicConfig
* client_negotiated_config
= client_
->client()->session()->config();
581 EXPECT_EQ(2u, client_negotiated_config
->max_streams_per_connection());
584 TEST_P(EndToEndTest
, ResetConnection
) {
585 // TODO(rtenneti): Delete this when NSS is supported.
586 if (!Aes128Gcm12Encrypter::IsSupported()) {
587 LOG(INFO
) << "AES GCM not supported. Test skipped.";
591 ASSERT_TRUE(Initialize());
593 EXPECT_EQ(kFooResponseBody
, client_
->SendSynchronousRequest("/foo"));
594 EXPECT_EQ(200u, client_
->response_headers()->parsed_response_code());
595 client_
->ResetConnection();
596 EXPECT_EQ(kBarResponseBody
, client_
->SendSynchronousRequest("/bar"));
597 EXPECT_EQ(200u, client_
->response_headers()->parsed_response_code());
600 class WrongAddressWriter
: public QuicPacketWriter
{
602 explicit WrongAddressWriter(int fd
) : fd_(fd
) {
604 CHECK(net::ParseIPLiteralToNumber("127.0.0.2", &ip
));
605 self_address_
= IPEndPoint(ip
, 0);
608 virtual int WritePacket(const char* buffer
, size_t buf_len
,
609 const IPAddressNumber
& real_self_address
,
610 const IPEndPoint
& peer_address
,
611 QuicBlockedWriterInterface
* blocked_writer
,
612 int* error
) OVERRIDE
{
613 return QuicSocketUtils::WritePacket(fd_
, buffer
, buf_len
,
614 self_address_
.address(), peer_address
,
618 IPEndPoint self_address_
;
622 TEST_P(EndToEndTest
, ConnectionMigration
) {
623 // TODO(rtenneti): Delete this when NSS is supported.
624 if (!Aes128Gcm12Encrypter::IsSupported()) {
625 LOG(INFO
) << "AES GCM not supported. Test skipped.";
629 ASSERT_TRUE(Initialize());
631 EXPECT_EQ(kFooResponseBody
, client_
->SendSynchronousRequest("/foo"));
632 EXPECT_EQ(200u, client_
->response_headers()->parsed_response_code());
634 WrongAddressWriter
writer(QuicClientPeer::GetFd(client_
->client()));
635 QuicEpollConnectionHelper
* helper
=
636 reinterpret_cast<QuicEpollConnectionHelper
*>(
637 QuicConnectionPeer::GetHelper(
638 client_
->client()->session()->connection()));
639 QuicEpollConnectionHelperPeer::SetWriter(helper
, &writer
);
641 client_
->SendSynchronousRequest("/bar");
642 QuicEpollConnectionHelperPeer::SetWriter(helper
, NULL
);
644 EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR
, client_
->stream_error());
645 EXPECT_EQ(QUIC_ERROR_MIGRATING_ADDRESS
, client_
->connection_error());