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/quic/quic_session.h" 6 7 #include <set> 8 #include <vector> 9 10 #include "base/containers/hash_tables.h" 11 #include "net/quic/crypto/crypto_handshake.h" 12 #include "net/quic/quic_connection.h" 13 #include "net/quic/quic_protocol.h" 14 #include "net/quic/test_tools/quic_connection_peer.h" 15 #include "net/quic/test_tools/quic_test_utils.h" 16 #include "net/spdy/spdy_framer.h" 17 #include "testing/gmock/include/gmock/gmock.h" 18 #include "testing/gtest/include/gtest/gtest.h" 19 20 using base::hash_map; 21 using std::set; 22 using std::vector; 23 using testing::_; 24 using testing::InSequence; 25 26 namespace net { 27 namespace test { 28 namespace { 29 30 class TestCryptoStream : public QuicCryptoStream { 31 public: 32 explicit TestCryptoStream(QuicSession* session) 33 : QuicCryptoStream(session) { 34 } 35 36 virtual void OnHandshakeMessage( 37 const CryptoHandshakeMessage& message) OVERRIDE { 38 encryption_established_ = true; 39 handshake_confirmed_ = true; 40 CryptoHandshakeMessage msg; 41 string error_details; 42 session()->config()->ToHandshakeMessage(&msg); 43 const QuicErrorCode error = session()->config()->ProcessClientHello( 44 msg, &error_details); 45 EXPECT_EQ(QUIC_NO_ERROR, error); 46 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); 47 } 48 }; 49 50 class TestStream : public ReliableQuicStream { 51 public: 52 TestStream(QuicStreamId id, QuicSession* session) 53 : ReliableQuicStream(id, session) { 54 } 55 56 using ReliableQuicStream::CloseWriteSide; 57 58 virtual uint32 ProcessData(const char* data, uint32 data_len) { 59 return data_len; 60 } 61 62 MOCK_METHOD0(OnCanWrite, void()); 63 }; 64 65 class TestSession : public QuicSession { 66 public: 67 TestSession(QuicConnection* connection, bool is_server) 68 : QuicSession(connection, DefaultQuicConfig(), is_server), 69 crypto_stream_(this) { 70 } 71 72 virtual QuicCryptoStream* GetCryptoStream() OVERRIDE { 73 return &crypto_stream_; 74 } 75 76 virtual TestStream* CreateOutgoingReliableStream() OVERRIDE { 77 TestStream* stream = new TestStream(GetNextStreamId(), this); 78 ActivateStream(stream); 79 return stream; 80 } 81 82 virtual TestStream* CreateIncomingReliableStream(QuicStreamId id) OVERRIDE { 83 return new TestStream(id, this); 84 } 85 86 bool IsClosedStream(QuicStreamId id) { 87 return QuicSession::IsClosedStream(id); 88 } 89 90 ReliableQuicStream* GetIncomingReliableStream(QuicStreamId stream_id) { 91 return QuicSession::GetIncomingReliableStream(stream_id); 92 } 93 94 // Helper method for gmock 95 void MarkTwoWriteBlocked() { 96 this->MarkWriteBlocked(2); 97 } 98 99 TestCryptoStream crypto_stream_; 100 }; 101 102 class QuicSessionTest : public ::testing::Test { 103 protected: 104 QuicSessionTest() 105 : guid_(1), 106 connection_(new MockConnection(guid_, IPEndPoint(), false)), 107 session_(connection_, true) { 108 } 109 110 void CheckClosedStreams() { 111 for (int i = kCryptoStreamId; i < 100; i++) { 112 if (closed_streams_.count(i) == 0) { 113 EXPECT_FALSE(session_.IsClosedStream(i)) << " stream id: " << i; 114 } else { 115 EXPECT_TRUE(session_.IsClosedStream(i)) << " stream id: " << i; 116 } 117 } 118 } 119 120 void CloseStream(QuicStreamId id) { 121 session_.CloseStream(id); 122 closed_streams_.insert(id); 123 } 124 125 QuicGuid guid_; 126 MockConnection* connection_; 127 TestSession session_; 128 QuicConnectionVisitorInterface* visitor_; 129 hash_map<QuicStreamId, ReliableQuicStream*>* streams_; 130 set<QuicStreamId> closed_streams_; 131 }; 132 133 TEST_F(QuicSessionTest, IsCryptoHandshakeConfirmed) { 134 EXPECT_FALSE(session_.IsCryptoHandshakeConfirmed()); 135 CryptoHandshakeMessage message; 136 session_.crypto_stream_.OnHandshakeMessage(message); 137 EXPECT_TRUE(session_.IsCryptoHandshakeConfirmed()); 138 } 139 140 TEST_F(QuicSessionTest, IsClosedStreamDefault) { 141 // Ensure that no streams are initially closed. 142 for (int i = kCryptoStreamId; i < 100; i++) { 143 EXPECT_FALSE(session_.IsClosedStream(i)); 144 } 145 } 146 147 TEST_F(QuicSessionTest, IsClosedStreamLocallyCreated) { 148 TestStream* stream2 = session_.CreateOutgoingReliableStream(); 149 EXPECT_EQ(2u, stream2->id()); 150 TestStream* stream4 = session_.CreateOutgoingReliableStream(); 151 EXPECT_EQ(4u, stream4->id()); 152 153 CheckClosedStreams(); 154 CloseStream(4); 155 CheckClosedStreams(); 156 CloseStream(2); 157 CheckClosedStreams(); 158 } 159 160 TEST_F(QuicSessionTest, IsClosedStreamPeerCreated) { 161 session_.GetIncomingReliableStream(3); 162 session_.GetIncomingReliableStream(5); 163 164 CheckClosedStreams(); 165 CloseStream(3); 166 CheckClosedStreams(); 167 CloseStream(5); 168 // Create stream id 9, and implicitly 7 169 session_.GetIncomingReliableStream(9); 170 CheckClosedStreams(); 171 // Close 9, but make sure 7 is still not closed 172 CloseStream(9); 173 CheckClosedStreams(); 174 } 175 176 TEST_F(QuicSessionTest, StreamIdTooLarge) { 177 session_.GetIncomingReliableStream(3); 178 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_STREAM_ID)); 179 session_.GetIncomingReliableStream(105); 180 } 181 182 TEST_F(QuicSessionTest, DecompressionError) { 183 ReliableQuicStream* stream = session_.GetIncomingReliableStream(3); 184 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_DECOMPRESSION_FAILURE)); 185 const char data[] = 186 "\1\0\0\0" // headers id 187 "\0\0\0\4" // length 188 "abcd"; // invalid compressed data 189 stream->ProcessRawData(data, arraysize(data)); 190 } 191 192 TEST_F(QuicSessionTest, OnCanWrite) { 193 TestStream* stream2 = session_.CreateOutgoingReliableStream(); 194 TestStream* stream4 = session_.CreateOutgoingReliableStream(); 195 TestStream* stream6 = session_.CreateOutgoingReliableStream(); 196 197 session_.MarkWriteBlocked(2); 198 session_.MarkWriteBlocked(6); 199 session_.MarkWriteBlocked(4); 200 201 InSequence s; 202 EXPECT_CALL(*stream2, OnCanWrite()).WillOnce( 203 // Reregister, to test the loop limit. 204 testing::InvokeWithoutArgs(&session_, &TestSession::MarkTwoWriteBlocked)); 205 EXPECT_CALL(*stream6, OnCanWrite()); 206 EXPECT_CALL(*stream4, OnCanWrite()); 207 208 EXPECT_FALSE(session_.OnCanWrite()); 209 } 210 211 TEST_F(QuicSessionTest, OnCanWriteWithClosedStream) { 212 TestStream* stream2 = session_.CreateOutgoingReliableStream(); 213 TestStream* stream4 = session_.CreateOutgoingReliableStream(); 214 session_.CreateOutgoingReliableStream(); // stream 6 215 216 session_.MarkWriteBlocked(2); 217 session_.MarkWriteBlocked(6); 218 session_.MarkWriteBlocked(4); 219 CloseStream(6); 220 221 InSequence s; 222 EXPECT_CALL(*stream2, OnCanWrite()); 223 EXPECT_CALL(*stream4, OnCanWrite()); 224 EXPECT_TRUE(session_.OnCanWrite()); 225 } 226 227 // Regression test for http://crbug.com/248737 228 TEST_F(QuicSessionTest, OutOfOrderHeaders) { 229 QuicSpdyCompressor compressor; 230 SpdyHeaderBlock headers; 231 headers[":host"] = "www.google.com"; 232 headers[":path"] = "/index.hml"; 233 headers[":scheme"] = "http"; 234 vector<QuicStreamFrame> frames; 235 QuicPacketHeader header; 236 header.public_header.guid = session_.guid(); 237 238 TestStream* stream2 = session_.CreateOutgoingReliableStream(); 239 TestStream* stream4 = session_.CreateOutgoingReliableStream(); 240 stream2->CloseWriteSide(); 241 stream4->CloseWriteSide(); 242 243 // Create frame with headers for stream2. 244 string compressed_headers1 = compressor.CompressHeaders(headers); 245 QuicStreamFrame frame1(stream2->id(), false, 0, compressed_headers1); 246 247 // Create frame with headers for stream4. 248 string compressed_headers2 = compressor.CompressHeaders(headers); 249 QuicStreamFrame frame2(stream4->id(), true, 0, compressed_headers2); 250 251 // Process the second frame first. This will cause the headers to 252 // be queued up and processed after the first frame is processed. 253 frames.push_back(frame2); 254 session_.OnPacket(IPEndPoint(), IPEndPoint(), header, frames); 255 256 // Process the first frame, and un-cork the buffered headers. 257 frames[0] = frame1; 258 session_.OnPacket(IPEndPoint(), IPEndPoint(), header, frames); 259 260 // Ensure that the streams actually close and we don't DCHECK. 261 session_.ConnectionClose(QUIC_CONNECTION_TIMED_OUT, true); 262 } 263 264 TEST_F(QuicSessionTest, SendGoAway) { 265 // After sending a GoAway, ensure new incoming streams cannot be created and 266 // result in a RST being sent. 267 EXPECT_CALL(*connection_, 268 SendGoAway(QUIC_PEER_GOING_AWAY, 0u, "Going Away.")); 269 session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away."); 270 EXPECT_TRUE(session_.goaway_sent()); 271 272 EXPECT_CALL(*connection_, SendRstStream(3u, QUIC_STREAM_PEER_GOING_AWAY)); 273 EXPECT_FALSE(session_.GetIncomingReliableStream(3u)); 274 } 275 276 TEST_F(QuicSessionTest, IncreasedTimeoutAfterCryptoHandshake) { 277 EXPECT_EQ(kDefaultInitialTimeoutSecs, 278 QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds()); 279 CryptoHandshakeMessage msg; 280 session_.crypto_stream_.OnHandshakeMessage(msg); 281 EXPECT_EQ(kDefaultTimeoutSecs, 282 QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds()); 283 } 284 285 } // namespace 286 } // namespace test 287 } // namespace net 288