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