| 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/basictypes.h" | 10 #include "base/basictypes.h" |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 211 EXPECT_FALSE(session_.IsClosedStream(5)); | 211 EXPECT_FALSE(session_.IsClosedStream(5)); |
| 212 ASSERT_TRUE(session_.GetIncomingDataStream(5) != NULL); | 212 ASSERT_TRUE(session_.GetIncomingDataStream(5) != NULL); |
| 213 ASSERT_TRUE(session_.GetIncomingDataStream(3) != NULL); | 213 ASSERT_TRUE(session_.GetIncomingDataStream(3) != NULL); |
| 214 } | 214 } |
| 215 | 215 |
| 216 TEST_P(QuicSessionTest, IsClosedStreamLocallyCreated) { | 216 TEST_P(QuicSessionTest, IsClosedStreamLocallyCreated) { |
| 217 TestStream* stream2 = session_.CreateOutgoingDataStream(); | 217 TestStream* stream2 = session_.CreateOutgoingDataStream(); |
| 218 EXPECT_EQ(2u, stream2->id()); | 218 EXPECT_EQ(2u, stream2->id()); |
| 219 TestStream* stream4 = session_.CreateOutgoingDataStream(); | 219 TestStream* stream4 = session_.CreateOutgoingDataStream(); |
| 220 EXPECT_EQ(4u, stream4->id()); | 220 EXPECT_EQ(4u, stream4->id()); |
| 221 if (version() <= QUIC_VERSION_12) { | |
| 222 QuicDataStreamPeer::SetHeadersDecompressed(stream2, true); | |
| 223 QuicDataStreamPeer::SetHeadersDecompressed(stream4, true); | |
| 224 } | |
| 225 | 221 |
| 226 CheckClosedStreams(); | 222 CheckClosedStreams(); |
| 227 CloseStream(4); | 223 CloseStream(4); |
| 228 CheckClosedStreams(); | 224 CheckClosedStreams(); |
| 229 CloseStream(2); | 225 CloseStream(2); |
| 230 CheckClosedStreams(); | 226 CheckClosedStreams(); |
| 231 } | 227 } |
| 232 | 228 |
| 233 TEST_P(QuicSessionTest, IsClosedStreamPeerCreated) { | 229 TEST_P(QuicSessionTest, IsClosedStreamPeerCreated) { |
| 234 QuicStreamId stream_id1 = version() > QUIC_VERSION_12 ? 5 : 3; | 230 QuicStreamId stream_id1 = 5; |
| 235 QuicStreamId stream_id2 = stream_id1 + 2; | 231 QuicStreamId stream_id2 = stream_id1 + 2; |
| 236 QuicDataStream* stream1 = session_.GetIncomingDataStream(stream_id1); | 232 QuicDataStream* stream1 = session_.GetIncomingDataStream(stream_id1); |
| 237 QuicDataStreamPeer::SetHeadersDecompressed(stream1, true); | 233 QuicDataStreamPeer::SetHeadersDecompressed(stream1, true); |
| 238 QuicDataStream* stream2 = session_.GetIncomingDataStream(stream_id2); | 234 QuicDataStream* stream2 = session_.GetIncomingDataStream(stream_id2); |
| 239 QuicDataStreamPeer::SetHeadersDecompressed(stream2, true); | 235 QuicDataStreamPeer::SetHeadersDecompressed(stream2, true); |
| 240 | 236 |
| 241 CheckClosedStreams(); | 237 CheckClosedStreams(); |
| 242 CloseStream(stream_id1); | 238 CloseStream(stream_id1); |
| 243 CheckClosedStreams(); | 239 CheckClosedStreams(); |
| 244 CloseStream(stream_id2); | 240 CloseStream(stream_id2); |
| 245 // Create a stream explicitly, and another implicitly. | 241 // Create a stream explicitly, and another implicitly. |
| 246 QuicDataStream* stream3 = session_.GetIncomingDataStream(stream_id2 + 4); | 242 QuicDataStream* stream3 = session_.GetIncomingDataStream(stream_id2 + 4); |
| 247 QuicDataStreamPeer::SetHeadersDecompressed(stream3, true); | 243 QuicDataStreamPeer::SetHeadersDecompressed(stream3, true); |
| 248 CheckClosedStreams(); | 244 CheckClosedStreams(); |
| 249 // Close one, but make sure the other is still not closed | 245 // Close one, but make sure the other is still not closed |
| 250 CloseStream(stream3->id()); | 246 CloseStream(stream3->id()); |
| 251 CheckClosedStreams(); | 247 CheckClosedStreams(); |
| 252 } | 248 } |
| 253 | 249 |
| 254 TEST_P(QuicSessionTest, StreamIdTooLarge) { | 250 TEST_P(QuicSessionTest, StreamIdTooLarge) { |
| 255 QuicStreamId stream_id = version() > QUIC_VERSION_12 ? 5 : 3; | 251 QuicStreamId stream_id = 5; |
| 256 session_.GetIncomingDataStream(stream_id); | 252 session_.GetIncomingDataStream(stream_id); |
| 257 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_STREAM_ID)); | 253 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_STREAM_ID)); |
| 258 session_.GetIncomingDataStream(stream_id + 102); | 254 session_.GetIncomingDataStream(stream_id + 102); |
| 259 } | 255 } |
| 260 | 256 |
| 261 TEST_P(QuicSessionTest, DecompressionError) { | 257 TEST_P(QuicSessionTest, DecompressionError) { |
| 262 if (version() > QUIC_VERSION_12) { | 258 QuicHeadersStream* stream = QuicSessionPeer::GetHeadersStream(&session_); |
| 263 QuicHeadersStream* stream = QuicSessionPeer::GetHeadersStream(&session_); | 259 const unsigned char data[] = { |
| 264 const unsigned char data[] = { | 260 0x80, 0x03, 0x00, 0x01, // SPDY/3 SYN_STREAM frame |
| 265 0x80, 0x03, 0x00, 0x01, // SPDY/3 SYN_STREAM frame | 261 0x00, 0x00, 0x00, 0x25, // flags/length |
| 266 0x00, 0x00, 0x00, 0x25, // flags/length | 262 0x00, 0x00, 0x00, 0x05, // stream id |
| 267 0x00, 0x00, 0x00, 0x05, // stream id | 263 0x00, 0x00, 0x00, 0x00, // associated stream id |
| 268 0x00, 0x00, 0x00, 0x00, // associated stream id | 264 0x00, 0x00, |
| 269 0x00, 0x00, | 265 'a', 'b', 'c', 'd' // invalid compressed data |
| 270 'a', 'b', 'c', 'd' // invalid compressed data | 266 }; |
| 271 }; | 267 EXPECT_CALL(*connection_, |
| 272 EXPECT_CALL(*connection_, | 268 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA, |
| 273 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA, | 269 "SPDY framing error.")); |
| 274 "SPDY framing error.")); | 270 stream->ProcessRawData(reinterpret_cast<const char*>(data), |
| 275 stream->ProcessRawData(reinterpret_cast<const char*>(data), | 271 arraysize(data)); |
| 276 arraysize(data)); | |
| 277 } else { | |
| 278 ReliableQuicStream* stream = session_.GetIncomingDataStream(3); | |
| 279 const char data[] = | |
| 280 "\0\0\0\0" // priority | |
| 281 "\1\0\0\0" // headers id | |
| 282 "\0\0\0\4" // length | |
| 283 "abcd"; // invalid compressed data | |
| 284 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_DECOMPRESSION_FAILURE)); | |
| 285 stream->ProcessRawData(data, arraysize(data)); | |
| 286 } | |
| 287 } | 272 } |
| 288 | 273 |
| 289 TEST_P(QuicSessionTest, DebugDFatalIfMarkingClosedStreamWriteBlocked) { | 274 TEST_P(QuicSessionTest, DebugDFatalIfMarkingClosedStreamWriteBlocked) { |
| 290 TestStream* stream2 = session_.CreateOutgoingDataStream(); | 275 TestStream* stream2 = session_.CreateOutgoingDataStream(); |
| 291 // Close the stream. | 276 // Close the stream. |
| 292 stream2->Reset(QUIC_BAD_APPLICATION_PAYLOAD); | 277 stream2->Reset(QUIC_BAD_APPLICATION_PAYLOAD); |
| 293 // TODO(rtenneti): enable when chromium supports EXPECT_DEBUG_DFATAL. | 278 // TODO(rtenneti): enable when chromium supports EXPECT_DEBUG_DFATAL. |
| 294 /* | 279 /* |
| 295 QuicStreamId kClosedStreamId = stream2->id(); | 280 QuicStreamId kClosedStreamId = stream2->id(); |
| 296 EXPECT_DEBUG_DFATAL( | 281 EXPECT_DEBUG_DFATAL( |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 434 session_.MarkWriteBlocked(stream4->id(), kSomeMiddlePriority); | 419 session_.MarkWriteBlocked(stream4->id(), kSomeMiddlePriority); |
| 435 CloseStream(stream6->id()); | 420 CloseStream(stream6->id()); |
| 436 | 421 |
| 437 InSequence s; | 422 InSequence s; |
| 438 EXPECT_CALL(*stream2, OnCanWrite()); | 423 EXPECT_CALL(*stream2, OnCanWrite()); |
| 439 EXPECT_CALL(*stream4, OnCanWrite()); | 424 EXPECT_CALL(*stream4, OnCanWrite()); |
| 440 session_.OnCanWrite(); | 425 session_.OnCanWrite(); |
| 441 EXPECT_FALSE(session_.HasPendingWrites()); | 426 EXPECT_FALSE(session_.HasPendingWrites()); |
| 442 } | 427 } |
| 443 | 428 |
| 444 // Regression test for http://crbug.com/248737 | |
| 445 TEST_P(QuicSessionTest, OutOfOrderHeaders) { | |
| 446 QuicSpdyCompressor compressor; | |
| 447 vector<QuicStreamFrame> frames; | |
| 448 QuicPacketHeader header; | |
| 449 header.public_header.connection_id = session_.connection_id(); | |
| 450 | |
| 451 TestStream* stream2 = session_.CreateOutgoingDataStream(); | |
| 452 TestStream* stream4 = session_.CreateOutgoingDataStream(); | |
| 453 stream2->CloseWriteSide(); | |
| 454 stream4->CloseWriteSide(); | |
| 455 | |
| 456 // Create frame with headers for stream2. | |
| 457 string compressed_headers1 = compressor.CompressHeaders(headers_); | |
| 458 QuicStreamFrame frame1( | |
| 459 stream2->id(), false, 0, MakeIOVector(compressed_headers1)); | |
| 460 | |
| 461 // Create frame with headers for stream4. | |
| 462 string compressed_headers2 = compressor.CompressHeaders(headers_); | |
| 463 QuicStreamFrame frame2( | |
| 464 stream4->id(), true, 0, MakeIOVector(compressed_headers2)); | |
| 465 | |
| 466 // Process the second frame first. This will cause the headers to | |
| 467 // be queued up and processed after the first frame is processed. | |
| 468 frames.push_back(frame2); | |
| 469 session_.OnStreamFrames(frames); | |
| 470 | |
| 471 // Process the first frame, and un-cork the buffered headers. | |
| 472 frames[0] = frame1; | |
| 473 session_.OnStreamFrames(frames); | |
| 474 | |
| 475 // Ensure that the streams actually close and we don't DCHECK. | |
| 476 connection_->CloseConnection(QUIC_CONNECTION_TIMED_OUT, true); | |
| 477 } | |
| 478 | |
| 479 TEST_P(QuicSessionTest, SendGoAway) { | 429 TEST_P(QuicSessionTest, SendGoAway) { |
| 480 // After sending a GoAway, ensure new incoming streams cannot be created and | 430 // After sending a GoAway, ensure new incoming streams cannot be created and |
| 481 // result in a RST being sent. | 431 // result in a RST being sent. |
| 482 EXPECT_CALL(*connection_, | 432 EXPECT_CALL(*connection_, |
| 483 SendGoAway(QUIC_PEER_GOING_AWAY, 0u, "Going Away.")); | 433 SendGoAway(QUIC_PEER_GOING_AWAY, 0u, "Going Away.")); |
| 484 session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away."); | 434 session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away."); |
| 485 EXPECT_TRUE(session_.goaway_sent()); | 435 EXPECT_TRUE(session_.goaway_sent()); |
| 486 | 436 |
| 487 EXPECT_CALL(*connection_, SendRstStream(3u, QUIC_STREAM_PEER_GOING_AWAY, 0)); | 437 EXPECT_CALL(*connection_, SendRstStream(3u, QUIC_STREAM_PEER_GOING_AWAY, 0)); |
| 488 EXPECT_FALSE(session_.GetIncomingDataStream(3u)); | 438 EXPECT_FALSE(session_.GetIncomingDataStream(3u)); |
| 489 } | 439 } |
| 490 | 440 |
| 491 TEST_P(QuicSessionTest, IncreasedTimeoutAfterCryptoHandshake) { | 441 TEST_P(QuicSessionTest, IncreasedTimeoutAfterCryptoHandshake) { |
| 492 EXPECT_EQ(kDefaultInitialTimeoutSecs, | 442 EXPECT_EQ(kDefaultInitialTimeoutSecs, |
| 493 QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds()); | 443 QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds()); |
| 494 CryptoHandshakeMessage msg; | 444 CryptoHandshakeMessage msg; |
| 495 session_.crypto_stream_.OnHandshakeMessage(msg); | 445 session_.crypto_stream_.OnHandshakeMessage(msg); |
| 496 EXPECT_EQ(kDefaultTimeoutSecs, | 446 EXPECT_EQ(kDefaultTimeoutSecs, |
| 497 QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds()); | 447 QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds()); |
| 498 } | 448 } |
| 499 | 449 |
| 500 TEST_P(QuicSessionTest, ZombieStream) { | |
| 501 QuicStreamId stream_id1 = version() > QUIC_VERSION_12 ? 5 : 3; | |
| 502 QuicStreamId stream_id2 = stream_id1 + 2; | |
| 503 StrictMock<MockConnection>* connection = | |
| 504 new StrictMock<MockConnection>(false, SupportedVersions(version())); | |
| 505 TestSession session(connection); | |
| 506 | |
| 507 TestStream* stream1 = session.CreateOutgoingDataStream(); | |
| 508 EXPECT_EQ(stream_id1, stream1->id()); | |
| 509 TestStream* stream2 = session.CreateOutgoingDataStream(); | |
| 510 EXPECT_EQ(stream_id2, stream2->id()); | |
| 511 EXPECT_EQ(2u, session.GetNumOpenStreams()); | |
| 512 | |
| 513 // Reset the stream, but since the headers have not been decompressed | |
| 514 // it will become a zombie and will continue to process data | |
| 515 // until the headers are decompressed. | |
| 516 EXPECT_CALL(*connection, SendRstStream(stream_id1, QUIC_STREAM_CANCELLED, 0)); | |
| 517 session.SendRstStream(stream_id1, QUIC_STREAM_CANCELLED, 0); | |
| 518 | |
| 519 EXPECT_EQ(1u, session.GetNumOpenStreams()); | |
| 520 | |
| 521 vector<QuicStreamFrame> frames; | |
| 522 QuicPacketHeader header; | |
| 523 header.public_header.connection_id = session_.connection_id(); | |
| 524 | |
| 525 // Create frame with headers for stream2. | |
| 526 QuicSpdyCompressor compressor; | |
| 527 string compressed_headers1 = compressor.CompressHeaders(headers_); | |
| 528 QuicStreamFrame frame1( | |
| 529 stream1->id(), false, 0, MakeIOVector(compressed_headers1)); | |
| 530 | |
| 531 // Process the second frame first. This will cause the headers to | |
| 532 // be queued up and processed after the first frame is processed. | |
| 533 frames.push_back(frame1); | |
| 534 EXPECT_FALSE(stream1->headers_decompressed()); | |
| 535 | |
| 536 session.OnStreamFrames(frames); | |
| 537 EXPECT_EQ(1u, session.GetNumOpenStreams()); | |
| 538 | |
| 539 EXPECT_TRUE(connection->connected()); | |
| 540 } | |
| 541 | |
| 542 TEST_P(QuicSessionTest, ZombieStreamConnectionClose) { | |
| 543 QuicStreamId stream_id1 = version() > QUIC_VERSION_12 ? 5 : 3; | |
| 544 QuicStreamId stream_id2 = stream_id1 + 2; | |
| 545 StrictMock<MockConnection>* connection = | |
| 546 new StrictMock<MockConnection>(false, SupportedVersions(version())); | |
| 547 TestSession session(connection); | |
| 548 | |
| 549 TestStream* stream1 = session.CreateOutgoingDataStream(); | |
| 550 EXPECT_EQ(stream_id1, stream1->id()); | |
| 551 TestStream* stream2 = session.CreateOutgoingDataStream(); | |
| 552 EXPECT_EQ(stream_id2, stream2->id()); | |
| 553 EXPECT_EQ(2u, session.GetNumOpenStreams()); | |
| 554 | |
| 555 stream1->CloseWriteSide(); | |
| 556 // Reset the stream, but since the headers have not been decompressed | |
| 557 // it will become a zombie and will continue to process data | |
| 558 // until the headers are decompressed. | |
| 559 EXPECT_CALL(*connection, SendRstStream(stream_id1, QUIC_STREAM_CANCELLED, 0)); | |
| 560 session.SendRstStream(stream_id1, QUIC_STREAM_CANCELLED, 0); | |
| 561 | |
| 562 EXPECT_EQ(1u, session.GetNumOpenStreams()); | |
| 563 | |
| 564 if (GetParam() > QUIC_VERSION_13) { | |
| 565 // Stream 2 will send a RST during normal termination. | |
| 566 EXPECT_CALL(*connection, | |
| 567 SendRstStream(stream_id2, QUIC_STREAM_NO_ERROR, 0)); | |
| 568 } | |
| 569 connection->CloseConnection(QUIC_CONNECTION_TIMED_OUT, false); | |
| 570 | |
| 571 EXPECT_EQ(0u, session.GetNumOpenStreams()); | |
| 572 } | |
| 573 | |
| 574 TEST_P(QuicSessionTest, RstStreamBeforeHeadersDecompressed) { | 450 TEST_P(QuicSessionTest, RstStreamBeforeHeadersDecompressed) { |
| 575 QuicStreamId stream_id1 = version() > QUIC_VERSION_12 ? 5 : 3; | 451 QuicStreamId stream_id1 = 5; |
| 576 // Send two bytes of payload. | 452 // Send two bytes of payload. |
| 577 QuicStreamFrame data1(stream_id1, false, 0, MakeIOVector("HT")); | 453 QuicStreamFrame data1(stream_id1, false, 0, MakeIOVector("HT")); |
| 578 vector<QuicStreamFrame> frames; | 454 vector<QuicStreamFrame> frames; |
| 579 frames.push_back(data1); | 455 frames.push_back(data1); |
| 580 EXPECT_TRUE(session_.OnStreamFrames(frames)); | 456 EXPECT_TRUE(session_.OnStreamFrames(frames)); |
| 581 EXPECT_EQ(1u, session_.GetNumOpenStreams()); | 457 EXPECT_EQ(1u, session_.GetNumOpenStreams()); |
| 582 | 458 |
| 583 if (version() <= QUIC_VERSION_12) { | |
| 584 // Send a reset before the headers have been decompressed. This causes | |
| 585 // an unrecoverable compression context state. | |
| 586 EXPECT_CALL(*connection_, SendConnectionClose( | |
| 587 QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED)); | |
| 588 } | |
| 589 | |
| 590 QuicRstStreamFrame rst1(stream_id1, QUIC_STREAM_NO_ERROR, 0); | 459 QuicRstStreamFrame rst1(stream_id1, QUIC_STREAM_NO_ERROR, 0); |
| 591 session_.OnRstStream(rst1); | 460 session_.OnRstStream(rst1); |
| 592 EXPECT_EQ(0u, session_.GetNumOpenStreams()); | 461 EXPECT_EQ(0u, session_.GetNumOpenStreams()); |
| 593 } | 462 } |
| 594 | 463 |
| 595 } // namespace | 464 } // namespace |
| 596 } // namespace test | 465 } // namespace test |
| 597 } // namespace net | 466 } // namespace net |
| OLD | NEW |