| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/quic/quic_session.h" | 5 #include "net/quic/quic_session.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/containers/hash_tables.h" | 10 #include "base/containers/hash_tables.h" |
| 11 #include "net/quic/crypto/crypto_handshake.h" | 11 #include "net/quic/crypto/crypto_handshake.h" |
| 12 #include "net/quic/quic_connection.h" | 12 #include "net/quic/quic_connection.h" |
| 13 #include "net/quic/quic_protocol.h" | 13 #include "net/quic/quic_protocol.h" |
| 14 #include "net/quic/test_tools/quic_connection_peer.h" | 14 #include "net/quic/test_tools/quic_connection_peer.h" |
| 15 #include "net/quic/test_tools/quic_test_utils.h" | 15 #include "net/quic/test_tools/quic_test_utils.h" |
| 16 #include "net/quic/test_tools/reliable_quic_stream_peer.h" | 16 #include "net/quic/test_tools/reliable_quic_stream_peer.h" |
| 17 #include "net/spdy/spdy_framer.h" | 17 #include "net/spdy/spdy_framer.h" |
| 18 #include "testing/gmock/include/gmock/gmock.h" | 18 #include "testing/gmock/include/gmock/gmock.h" |
| 19 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
| 20 | 20 |
| 21 using base::hash_map; | 21 using base::hash_map; |
| 22 using std::set; | 22 using std::set; |
| 23 using std::vector; | 23 using std::vector; |
| 24 using testing::_; | 24 using testing::_; |
| 25 using testing::InSequence; | 25 using testing::InSequence; |
| 26 using testing::InvokeWithoutArgs; |
| 26 using testing::StrictMock; | 27 using testing::StrictMock; |
| 27 | 28 |
| 28 namespace net { | 29 namespace net { |
| 29 namespace test { | 30 namespace test { |
| 30 namespace { | 31 namespace { |
| 31 | 32 |
| 33 const QuicPriority kSomeMiddlePriority = 2; |
| 34 |
| 32 class TestCryptoStream : public QuicCryptoStream { | 35 class TestCryptoStream : public QuicCryptoStream { |
| 33 public: | 36 public: |
| 34 explicit TestCryptoStream(QuicSession* session) | 37 explicit TestCryptoStream(QuicSession* session) |
| 35 : QuicCryptoStream(session) { | 38 : QuicCryptoStream(session) { |
| 36 } | 39 } |
| 37 | 40 |
| 38 virtual void OnHandshakeMessage( | 41 virtual void OnHandshakeMessage( |
| 39 const CryptoHandshakeMessage& message) OVERRIDE { | 42 const CryptoHandshakeMessage& message) OVERRIDE { |
| 40 encryption_established_ = true; | 43 encryption_established_ = true; |
| 41 handshake_confirmed_ = true; | 44 handshake_confirmed_ = true; |
| 42 CryptoHandshakeMessage msg; | 45 CryptoHandshakeMessage msg; |
| 43 string error_details; | 46 string error_details; |
| 44 session()->config()->ToHandshakeMessage(&msg); | 47 session()->config()->ToHandshakeMessage(&msg); |
| 45 const QuicErrorCode error = session()->config()->ProcessClientHello( | 48 const QuicErrorCode error = session()->config()->ProcessClientHello( |
| 46 msg, &error_details); | 49 msg, &error_details); |
| 47 EXPECT_EQ(QUIC_NO_ERROR, error); | 50 EXPECT_EQ(QUIC_NO_ERROR, error); |
| 48 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); | 51 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); |
| 49 } | 52 } |
| 53 |
| 54 MOCK_METHOD0(OnCanWrite, void()); |
| 50 }; | 55 }; |
| 51 | 56 |
| 52 class TestStream : public ReliableQuicStream { | 57 class TestStream : public ReliableQuicStream { |
| 53 public: | 58 public: |
| 54 TestStream(QuicStreamId id, QuicSession* session) | 59 TestStream(QuicStreamId id, QuicSession* session) |
| 55 : ReliableQuicStream(id, session) { | 60 : ReliableQuicStream(id, session) { |
| 56 } | 61 } |
| 57 | 62 |
| 58 using ReliableQuicStream::CloseWriteSide; | 63 using ReliableQuicStream::CloseWriteSide; |
| 59 | 64 |
| 60 virtual uint32 ProcessData(const char* data, uint32 data_len) { | 65 virtual uint32 ProcessData(const char* data, uint32 data_len) { |
| 61 return data_len; | 66 return data_len; |
| 62 } | 67 } |
| 63 | 68 |
| 64 MOCK_METHOD0(OnCanWrite, void()); | 69 MOCK_METHOD0(OnCanWrite, void()); |
| 65 }; | 70 }; |
| 66 | 71 |
| 72 // Poor man's functor for use as callback in a mock. |
| 73 class StreamBlocker { |
| 74 public: |
| 75 StreamBlocker(QuicSession* session, QuicStreamId stream_id) |
| 76 : session_(session), |
| 77 stream_id_(stream_id) { |
| 78 } |
| 79 |
| 80 void MarkWriteBlocked() { |
| 81 session_->MarkWriteBlocked(stream_id_, kSomeMiddlePriority); |
| 82 } |
| 83 |
| 84 private: |
| 85 QuicSession* const session_; |
| 86 const QuicStreamId stream_id_; |
| 87 }; |
| 88 |
| 67 class TestSession : public QuicSession { | 89 class TestSession : public QuicSession { |
| 68 public: | 90 public: |
| 69 TestSession(QuicConnection* connection, bool is_server) | 91 TestSession(QuicConnection* connection, bool is_server) |
| 70 : QuicSession(connection, DefaultQuicConfig(), is_server), | 92 : QuicSession(connection, DefaultQuicConfig(), is_server), |
| 71 crypto_stream_(this) { | 93 crypto_stream_(this) { |
| 72 } | 94 } |
| 73 | 95 |
| 74 virtual QuicCryptoStream* GetCryptoStream() OVERRIDE { | 96 virtual TestCryptoStream* GetCryptoStream() OVERRIDE { |
| 75 return &crypto_stream_; | 97 return &crypto_stream_; |
| 76 } | 98 } |
| 77 | 99 |
| 78 virtual TestStream* CreateOutgoingReliableStream() OVERRIDE { | 100 virtual TestStream* CreateOutgoingReliableStream() OVERRIDE { |
| 79 TestStream* stream = new TestStream(GetNextStreamId(), this); | 101 TestStream* stream = new TestStream(GetNextStreamId(), this); |
| 80 ActivateStream(stream); | 102 ActivateStream(stream); |
| 81 return stream; | 103 return stream; |
| 82 } | 104 } |
| 83 | 105 |
| 84 virtual TestStream* CreateIncomingReliableStream(QuicStreamId id) OVERRIDE { | 106 virtual TestStream* CreateIncomingReliableStream(QuicStreamId id) OVERRIDE { |
| 85 return new TestStream(id, this); | 107 return new TestStream(id, this); |
| 86 } | 108 } |
| 87 | 109 |
| 88 bool IsClosedStream(QuicStreamId id) { | 110 bool IsClosedStream(QuicStreamId id) { |
| 89 return QuicSession::IsClosedStream(id); | 111 return QuicSession::IsClosedStream(id); |
| 90 } | 112 } |
| 91 | 113 |
| 92 ReliableQuicStream* GetIncomingReliableStream(QuicStreamId stream_id) { | 114 ReliableQuicStream* GetIncomingReliableStream(QuicStreamId stream_id) { |
| 93 return QuicSession::GetIncomingReliableStream(stream_id); | 115 return QuicSession::GetIncomingReliableStream(stream_id); |
| 94 } | 116 } |
| 95 | 117 |
| 96 // Helper method for gmock | |
| 97 void MarkTwoWriteBlocked() { | |
| 98 this->MarkWriteBlocked(2, 0); | |
| 99 } | |
| 100 | |
| 101 TestCryptoStream crypto_stream_; | 118 TestCryptoStream crypto_stream_; |
| 102 }; | 119 }; |
| 103 | 120 |
| 104 class QuicSessionTest : public ::testing::Test { | 121 class QuicSessionTest : public ::testing::Test { |
| 105 protected: | 122 protected: |
| 106 QuicSessionTest() | 123 QuicSessionTest() |
| 107 : guid_(1), | 124 : guid_(1), |
| 108 connection_(new MockConnection(guid_, IPEndPoint(), false)), | 125 connection_(new MockConnection(guid_, IPEndPoint(), false)), |
| 109 session_(connection_, true) { | 126 session_(connection_, true) { |
| 110 headers_[":host"] = "www.google.com"; | 127 headers_[":host"] = "www.google.com"; |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 233 "\0\0\0\4" // length | 250 "\0\0\0\4" // length |
| 234 "abcd"; // invalid compressed data | 251 "abcd"; // invalid compressed data |
| 235 stream->ProcessRawData(data, arraysize(data)); | 252 stream->ProcessRawData(data, arraysize(data)); |
| 236 } | 253 } |
| 237 | 254 |
| 238 TEST_F(QuicSessionTest, OnCanWrite) { | 255 TEST_F(QuicSessionTest, OnCanWrite) { |
| 239 TestStream* stream2 = session_.CreateOutgoingReliableStream(); | 256 TestStream* stream2 = session_.CreateOutgoingReliableStream(); |
| 240 TestStream* stream4 = session_.CreateOutgoingReliableStream(); | 257 TestStream* stream4 = session_.CreateOutgoingReliableStream(); |
| 241 TestStream* stream6 = session_.CreateOutgoingReliableStream(); | 258 TestStream* stream6 = session_.CreateOutgoingReliableStream(); |
| 242 | 259 |
| 243 session_.MarkWriteBlocked(2, 0); | 260 session_.MarkWriteBlocked(stream2->id(), kSomeMiddlePriority); |
| 244 session_.MarkWriteBlocked(6, 0); | 261 session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority); |
| 245 session_.MarkWriteBlocked(4, 0); | 262 session_.MarkWriteBlocked(stream4->id(), kSomeMiddlePriority); |
| 246 | 263 |
| 247 InSequence s; | 264 InSequence s; |
| 265 StreamBlocker stream2_blocker(&session_, stream2->id()); |
| 248 EXPECT_CALL(*stream2, OnCanWrite()).WillOnce( | 266 EXPECT_CALL(*stream2, OnCanWrite()).WillOnce( |
| 249 // Reregister, to test the loop limit. | 267 // Reregister, to test the loop limit. |
| 250 testing::InvokeWithoutArgs(&session_, &TestSession::MarkTwoWriteBlocked)); | 268 InvokeWithoutArgs(&stream2_blocker, &StreamBlocker::MarkWriteBlocked)); |
| 251 EXPECT_CALL(*stream6, OnCanWrite()); | 269 EXPECT_CALL(*stream6, OnCanWrite()); |
| 252 EXPECT_CALL(*stream4, OnCanWrite()); | 270 EXPECT_CALL(*stream4, OnCanWrite()); |
| 253 | 271 |
| 254 EXPECT_FALSE(session_.OnCanWrite()); | 272 EXPECT_FALSE(session_.OnCanWrite()); |
| 255 } | 273 } |
| 256 | 274 |
| 275 TEST_F(QuicSessionTest, BufferedHandshake) { |
| 276 EXPECT_FALSE(session_.HasPendingHandshake()); // Default value. |
| 277 |
| 278 // Test that blocking other streams does not change our status. |
| 279 TestStream* stream2 = session_.CreateOutgoingReliableStream(); |
| 280 StreamBlocker stream2_blocker(&session_, stream2->id()); |
| 281 stream2_blocker.MarkWriteBlocked(); |
| 282 EXPECT_FALSE(session_.HasPendingHandshake()); |
| 283 |
| 284 TestStream* stream3 = session_.CreateOutgoingReliableStream(); |
| 285 StreamBlocker stream3_blocker(&session_, stream3->id()); |
| 286 stream3_blocker.MarkWriteBlocked(); |
| 287 EXPECT_FALSE(session_.HasPendingHandshake()); |
| 288 |
| 289 // Blocking (due to buffering of) the Crypto stream is detected. |
| 290 session_.MarkWriteBlocked(kCryptoStreamId, kSomeMiddlePriority); |
| 291 EXPECT_TRUE(session_.HasPendingHandshake()); |
| 292 |
| 293 TestStream* stream4 = session_.CreateOutgoingReliableStream(); |
| 294 StreamBlocker stream4_blocker(&session_, stream4->id()); |
| 295 stream4_blocker.MarkWriteBlocked(); |
| 296 EXPECT_TRUE(session_.HasPendingHandshake()); |
| 297 |
| 298 InSequence s; |
| 299 // Force most streams to re-register, which is common scenario when we block |
| 300 // the Crypto stream, and only the crypto stream can "really" write. |
| 301 |
| 302 // Due to prioritization, we *should* be asked to write the crypto stream |
| 303 // first. |
| 304 // Don't re-register the crypto stream (which signals complete writing). |
| 305 TestCryptoStream* crypto_stream = session_.GetCryptoStream(); |
| 306 EXPECT_CALL(*crypto_stream, OnCanWrite()); |
| 307 |
| 308 // Re-register all other streams, to show they weren't able to proceed. |
| 309 EXPECT_CALL(*stream2, OnCanWrite()).WillOnce( |
| 310 InvokeWithoutArgs(&stream2_blocker, &StreamBlocker::MarkWriteBlocked)); |
| 311 |
| 312 EXPECT_CALL(*stream3, OnCanWrite()).WillOnce( |
| 313 InvokeWithoutArgs(&stream3_blocker, &StreamBlocker::MarkWriteBlocked)); |
| 314 |
| 315 EXPECT_CALL(*stream4, OnCanWrite()).WillOnce( |
| 316 InvokeWithoutArgs(&stream4_blocker, &StreamBlocker::MarkWriteBlocked)); |
| 317 |
| 318 EXPECT_FALSE(session_.OnCanWrite()); |
| 319 EXPECT_FALSE(session_.HasPendingHandshake()); // Crypto stream wrote. |
| 320 } |
| 321 |
| 257 TEST_F(QuicSessionTest, OnCanWriteWithClosedStream) { | 322 TEST_F(QuicSessionTest, OnCanWriteWithClosedStream) { |
| 258 TestStream* stream2 = session_.CreateOutgoingReliableStream(); | 323 TestStream* stream2 = session_.CreateOutgoingReliableStream(); |
| 259 TestStream* stream4 = session_.CreateOutgoingReliableStream(); | 324 TestStream* stream4 = session_.CreateOutgoingReliableStream(); |
| 260 session_.CreateOutgoingReliableStream(); // stream 6 | 325 TestStream* stream6 = session_.CreateOutgoingReliableStream(); |
| 261 | 326 |
| 262 session_.MarkWriteBlocked(2, 0); | 327 session_.MarkWriteBlocked(stream2->id(), kSomeMiddlePriority); |
| 263 session_.MarkWriteBlocked(6, 0); | 328 session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority); |
| 264 session_.MarkWriteBlocked(4, 0); | 329 session_.MarkWriteBlocked(stream4->id(), kSomeMiddlePriority); |
| 265 CloseStream(6); | 330 CloseStream(stream6->id()); |
| 266 | 331 |
| 267 InSequence s; | 332 InSequence s; |
| 268 EXPECT_CALL(*stream2, OnCanWrite()); | 333 EXPECT_CALL(*stream2, OnCanWrite()); |
| 269 EXPECT_CALL(*stream4, OnCanWrite()); | 334 EXPECT_CALL(*stream4, OnCanWrite()); |
| 270 EXPECT_TRUE(session_.OnCanWrite()); | 335 EXPECT_TRUE(session_.OnCanWrite()); |
| 271 } | 336 } |
| 272 | 337 |
| 273 // Regression test for http://crbug.com/248737 | 338 // Regression test for http://crbug.com/248737 |
| 274 TEST_F(QuicSessionTest, OutOfOrderHeaders) { | 339 TEST_F(QuicSessionTest, OutOfOrderHeaders) { |
| 275 QuicSpdyCompressor compressor; | 340 QuicSpdyCompressor compressor; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 286 string compressed_headers1 = compressor.CompressHeaders(headers_); | 351 string compressed_headers1 = compressor.CompressHeaders(headers_); |
| 287 QuicStreamFrame frame1(stream2->id(), false, 0, compressed_headers1); | 352 QuicStreamFrame frame1(stream2->id(), false, 0, compressed_headers1); |
| 288 | 353 |
| 289 // Create frame with headers for stream4. | 354 // Create frame with headers for stream4. |
| 290 string compressed_headers2 = compressor.CompressHeaders(headers_); | 355 string compressed_headers2 = compressor.CompressHeaders(headers_); |
| 291 QuicStreamFrame frame2(stream4->id(), true, 0, compressed_headers2); | 356 QuicStreamFrame frame2(stream4->id(), true, 0, compressed_headers2); |
| 292 | 357 |
| 293 // Process the second frame first. This will cause the headers to | 358 // Process the second frame first. This will cause the headers to |
| 294 // be queued up and processed after the first frame is processed. | 359 // be queued up and processed after the first frame is processed. |
| 295 frames.push_back(frame2); | 360 frames.push_back(frame2); |
| 296 session_.OnPacket(IPEndPoint(), IPEndPoint(), header, frames); | 361 session_.OnStreamFrames(frames); |
| 297 | 362 |
| 298 // Process the first frame, and un-cork the buffered headers. | 363 // Process the first frame, and un-cork the buffered headers. |
| 299 frames[0] = frame1; | 364 frames[0] = frame1; |
| 300 session_.OnPacket(IPEndPoint(), IPEndPoint(), header, frames); | 365 session_.OnStreamFrames(frames); |
| 301 | 366 |
| 302 // Ensure that the streams actually close and we don't DCHECK. | 367 // Ensure that the streams actually close and we don't DCHECK. |
| 303 connection_->CloseConnection(QUIC_CONNECTION_TIMED_OUT, true); | 368 connection_->CloseConnection(QUIC_CONNECTION_TIMED_OUT, true); |
| 304 } | 369 } |
| 305 | 370 |
| 306 TEST_F(QuicSessionTest, SendGoAway) { | 371 TEST_F(QuicSessionTest, SendGoAway) { |
| 307 // After sending a GoAway, ensure new incoming streams cannot be created and | 372 // After sending a GoAway, ensure new incoming streams cannot be created and |
| 308 // result in a RST being sent. | 373 // result in a RST being sent. |
| 309 EXPECT_CALL(*connection_, | 374 EXPECT_CALL(*connection_, |
| 310 SendGoAway(QUIC_PEER_GOING_AWAY, 0u, "Going Away.")); | 375 SendGoAway(QUIC_PEER_GOING_AWAY, 0u, "Going Away.")); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 349 | 414 |
| 350 // Create frame with headers for stream2. | 415 // Create frame with headers for stream2. |
| 351 QuicSpdyCompressor compressor; | 416 QuicSpdyCompressor compressor; |
| 352 string compressed_headers1 = compressor.CompressHeaders(headers_); | 417 string compressed_headers1 = compressor.CompressHeaders(headers_); |
| 353 QuicStreamFrame frame1(stream3->id(), false, 0, compressed_headers1); | 418 QuicStreamFrame frame1(stream3->id(), false, 0, compressed_headers1); |
| 354 | 419 |
| 355 // Process the second frame first. This will cause the headers to | 420 // Process the second frame first. This will cause the headers to |
| 356 // be queued up and processed after the first frame is processed. | 421 // be queued up and processed after the first frame is processed. |
| 357 frames.push_back(frame1); | 422 frames.push_back(frame1); |
| 358 EXPECT_FALSE(stream3->headers_decompressed()); | 423 EXPECT_FALSE(stream3->headers_decompressed()); |
| 359 session.OnPacket(IPEndPoint(), IPEndPoint(), header, frames); | 424 |
| 425 session.OnStreamFrames(frames); |
| 360 EXPECT_EQ(1u, session.GetNumOpenStreams()); | 426 EXPECT_EQ(1u, session.GetNumOpenStreams()); |
| 361 | 427 |
| 362 EXPECT_TRUE(connection->connected()); | 428 EXPECT_TRUE(connection->connected()); |
| 363 } | 429 } |
| 364 | 430 |
| 365 TEST_F(QuicSessionTest, ZombieStreamConnectionClose) { | 431 TEST_F(QuicSessionTest, ZombieStreamConnectionClose) { |
| 366 StrictMock<MockConnection>* connection = | 432 StrictMock<MockConnection>* connection = |
| 367 new StrictMock<MockConnection>(guid_, IPEndPoint(), false); | 433 new StrictMock<MockConnection>(guid_, IPEndPoint(), false); |
| 368 TestSession session(connection, /*is_server=*/ false); | 434 TestSession session(connection, /*is_server=*/ false); |
| 369 | 435 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 383 EXPECT_EQ(1u, session.GetNumOpenStreams()); | 449 EXPECT_EQ(1u, session.GetNumOpenStreams()); |
| 384 | 450 |
| 385 connection->CloseConnection(QUIC_CONNECTION_TIMED_OUT, false); | 451 connection->CloseConnection(QUIC_CONNECTION_TIMED_OUT, false); |
| 386 | 452 |
| 387 EXPECT_EQ(0u, session.GetNumOpenStreams()); | 453 EXPECT_EQ(0u, session.GetNumOpenStreams()); |
| 388 } | 454 } |
| 389 | 455 |
| 390 } // namespace | 456 } // namespace |
| 391 } // namespace test | 457 } // namespace test |
| 392 } // namespace net | 458 } // namespace net |
| OLD | NEW |