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 |