|  | // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "net/quic/quic_config.h" | 
|  |  | 
|  | #include "net/quic/crypto/crypto_handshake_message.h" | 
|  | #include "net/quic/crypto/crypto_protocol.h" | 
|  | #include "net/quic/quic_flags.h" | 
|  | #include "net/quic/quic_protocol.h" | 
|  | #include "net/quic/quic_time.h" | 
|  | #include "net/quic/quic_utils.h" | 
|  | #include "net/quic/test_tools/quic_config_peer.h" | 
|  | #include "net/quic/test_tools/quic_test_utils.h" | 
|  | #include "net/test/gtest_util.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | using std::string; | 
|  |  | 
|  | namespace net { | 
|  | namespace test { | 
|  | namespace { | 
|  |  | 
|  | class QuicConfigTest : public ::testing::Test { | 
|  | protected: | 
|  | QuicConfig config_; | 
|  | }; | 
|  |  | 
|  | TEST_F(QuicConfigTest, ToHandshakeMessage) { | 
|  | config_.SetInitialStreamFlowControlWindowToSend( | 
|  | kInitialStreamFlowControlWindowForTest); | 
|  | config_.SetInitialSessionFlowControlWindowToSend( | 
|  | kInitialSessionFlowControlWindowForTest); | 
|  | config_.SetIdleConnectionStateLifetime(QuicTime::Delta::FromSeconds(5), | 
|  | QuicTime::Delta::FromSeconds(2)); | 
|  | config_.SetMaxStreamsPerConnection(4, 2); | 
|  | config_.SetSocketReceiveBufferToSend(kDefaultSocketReceiveBuffer); | 
|  | CryptoHandshakeMessage msg; | 
|  | config_.ToHandshakeMessage(&msg); | 
|  |  | 
|  | uint32 value; | 
|  | QuicErrorCode error = msg.GetUint32(kICSL, &value); | 
|  | EXPECT_EQ(QUIC_NO_ERROR, error); | 
|  | EXPECT_EQ(5u, value); | 
|  |  | 
|  | error = msg.GetUint32(kMSPC, &value); | 
|  | EXPECT_EQ(QUIC_NO_ERROR, error); | 
|  | EXPECT_EQ(4u, value); | 
|  |  | 
|  | error = msg.GetUint32(kSFCW, &value); | 
|  | EXPECT_EQ(QUIC_NO_ERROR, error); | 
|  | EXPECT_EQ(kInitialStreamFlowControlWindowForTest, value); | 
|  |  | 
|  | error = msg.GetUint32(kCFCW, &value); | 
|  | EXPECT_EQ(QUIC_NO_ERROR, error); | 
|  | EXPECT_EQ(kInitialSessionFlowControlWindowForTest, value); | 
|  |  | 
|  | error = msg.GetUint32(kSRBF, &value); | 
|  | EXPECT_EQ(QUIC_NO_ERROR, error); | 
|  | EXPECT_EQ(kDefaultSocketReceiveBuffer, value); | 
|  | } | 
|  |  | 
|  | TEST_F(QuicConfigTest, ProcessClientHello) { | 
|  | QuicConfig client_config; | 
|  | QuicTagVector cgst; | 
|  | cgst.push_back(kQBIC); | 
|  | client_config.SetIdleConnectionStateLifetime( | 
|  | QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs), | 
|  | QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs)); | 
|  | client_config.SetMaxStreamsPerConnection( | 
|  | 2 * kDefaultMaxStreamsPerConnection, kDefaultMaxStreamsPerConnection); | 
|  | client_config.SetInitialRoundTripTimeUsToSend(10 * kNumMicrosPerMilli); | 
|  | client_config.SetInitialStreamFlowControlWindowToSend( | 
|  | 2 * kInitialStreamFlowControlWindowForTest); | 
|  | client_config.SetInitialSessionFlowControlWindowToSend( | 
|  | 2 * kInitialSessionFlowControlWindowForTest); | 
|  | client_config.SetSocketReceiveBufferToSend(kDefaultSocketReceiveBuffer); | 
|  | QuicTagVector copt; | 
|  | copt.push_back(kTBBR); | 
|  | copt.push_back(kFHDR); | 
|  | client_config.SetConnectionOptionsToSend(copt); | 
|  | CryptoHandshakeMessage msg; | 
|  | client_config.ToHandshakeMessage(&msg); | 
|  |  | 
|  | string error_details; | 
|  | const QuicErrorCode error = | 
|  | config_.ProcessPeerHello(msg, CLIENT, &error_details); | 
|  | EXPECT_EQ(QUIC_NO_ERROR, error); | 
|  | EXPECT_TRUE(config_.negotiated()); | 
|  | EXPECT_EQ(QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs), | 
|  | config_.IdleConnectionStateLifetime()); | 
|  | EXPECT_EQ(kDefaultMaxStreamsPerConnection, | 
|  | config_.MaxStreamsPerConnection()); | 
|  | EXPECT_EQ(10 * kNumMicrosPerMilli, config_.ReceivedInitialRoundTripTimeUs()); | 
|  | EXPECT_TRUE(config_.HasReceivedConnectionOptions()); | 
|  | EXPECT_EQ(2u, config_.ReceivedConnectionOptions().size()); | 
|  | EXPECT_EQ(config_.ReceivedConnectionOptions()[0], kTBBR); | 
|  | EXPECT_EQ(config_.ReceivedConnectionOptions()[1], kFHDR); | 
|  | EXPECT_EQ(config_.ReceivedInitialStreamFlowControlWindowBytes(), | 
|  | 2 * kInitialStreamFlowControlWindowForTest); | 
|  | EXPECT_EQ(config_.ReceivedInitialSessionFlowControlWindowBytes(), | 
|  | 2 * kInitialSessionFlowControlWindowForTest); | 
|  | EXPECT_EQ(config_.ReceivedSocketReceiveBuffer(), | 
|  | kDefaultSocketReceiveBuffer); | 
|  | } | 
|  |  | 
|  | TEST_F(QuicConfigTest, ProcessServerHello) { | 
|  | QuicConfig server_config; | 
|  | QuicTagVector cgst; | 
|  | cgst.push_back(kQBIC); | 
|  | server_config.SetIdleConnectionStateLifetime( | 
|  | QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs / 2), | 
|  | QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs / 2)); | 
|  | server_config.SetMaxStreamsPerConnection( | 
|  | kDefaultMaxStreamsPerConnection / 2, | 
|  | kDefaultMaxStreamsPerConnection / 2); | 
|  | server_config.SetInitialRoundTripTimeUsToSend(10 * kNumMicrosPerMilli); | 
|  | server_config.SetInitialStreamFlowControlWindowToSend( | 
|  | 2 * kInitialStreamFlowControlWindowForTest); | 
|  | server_config.SetInitialSessionFlowControlWindowToSend( | 
|  | 2 * kInitialSessionFlowControlWindowForTest); | 
|  | server_config.SetSocketReceiveBufferToSend(kDefaultSocketReceiveBuffer); | 
|  | CryptoHandshakeMessage msg; | 
|  | server_config.ToHandshakeMessage(&msg); | 
|  | string error_details; | 
|  | const QuicErrorCode error = | 
|  | config_.ProcessPeerHello(msg, SERVER, &error_details); | 
|  | EXPECT_EQ(QUIC_NO_ERROR, error); | 
|  | EXPECT_TRUE(config_.negotiated()); | 
|  | EXPECT_EQ(QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs / 2), | 
|  | config_.IdleConnectionStateLifetime()); | 
|  | EXPECT_EQ(kDefaultMaxStreamsPerConnection / 2, | 
|  | config_.MaxStreamsPerConnection()); | 
|  | EXPECT_EQ(10 * kNumMicrosPerMilli, config_.ReceivedInitialRoundTripTimeUs()); | 
|  | EXPECT_EQ(config_.ReceivedInitialStreamFlowControlWindowBytes(), | 
|  | 2 * kInitialStreamFlowControlWindowForTest); | 
|  | EXPECT_EQ(config_.ReceivedInitialSessionFlowControlWindowBytes(), | 
|  | 2 * kInitialSessionFlowControlWindowForTest); | 
|  | EXPECT_EQ(config_.ReceivedSocketReceiveBuffer(), | 
|  | kDefaultSocketReceiveBuffer); | 
|  | } | 
|  |  | 
|  | TEST_F(QuicConfigTest, MissingOptionalValuesInCHLO) { | 
|  | CryptoHandshakeMessage msg; | 
|  | msg.SetValue(kICSL, 1); | 
|  |  | 
|  | // Set all REQUIRED tags. | 
|  | msg.SetValue(kICSL, 1); | 
|  | msg.SetValue(kMSPC, 1); | 
|  |  | 
|  | // No error, as rest are optional. | 
|  | string error_details; | 
|  | const QuicErrorCode error = | 
|  | config_.ProcessPeerHello(msg, CLIENT, &error_details); | 
|  | EXPECT_EQ(QUIC_NO_ERROR, error); | 
|  | EXPECT_TRUE(config_.negotiated()); | 
|  | } | 
|  |  | 
|  | TEST_F(QuicConfigTest, MissingOptionalValuesInSHLO) { | 
|  | CryptoHandshakeMessage msg; | 
|  |  | 
|  | // Set all REQUIRED tags. | 
|  | msg.SetValue(kICSL, 1); | 
|  | msg.SetValue(kMSPC, 1); | 
|  |  | 
|  | // No error, as rest are optional. | 
|  | string error_details; | 
|  | const QuicErrorCode error = | 
|  | config_.ProcessPeerHello(msg, SERVER, &error_details); | 
|  | EXPECT_EQ(QUIC_NO_ERROR, error); | 
|  | EXPECT_TRUE(config_.negotiated()); | 
|  | } | 
|  |  | 
|  | TEST_F(QuicConfigTest, MissingValueInCHLO) { | 
|  | CryptoHandshakeMessage msg; | 
|  | msg.SetValue(kICSL, 1); | 
|  | // Missing kMSPC. KATO is optional. | 
|  | string error_details; | 
|  | const QuicErrorCode error = | 
|  | config_.ProcessPeerHello(msg, CLIENT, &error_details); | 
|  | EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, error); | 
|  | } | 
|  |  | 
|  | TEST_F(QuicConfigTest, MissingValueInSHLO) { | 
|  | CryptoHandshakeMessage msg; | 
|  | msg.SetValue(kMSPC, 3); | 
|  | // Missing ICSL. KATO is optional. | 
|  | string error_details; | 
|  | const QuicErrorCode error = | 
|  | config_.ProcessPeerHello(msg, SERVER, &error_details); | 
|  | EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, error); | 
|  | } | 
|  |  | 
|  | TEST_F(QuicConfigTest, OutOfBoundSHLO) { | 
|  | QuicConfig server_config; | 
|  | server_config.SetIdleConnectionStateLifetime( | 
|  | QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs), | 
|  | QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs)); | 
|  |  | 
|  | CryptoHandshakeMessage msg; | 
|  | server_config.ToHandshakeMessage(&msg); | 
|  | string error_details; | 
|  | const QuicErrorCode error = | 
|  | config_.ProcessPeerHello(msg, SERVER, &error_details); | 
|  | EXPECT_EQ(QUIC_INVALID_NEGOTIATED_VALUE, error); | 
|  | } | 
|  |  | 
|  | TEST_F(QuicConfigTest, InvalidFlowControlWindow) { | 
|  | // QuicConfig should not accept an invalid flow control window to send to the | 
|  | // peer: the receive window must be at least the default of 16 Kb. | 
|  | QuicConfig config; | 
|  | const uint64 kInvalidWindow = kMinimumFlowControlSendWindow - 1; | 
|  | EXPECT_DFATAL(config.SetInitialStreamFlowControlWindowToSend(kInvalidWindow), | 
|  | "Initial stream flow control receive window"); | 
|  |  | 
|  | EXPECT_EQ(kMinimumFlowControlSendWindow, | 
|  | config.GetInitialStreamFlowControlWindowToSend()); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  | }  // namespace test | 
|  | }  // namespace net |