quic_server_session_test.cc revision f2477e01787aa58f445919b809d89e252beef54f
1// Copyright 2013 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_server_session.h" 6 7 8#include "net/quic/crypto/quic_crypto_server_config.h" 9#include "net/quic/crypto/quic_random.h" 10#include "net/quic/quic_connection.h" 11#include "net/quic/test_tools/quic_connection_peer.h" 12#include "net/quic/test_tools/quic_test_utils.h" 13#include "net/quic/test_tools/reliable_quic_stream_peer.h" 14#include "net/tools/epoll_server/epoll_server.h" 15#include "net/tools/quic/quic_spdy_server_stream.h" 16#include "net/tools/quic/test_tools/quic_test_utils.h" 17#include "testing/gmock/include/gmock/gmock.h" 18#include "testing/gtest/include/gtest/gtest.h" 19 20using __gnu_cxx::vector; 21using net::test::MockConnection; 22using net::test::QuicConnectionPeer; 23using net::test::ReliableQuicStreamPeer; 24using testing::_; 25using testing::StrictMock; 26 27namespace net { 28namespace tools { 29namespace test { 30 31class QuicServerSessionPeer { 32 public: 33 static ReliableQuicStream* GetIncomingReliableStream( 34 QuicServerSession* s, QuicStreamId id) { 35 return s->GetIncomingReliableStream(id); 36 } 37 static ReliableQuicStream* GetStream(QuicServerSession* s, QuicStreamId id) { 38 return s->GetStream(id); 39 } 40}; 41 42class CloseOnDataStream : public ReliableQuicStream { 43 public: 44 CloseOnDataStream(QuicStreamId id, QuicSession* session) 45 : ReliableQuicStream(id, session) { 46 } 47 48 virtual bool OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE { 49 session()->MarkDecompressionBlocked(1, id()); 50 session()->CloseStream(id()); 51 return true; 52 } 53 54 virtual uint32 ProcessData(const char* data, uint32 data_len) OVERRIDE { 55 return 0; 56 } 57}; 58 59class TestQuicQuicServerSession : public QuicServerSession { 60 public: 61 TestQuicQuicServerSession(const QuicConfig& config, 62 QuicConnection* connection, 63 QuicSessionOwner* owner) 64 : QuicServerSession(config, connection, owner), 65 close_stream_on_data_(false) { 66 } 67 68 virtual ReliableQuicStream* CreateIncomingReliableStream( 69 QuicStreamId id) OVERRIDE { 70 if (!ShouldCreateIncomingReliableStream(id)) { 71 return NULL; 72 } 73 if (close_stream_on_data_) { 74 return new CloseOnDataStream(id, this); 75 } else { 76 return new QuicSpdyServerStream(id, this); 77 } 78 } 79 80 void CloseStreamOnData() { 81 close_stream_on_data_ = true; 82 } 83 84 private: 85 bool close_stream_on_data_; 86}; 87 88namespace { 89 90class QuicServerSessionTest : public ::testing::Test { 91 protected: 92 QuicServerSessionTest() 93 : guid_(1), 94 crypto_config_(QuicCryptoServerConfig::TESTING, 95 QuicRandom::GetInstance()) { 96 config_.SetDefaults(); 97 config_.set_max_streams_per_connection(3, 3); 98 99 connection_ = new MockConnection(guid_, IPEndPoint(), 0, &eps_, true); 100 session_.reset(new TestQuicQuicServerSession( 101 config_, connection_, &owner_)); 102 session_->InitializeSession(crypto_config_); 103 visitor_ = QuicConnectionPeer::GetVisitor(connection_); 104 } 105 106 void MarkHeadersReadForStream(QuicStreamId id) { 107 ReliableQuicStream* stream = QuicServerSessionPeer::GetStream( 108 session_.get(), id); 109 ASSERT_TRUE(stream != NULL); 110 ReliableQuicStreamPeer::SetHeadersDecompressed(stream, true); 111 } 112 113 QuicGuid guid_; 114 EpollServer eps_; 115 StrictMock<MockQuicSessionOwner> owner_; 116 MockConnection* connection_; 117 QuicConfig config_; 118 QuicCryptoServerConfig crypto_config_; 119 scoped_ptr<TestQuicQuicServerSession> session_; 120 QuicConnectionVisitorInterface* visitor_; 121}; 122 123TEST_F(QuicServerSessionTest, CloseStreamDueToReset) { 124 // Open a stream, then reset it. 125 // Send two bytes of payload to open it. 126 QuicStreamFrame data1(3, false, 0, MakeIOVector("HT")); 127 vector<QuicStreamFrame> frames; 128 frames.push_back(data1); 129 EXPECT_TRUE(visitor_->OnStreamFrames(frames)); 130 EXPECT_EQ(1u, session_->GetNumOpenStreams()); 131 132 // Pretend we got full headers, so we won't trigger the 'unrecoverable 133 // compression context' state. 134 MarkHeadersReadForStream(3); 135 136 // Send a reset. 137 QuicRstStreamFrame rst1(3, QUIC_STREAM_NO_ERROR); 138 visitor_->OnRstStream(rst1); 139 EXPECT_EQ(0u, session_->GetNumOpenStreams()); 140 141 // Send the same two bytes of payload in a new packet. 142 EXPECT_TRUE(visitor_->OnStreamFrames(frames)); 143 144 // The stream should not be re-opened. 145 EXPECT_EQ(0u, session_->GetNumOpenStreams()); 146} 147 148TEST_F(QuicServerSessionTest, NeverOpenStreamDueToReset) { 149 // Send a reset. 150 QuicRstStreamFrame rst1(3, QUIC_STREAM_NO_ERROR); 151 visitor_->OnRstStream(rst1); 152 EXPECT_EQ(0u, session_->GetNumOpenStreams()); 153 154 // Send two bytes of payload. 155 QuicStreamFrame data1(3, false, 0, MakeIOVector("HT")); 156 vector<QuicStreamFrame> frames; 157 frames.push_back(data1); 158 159 // When we get data for the closed stream, it implies the far side has 160 // compressed some headers. As a result we're going to bail due to 161 // unrecoverable compression context state. 162 EXPECT_CALL(*connection_, SendConnectionClose( 163 QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED)); 164 EXPECT_FALSE(visitor_->OnStreamFrames(frames)); 165 166 // The stream should never be opened, now that the reset is received. 167 EXPECT_EQ(0u, session_->GetNumOpenStreams()); 168} 169 170TEST_F(QuicServerSessionTest, GoOverPrematureClosedStreamLimit) { 171 QuicStreamFrame data1(3, false, 0, MakeIOVector("H")); 172 vector<QuicStreamFrame> frames; 173 frames.push_back(data1); 174 175 // Set up the stream such that it's open in OnPacket, but closes half way 176 // through while on the decompression blocked list. 177 session_->CloseStreamOnData(); 178 179 EXPECT_CALL(*connection_, SendConnectionClose( 180 QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED)); 181 EXPECT_FALSE(visitor_->OnStreamFrames(frames)); 182} 183 184TEST_F(QuicServerSessionTest, AcceptClosedStream) { 185 vector<QuicStreamFrame> frames; 186 // Send (empty) compressed headers followed by two bytes of data. 187 frames.push_back( 188 QuicStreamFrame(3, false, 0, MakeIOVector("\1\0\0\0\0\0\0\0HT"))); 189 frames.push_back( 190 QuicStreamFrame(5, false, 0, MakeIOVector("\2\0\0\0\0\0\0\0HT"))); 191 EXPECT_TRUE(visitor_->OnStreamFrames(frames)); 192 193 // Pretend we got full headers, so we won't trigger the 'unercoverable 194 // compression context' state. 195 MarkHeadersReadForStream(3); 196 197 // Send a reset. 198 QuicRstStreamFrame rst(3, QUIC_STREAM_NO_ERROR); 199 visitor_->OnRstStream(rst); 200 201 // If we were tracking, we'd probably want to reject this because it's data 202 // past the reset point of stream 3. As it's a closed stream we just drop the 203 // data on the floor, but accept the packet because it has data for stream 5. 204 frames.clear(); 205 frames.push_back(QuicStreamFrame(3, false, 2, MakeIOVector("TP"))); 206 frames.push_back(QuicStreamFrame(5, false, 2, MakeIOVector("TP"))); 207 EXPECT_TRUE(visitor_->OnStreamFrames(frames)); 208} 209 210TEST_F(QuicServerSessionTest, MaxNumConnections) { 211 EXPECT_EQ(0u, session_->GetNumOpenStreams()); 212 EXPECT_TRUE( 213 QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 3)); 214 EXPECT_TRUE( 215 QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 5)); 216 EXPECT_TRUE( 217 QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 7)); 218 EXPECT_FALSE( 219 QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 9)); 220} 221 222TEST_F(QuicServerSessionTest, MaxNumConnectionsImplicit) { 223 EXPECT_EQ(0u, session_->GetNumOpenStreams()); 224 EXPECT_TRUE( 225 QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 3)); 226 // Implicitly opens two more streams before 9. 227 EXPECT_FALSE( 228 QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 9)); 229} 230 231TEST_F(QuicServerSessionTest, GetEvenIncomingError) { 232 // Incoming streams on the server session must be odd. 233 EXPECT_EQ(NULL, 234 QuicServerSessionPeer::GetIncomingReliableStream( 235 session_.get(), 2)); 236} 237 238} // namespace 239} // namespace test 240} // namespace tools 241} // namespace net 242