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.
4
5#include "net/tools/quic/quic_client_session.h"
6
7#include <vector>
8
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_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 "net/tools/quic/test_tools/quic_test_utils.h"
17#include "testing/gtest/include/gtest/gtest.h"
18
19using net::test::CryptoTestUtils;
20using net::test::DefaultQuicConfig;
21using net::test::PacketSavingConnection;
22using net::test::QuicSessionPeer;
23using net::test::SupportedVersions;
24using net::test::TestPeerIPAddress;
25using net::test::ValueRestore;
26using net::test::kTestPort;
27using net::tools::test::MockConnection;
28using testing::Invoke;
29using testing::_;
30
31namespace net {
32namespace tools {
33namespace test {
34namespace {
35
36const char kServerHostname[] = "www.example.com";
37const uint16 kPort = 80;
38
39class ToolsQuicClientSessionTest
40    : public ::testing::TestWithParam<QuicVersion> {
41 protected:
42  ToolsQuicClientSessionTest()
43      : connection_(new PacketSavingConnection(false,
44                                               SupportedVersions(GetParam()))) {
45    crypto_config_.SetDefaults();
46    session_.reset(new QuicClientSession(DefaultQuicConfig(), connection_));
47    session_->InitializeSession(
48        QuicServerId(kServerHostname, kPort, false, PRIVACY_MODE_DISABLED),
49        &crypto_config_);
50    session_->config()->SetDefaults();
51  }
52
53  void CompleteCryptoHandshake() {
54    ASSERT_TRUE(session_->CryptoConnect());
55    CryptoTestUtils::HandshakeWithFakeServer(
56        connection_, session_->GetCryptoStream());
57  }
58
59  PacketSavingConnection* connection_;
60  scoped_ptr<QuicClientSession> session_;
61  QuicCryptoClientConfig crypto_config_;
62};
63
64INSTANTIATE_TEST_CASE_P(Tests, ToolsQuicClientSessionTest,
65                        ::testing::ValuesIn(QuicSupportedVersions()));
66
67TEST_P(ToolsQuicClientSessionTest, CryptoConnect) {
68  CompleteCryptoHandshake();
69}
70
71TEST_P(ToolsQuicClientSessionTest, MaxNumStreams) {
72  session_->config()->set_max_streams_per_connection(1, 1);
73  // FLAGS_max_streams_per_connection = 1;
74  // Initialize crypto before the client session will create a stream.
75  CompleteCryptoHandshake();
76
77  QuicSpdyClientStream* stream =
78      session_->CreateOutgoingDataStream();
79  ASSERT_TRUE(stream);
80  EXPECT_FALSE(session_->CreateOutgoingDataStream());
81
82  // Close a stream and ensure I can now open a new one.
83  session_->CloseStream(stream->id());
84  stream = session_->CreateOutgoingDataStream();
85  EXPECT_TRUE(stream);
86}
87
88TEST_P(ToolsQuicClientSessionTest, GoAwayReceived) {
89  CompleteCryptoHandshake();
90
91  // After receiving a GoAway, I should no longer be able to create outgoing
92  // streams.
93  session_->OnGoAway(QuicGoAwayFrame(QUIC_PEER_GOING_AWAY, 1u, "Going away."));
94  EXPECT_EQ(NULL, session_->CreateOutgoingDataStream());
95}
96
97TEST_P(ToolsQuicClientSessionTest, SetFecProtectionFromConfig) {
98  ValueRestore<bool> old_flag(&FLAGS_enable_quic_fec, true);
99
100  // Set FEC config in client's connection options.
101  QuicTagVector copt;
102  copt.push_back(kFHDR);
103  session_->config()->SetConnectionOptionsToSend(copt);
104
105  // Doing the handshake should set up FEC config correctly.
106  CompleteCryptoHandshake();
107
108  // Verify that headers stream is always protected and data streams are
109  // optionally protected.
110  EXPECT_EQ(FEC_PROTECT_ALWAYS,
111            QuicSessionPeer::GetHeadersStream(session_.get())->fec_policy());
112  QuicSpdyClientStream* stream = session_->CreateOutgoingDataStream();
113  ASSERT_TRUE(stream);
114  EXPECT_EQ(FEC_PROTECT_OPTIONAL, stream->fec_policy());
115}
116
117TEST_P(ToolsQuicClientSessionTest, EmptyPacketReceived) {
118  // This test covers broken behavior that empty packets cause QUIC connection
119  // broken.
120
121  // Create Packet with 0 length.
122  QuicEncryptedPacket invalid_packet(nullptr, 0, false);
123  IPEndPoint server_address(TestPeerIPAddress(), kTestPort);
124  IPEndPoint client_address(TestPeerIPAddress(), kTestPort);
125
126  EXPECT_CALL(*reinterpret_cast<MockConnection*>(session_->connection()),
127              ProcessUdpPacket(server_address, client_address, _))
128      .WillRepeatedly(
129          Invoke(reinterpret_cast<MockConnection*>(session_->connection()),
130                 &MockConnection::ReallyProcessUdpPacket));
131
132  // Expect call to close connection with error QUIC_INVALID_PACKET_HEADER.
133  // TODO(b/17206611): Correct behavior: packet should get dropped and
134  // connection should remain open.
135  EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(
136      QUIC_INVALID_PACKET_HEADER, _)).Times(1);
137  session_->connection()->ProcessUdpPacket(client_address, server_address,
138                                           invalid_packet);
139
140  // Create a packet that causes DecryptPacket failed. The packet will get
141  // dropped without closing connection. This is a correct behavior.
142  char buf[2] = {0x00, 0x01};
143  QuicEncryptedPacket valid_packet(buf, 2, false);
144  // Close connection shouldn't be called.
145  EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(_, _)).Times(0);
146  session_->connection()->ProcessUdpPacket(client_address, server_address,
147                                           valid_packet);
148}
149
150}  // namespace
151}  // namespace test
152}  // namespace tools
153}  // namespace net
154