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.
5 #include "net/tools/quic/quic_client_session.h"
9 #include "net/base/ip_endpoint.h"
10 #include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
11 #include "net/quic/quic_flags.h"
12 #include "net/quic/test_tools/crypto_test_utils.h"
13 #include "net/quic/test_tools/quic_spdy_session_peer.h"
14 #include "net/quic/test_tools/quic_test_utils.h"
15 #include "net/tools/quic/quic_spdy_client_stream.h"
16 #include "testing/gtest/include/gtest/gtest.h"
18 using net::test::ConstructEncryptedPacket
;
19 using net::test::ConstructMisFramedEncryptedPacket
;
20 using net::test::CryptoTestUtils
;
21 using net::test::DefaultQuicConfig
;
22 using net::test::MockConnection
;
23 using net::test::PacketSavingConnection
;
24 using net::test::QuicSpdySessionPeer
;
25 using net::test::SupportedVersions
;
26 using net::test::TestPeerIPAddress
;
27 using net::test::ValueRestore
;
28 using net::test::kTestPort
;
29 using testing::AnyNumber
;
30 using testing::Invoke
;
39 const char kServerHostname
[] = "www.example.org";
40 const uint16 kPort
= 80;
42 class ToolsQuicClientSessionTest
43 : public ::testing::TestWithParam
<QuicVersion
> {
45 ToolsQuicClientSessionTest()
46 : connection_(new PacketSavingConnection(Perspective::IS_CLIENT
,
47 SupportedVersions(GetParam()))) {
48 session_
.reset(new QuicClientSession(
49 DefaultQuicConfig(), connection_
,
50 QuicServerId(kServerHostname
, kPort
, false, PRIVACY_MODE_DISABLED
),
52 session_
->Initialize();
53 // Advance the time, because timers do not like uninitialized times.
54 connection_
->AdvanceTime(QuicTime::Delta::FromSeconds(1));
57 void CompleteCryptoHandshake() {
58 session_
->CryptoConnect();
59 CryptoTestUtils::HandshakeWithFakeServer(
60 connection_
, session_
->GetCryptoStream());
63 PacketSavingConnection
* connection_
;
64 scoped_ptr
<QuicClientSession
> session_
;
65 QuicCryptoClientConfig crypto_config_
;
68 INSTANTIATE_TEST_CASE_P(Tests
, ToolsQuicClientSessionTest
,
69 ::testing::ValuesIn(QuicSupportedVersions()));
71 TEST_P(ToolsQuicClientSessionTest
, CryptoConnect
) {
72 CompleteCryptoHandshake();
75 TEST_P(ToolsQuicClientSessionTest
, MaxNumStreams
) {
76 EXPECT_CALL(*connection_
, SendRstStream(_
, _
, _
)).Times(AnyNumber());
78 session_
->config()->SetMaxStreamsPerConnection(1, 1);
80 // Initialize crypto before the client session will create a stream.
81 CompleteCryptoHandshake();
83 QuicSpdyClientStream
* stream
= session_
->CreateOutgoingDynamicStream();
85 EXPECT_FALSE(session_
->CreateOutgoingDynamicStream());
87 // Close a stream and ensure I can now open a new one.
88 session_
->CloseStream(stream
->id());
89 stream
= session_
->CreateOutgoingDynamicStream();
93 TEST_P(ToolsQuicClientSessionTest
, GoAwayReceived
) {
94 CompleteCryptoHandshake();
96 // After receiving a GoAway, I should no longer be able to create outgoing
98 session_
->connection()->OnGoAwayFrame(
99 QuicGoAwayFrame(QUIC_PEER_GOING_AWAY
, 1u, "Going away."));
100 EXPECT_EQ(nullptr, session_
->CreateOutgoingDynamicStream());
103 TEST_P(ToolsQuicClientSessionTest
, SetFecProtectionFromConfig
) {
104 ValueRestore
<bool> old_flag(&FLAGS_enable_quic_fec
, true);
106 // Set FEC config in client's connection options.
108 copt
.push_back(kFHDR
);
109 session_
->config()->SetConnectionOptionsToSend(copt
);
111 // Doing the handshake should set up FEC config correctly.
112 CompleteCryptoHandshake();
114 // Verify that headers stream is always protected and data streams are
115 // optionally protected.
116 EXPECT_EQ(FEC_PROTECT_ALWAYS
, QuicSpdySessionPeer::GetHeadersStream(
117 session_
.get())->fec_policy());
118 QuicSpdyClientStream
* stream
= session_
->CreateOutgoingDynamicStream();
120 EXPECT_EQ(FEC_PROTECT_OPTIONAL
, stream
->fec_policy());
123 static bool CheckForDecryptionError(QuicFramer
* framer
) {
124 return framer
->error() == QUIC_DECRYPTION_FAILURE
;
127 // Regression test for b/17206611.
128 TEST_P(ToolsQuicClientSessionTest
, InvalidPacketReceived
) {
129 IPEndPoint
server_address(TestPeerIPAddress(), kTestPort
);
130 IPEndPoint
client_address(TestPeerIPAddress(), kTestPort
);
132 EXPECT_CALL(*connection_
, ProcessUdpPacket(server_address
, client_address
, _
))
133 .WillRepeatedly(Invoke(implicit_cast
<MockConnection
*>(connection_
),
134 &MockConnection::ReallyProcessUdpPacket
));
135 EXPECT_CALL(*connection_
, OnCanWrite()).Times(AnyNumber());
136 EXPECT_CALL(*connection_
, OnError(_
)).Times(1);
138 // Verify that empty packets don't close the connection.
139 QuicEncryptedPacket
zero_length_packet(nullptr, 0, false);
140 EXPECT_CALL(*connection_
, SendConnectionCloseWithDetails(_
, _
)).Times(0);
141 session_
->connection()->ProcessUdpPacket(client_address
, server_address
,
144 // Verifiy that small, invalid packets don't close the connection.
145 char buf
[2] = {0x00, 0x01};
146 QuicEncryptedPacket
valid_packet(buf
, 2, false);
147 // Close connection shouldn't be called.
148 EXPECT_CALL(*connection_
, SendConnectionCloseWithDetails(_
, _
)).Times(0);
149 session_
->connection()->ProcessUdpPacket(client_address
, server_address
,
152 // Verify that a non-decryptable packet doesn't close the connection.
153 QuicConnectionId connection_id
= session_
->connection()->connection_id();
154 scoped_ptr
<QuicEncryptedPacket
> packet(
155 ConstructEncryptedPacket(connection_id
, false, false, 100, "data"));
156 // Change the last byte of the encrypted data.
157 *(const_cast<char*>(packet
->data() + packet
->length() - 1)) += 1;
158 EXPECT_CALL(*connection_
, SendConnectionCloseWithDetails(_
, _
)).Times(0);
159 EXPECT_CALL(*connection_
, OnError(Truly(CheckForDecryptionError
))).Times(1);
160 session_
->connection()->ProcessUdpPacket(client_address
, server_address
,
164 // A packet with invalid framing should cause a connection to be closed.
165 TEST_P(ToolsQuicClientSessionTest
, InvalidFramedPacketReceived
) {
166 IPEndPoint
server_address(TestPeerIPAddress(), kTestPort
);
167 IPEndPoint
client_address(TestPeerIPAddress(), kTestPort
);
169 EXPECT_CALL(*connection_
, ProcessUdpPacket(server_address
, client_address
, _
))
170 .WillRepeatedly(Invoke(implicit_cast
<MockConnection
*>(connection_
),
171 &MockConnection::ReallyProcessUdpPacket
));
172 EXPECT_CALL(*connection_
, OnError(_
)).Times(1);
174 // Verify that a decryptable packet with bad frames does close the connection.
175 QuicConnectionId connection_id
= session_
->connection()->connection_id();
176 scoped_ptr
<QuicEncryptedPacket
> packet(ConstructMisFramedEncryptedPacket(
177 connection_id
, false, false, 100, "data", PACKET_8BYTE_CONNECTION_ID
,
178 PACKET_6BYTE_PACKET_NUMBER
, nullptr));
179 EXPECT_CALL(*connection_
, SendConnectionCloseWithDetails(_
, _
)).Times(1);
180 session_
->connection()->ProcessUdpPacket(client_address
, server_address
,