Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / net / quic / quic_session_test.cc
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/basictypes.h"
11 #include "base/containers/hash_tables.h"
12 #include "net/quic/crypto/crypto_protocol.h"
13 #include "net/quic/quic_crypto_stream.h"
14 #include "net/quic/quic_protocol.h"
15 #include "net/quic/quic_utils.h"
16 #include "net/quic/reliable_quic_stream.h"
17 #include "net/quic/test_tools/quic_connection_peer.h"
18 #include "net/quic/test_tools/quic_data_stream_peer.h"
19 #include "net/quic/test_tools/quic_session_peer.h"
20 #include "net/quic/test_tools/quic_test_utils.h"
21 #include "net/quic/test_tools/reliable_quic_stream_peer.h"
22 #include "net/spdy/spdy_framer.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 using base::hash_map;
27 using std::set;
28 using std::vector;
29 using testing::_;
30 using testing::InSequence;
31 using testing::InvokeWithoutArgs;
32 using testing::Return;
33 using testing::StrictMock;
34
35 namespace net {
36 namespace test {
37 namespace {
38
39 const QuicPriority kHighestPriority = 0;
40 const QuicPriority kSomeMiddlePriority = 3;
41
42 class TestCryptoStream : public QuicCryptoStream {
43  public:
44   explicit TestCryptoStream(QuicSession* session)
45       : QuicCryptoStream(session) {
46   }
47
48   virtual void OnHandshakeMessage(
49       const CryptoHandshakeMessage& message) OVERRIDE {
50     encryption_established_ = true;
51     handshake_confirmed_ = true;
52     CryptoHandshakeMessage msg;
53     string error_details;
54     session()->config()->ToHandshakeMessage(&msg);
55     const QuicErrorCode error = session()->config()->ProcessClientHello(
56         msg, &error_details);
57     EXPECT_EQ(QUIC_NO_ERROR, error);
58     session()->OnConfigNegotiated();
59     session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
60   }
61
62   MOCK_METHOD0(OnCanWrite, void());
63 };
64
65 class TestStream : public QuicDataStream {
66  public:
67   TestStream(QuicStreamId id, QuicSession* session)
68       : QuicDataStream(id, session) {
69   }
70
71   using ReliableQuicStream::CloseWriteSide;
72
73   virtual uint32 ProcessData(const char* data, uint32 data_len) {
74     return data_len;
75   }
76
77   MOCK_METHOD0(OnCanWrite, void());
78 };
79
80 // Poor man's functor for use as callback in a mock.
81 class StreamBlocker {
82  public:
83   StreamBlocker(QuicSession* session, QuicStreamId stream_id)
84       : session_(session),
85         stream_id_(stream_id) {
86   }
87
88   void MarkWriteBlocked() {
89     session_->MarkWriteBlocked(stream_id_, kSomeMiddlePriority);
90   }
91
92  private:
93   QuicSession* const session_;
94   const QuicStreamId stream_id_;
95 };
96
97 class TestSession : public QuicSession {
98  public:
99   explicit TestSession(QuicConnection* connection)
100       : QuicSession(connection, DefaultQuicConfig()),
101         crypto_stream_(this) {
102   }
103
104   virtual TestCryptoStream* GetCryptoStream() OVERRIDE {
105     return &crypto_stream_;
106   }
107
108   virtual TestStream* CreateOutgoingDataStream() OVERRIDE {
109     TestStream* stream = new TestStream(GetNextStreamId(), this);
110     ActivateStream(stream);
111     return stream;
112   }
113
114   virtual TestStream* CreateIncomingDataStream(QuicStreamId id) OVERRIDE {
115     return new TestStream(id, this);
116   }
117
118   bool IsClosedStream(QuicStreamId id) {
119     return QuicSession::IsClosedStream(id);
120   }
121
122   QuicDataStream* GetIncomingDataStream(QuicStreamId stream_id) {
123     return QuicSession::GetIncomingDataStream(stream_id);
124   }
125
126   TestCryptoStream crypto_stream_;
127 };
128
129 class QuicSessionTest : public ::testing::TestWithParam<QuicVersion> {
130  protected:
131   QuicSessionTest()
132       : connection_(new MockConnection(true, SupportedVersions(GetParam()))),
133         session_(connection_) {
134     headers_[":host"] = "www.google.com";
135     headers_[":path"] = "/index.hml";
136     headers_[":scheme"] = "http";
137     headers_["cookie"] =
138         "__utma=208381060.1228362404.1372200928.1372200928.1372200928.1; "
139         "__utmc=160408618; "
140         "GX=DQAAAOEAAACWJYdewdE9rIrW6qw3PtVi2-d729qaa-74KqOsM1NVQblK4VhX"
141         "hoALMsy6HOdDad2Sz0flUByv7etmo3mLMidGrBoljqO9hSVA40SLqpG_iuKKSHX"
142         "RW3Np4bq0F0SDGDNsW0DSmTS9ufMRrlpARJDS7qAI6M3bghqJp4eABKZiRqebHT"
143         "pMU-RXvTI5D5oCF1vYxYofH_l1Kviuiy3oQ1kS1enqWgbhJ2t61_SNdv-1XJIS0"
144         "O3YeHLmVCs62O6zp89QwakfAWK9d3IDQvVSJzCQsvxvNIvaZFa567MawWlXg0Rh"
145         "1zFMi5vzcns38-8_Sns; "
146         "GA=v*2%2Fmem*57968640*47239936%2Fmem*57968640*47114716%2Fno-nm-"
147         "yj*15%2Fno-cc-yj*5%2Fpc-ch*133685%2Fpc-s-cr*133947%2Fpc-s-t*1339"
148         "47%2Fno-nm-yj*4%2Fno-cc-yj*1%2Fceft-as*1%2Fceft-nqas*0%2Fad-ra-c"
149         "v_p%2Fad-nr-cv_p-f*1%2Fad-v-cv_p*859%2Fad-ns-cv_p-f*1%2Ffn-v-ad%"
150         "2Fpc-t*250%2Fpc-cm*461%2Fpc-s-cr*722%2Fpc-s-t*722%2Fau_p*4"
151         "SICAID=AJKiYcHdKgxum7KMXG0ei2t1-W4OD1uW-ecNsCqC0wDuAXiDGIcT_HA2o1"
152         "3Rs1UKCuBAF9g8rWNOFbxt8PSNSHFuIhOo2t6bJAVpCsMU5Laa6lewuTMYI8MzdQP"
153         "ARHKyW-koxuhMZHUnGBJAM1gJODe0cATO_KGoX4pbbFxxJ5IicRxOrWK_5rU3cdy6"
154         "edlR9FsEdH6iujMcHkbE5l18ehJDwTWmBKBzVD87naobhMMrF6VvnDGxQVGp9Ir_b"
155         "Rgj3RWUoPumQVCxtSOBdX0GlJOEcDTNCzQIm9BSfetog_eP_TfYubKudt5eMsXmN6"
156         "QnyXHeGeK2UINUzJ-D30AFcpqYgH9_1BvYSpi7fc7_ydBU8TaD8ZRxvtnzXqj0RfG"
157         "tuHghmv3aD-uzSYJ75XDdzKdizZ86IG6Fbn1XFhYZM-fbHhm3mVEXnyRW4ZuNOLFk"
158         "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn"
159         "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr"
160         "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo ";
161   }
162
163   void CheckClosedStreams() {
164     for (int i = kCryptoStreamId; i < 100; i++) {
165       if (closed_streams_.count(i) == 0) {
166         EXPECT_FALSE(session_.IsClosedStream(i)) << " stream id: " << i;
167       } else {
168         EXPECT_TRUE(session_.IsClosedStream(i)) << " stream id: " << i;
169       }
170     }
171   }
172
173   void CloseStream(QuicStreamId id) {
174     session_.CloseStream(id);
175     closed_streams_.insert(id);
176   }
177
178   QuicVersion version() const { return connection_->version(); }
179
180   MockConnection* connection_;
181   TestSession session_;
182   set<QuicStreamId> closed_streams_;
183   SpdyHeaderBlock headers_;
184 };
185
186 INSTANTIATE_TEST_CASE_P(Tests, QuicSessionTest,
187                         ::testing::ValuesIn(QuicSupportedVersions()));
188
189 TEST_P(QuicSessionTest, PeerAddress) {
190   EXPECT_EQ(IPEndPoint(Loopback4(), kTestPort), session_.peer_address());
191 }
192
193 TEST_P(QuicSessionTest, IsCryptoHandshakeConfirmed) {
194   EXPECT_FALSE(session_.IsCryptoHandshakeConfirmed());
195   CryptoHandshakeMessage message;
196   session_.crypto_stream_.OnHandshakeMessage(message);
197   EXPECT_TRUE(session_.IsCryptoHandshakeConfirmed());
198 }
199
200 TEST_P(QuicSessionTest, IsClosedStreamDefault) {
201   // Ensure that no streams are initially closed.
202   for (int i = kCryptoStreamId; i < 100; i++) {
203     EXPECT_FALSE(session_.IsClosedStream(i)) << "stream id: " << i;
204   }
205 }
206
207 TEST_P(QuicSessionTest, ImplicitlyCreatedStreams) {
208   ASSERT_TRUE(session_.GetIncomingDataStream(7) != NULL);
209   // Both 3 and 5 should be implicitly created.
210   EXPECT_FALSE(session_.IsClosedStream(3));
211   EXPECT_FALSE(session_.IsClosedStream(5));
212   ASSERT_TRUE(session_.GetIncomingDataStream(5) != NULL);
213   ASSERT_TRUE(session_.GetIncomingDataStream(3) != NULL);
214 }
215
216 TEST_P(QuicSessionTest, IsClosedStreamLocallyCreated) {
217   TestStream* stream2 = session_.CreateOutgoingDataStream();
218   EXPECT_EQ(2u, stream2->id());
219   TestStream* stream4 = session_.CreateOutgoingDataStream();
220   EXPECT_EQ(4u, stream4->id());
221   if (version() <= QUIC_VERSION_12) {
222     QuicDataStreamPeer::SetHeadersDecompressed(stream2, true);
223     QuicDataStreamPeer::SetHeadersDecompressed(stream4, true);
224   }
225
226   CheckClosedStreams();
227   CloseStream(4);
228   CheckClosedStreams();
229   CloseStream(2);
230   CheckClosedStreams();
231 }
232
233 TEST_P(QuicSessionTest, IsClosedStreamPeerCreated) {
234   QuicStreamId stream_id1 = version() > QUIC_VERSION_12 ? 5 : 3;
235   QuicStreamId stream_id2 = stream_id1 + 2;
236   QuicDataStream* stream1 = session_.GetIncomingDataStream(stream_id1);
237   QuicDataStreamPeer::SetHeadersDecompressed(stream1, true);
238   QuicDataStream* stream2 = session_.GetIncomingDataStream(stream_id2);
239   QuicDataStreamPeer::SetHeadersDecompressed(stream2, true);
240
241   CheckClosedStreams();
242   CloseStream(stream_id1);
243   CheckClosedStreams();
244   CloseStream(stream_id2);
245   // Create a stream explicitly, and another implicitly.
246   QuicDataStream* stream3 = session_.GetIncomingDataStream(stream_id2 + 4);
247   QuicDataStreamPeer::SetHeadersDecompressed(stream3, true);
248   CheckClosedStreams();
249   // Close one, but make sure the other is still not closed
250   CloseStream(stream3->id());
251   CheckClosedStreams();
252 }
253
254 TEST_P(QuicSessionTest, StreamIdTooLarge) {
255   QuicStreamId stream_id = version() > QUIC_VERSION_12 ? 5 : 3;
256   session_.GetIncomingDataStream(stream_id);
257   EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_STREAM_ID));
258   session_.GetIncomingDataStream(stream_id + 102);
259 }
260
261 TEST_P(QuicSessionTest, DecompressionError) {
262   if (version() > QUIC_VERSION_12) {
263     QuicHeadersStream* stream = QuicSessionPeer::GetHeadersStream(&session_);
264     const unsigned char data[] = {
265         0x80, 0x03, 0x00, 0x01,  // SPDY/3 SYN_STREAM frame
266         0x00, 0x00, 0x00, 0x25,  // flags/length
267         0x00, 0x00, 0x00, 0x05,  // stream id
268         0x00, 0x00, 0x00, 0x00,  // associated stream id
269         0x00, 0x00,
270         'a',  'b',  'c',  'd'    // invalid compressed data
271     };
272     EXPECT_CALL(*connection_,
273                 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
274                                                "SPDY framing error."));
275     stream->ProcessRawData(reinterpret_cast<const char*>(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 }
288
289 TEST_P(QuicSessionTest, DebugDFatalIfMarkingClosedStreamWriteBlocked) {
290   TestStream* stream2 = session_.CreateOutgoingDataStream();
291   // Close the stream.
292   stream2->Reset(QUIC_BAD_APPLICATION_PAYLOAD);
293   // TODO(rtenneti): enable when chromium supports EXPECT_DEBUG_DFATAL.
294   /*
295   QuicStreamId kClosedStreamId = stream2->id();
296   EXPECT_DEBUG_DFATAL(
297       session_.MarkWriteBlocked(kClosedStreamId, kSomeMiddlePriority),
298       "Marking unknown stream 2 blocked.");
299   */
300 }
301
302 TEST_P(QuicSessionTest, DebugDFatalIfMarkWriteBlockedCalledWithWrongPriority) {
303   const QuicPriority kDifferentPriority = 0;
304
305   TestStream* stream2 = session_.CreateOutgoingDataStream();
306   EXPECT_NE(kDifferentPriority, stream2->EffectivePriority());
307   // TODO(rtenneti): enable when chromium supports EXPECT_DEBUG_DFATAL.
308   /*
309   EXPECT_DEBUG_DFATAL(
310       session_.MarkWriteBlocked(stream2->id(), kDifferentPriority),
311       "Priorities do not match.  Got: 0 Expected: 3");
312   */
313 }
314
315 TEST_P(QuicSessionTest, OnCanWrite) {
316   TestStream* stream2 = session_.CreateOutgoingDataStream();
317   TestStream* stream4 = session_.CreateOutgoingDataStream();
318   TestStream* stream6 = session_.CreateOutgoingDataStream();
319
320   session_.MarkWriteBlocked(stream2->id(), kSomeMiddlePriority);
321   session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority);
322   session_.MarkWriteBlocked(stream4->id(), kSomeMiddlePriority);
323
324   InSequence s;
325   StreamBlocker stream2_blocker(&session_, stream2->id());
326   EXPECT_CALL(*stream2, OnCanWrite()).WillOnce(
327       // Reregister, to test the loop limit.
328       InvokeWithoutArgs(&stream2_blocker, &StreamBlocker::MarkWriteBlocked));
329   EXPECT_CALL(*stream6, OnCanWrite());
330   EXPECT_CALL(*stream4, OnCanWrite());
331
332   EXPECT_FALSE(session_.OnCanWrite());
333 }
334
335 TEST_P(QuicSessionTest, OnCanWriteCongestionControlBlocks) {
336   InSequence s;
337
338   // Drive congestion control manually.
339   MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>;
340   QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm);
341
342   TestStream* stream2 = session_.CreateOutgoingDataStream();
343   TestStream* stream4 = session_.CreateOutgoingDataStream();
344   TestStream* stream6 = session_.CreateOutgoingDataStream();
345
346   session_.MarkWriteBlocked(stream2->id(), kSomeMiddlePriority);
347   session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority);
348   session_.MarkWriteBlocked(stream4->id(), kSomeMiddlePriority);
349
350   StreamBlocker stream2_blocker(&session_, stream2->id());
351   EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _, _)).WillOnce(Return(
352       QuicTime::Delta::Zero()));
353   EXPECT_CALL(*stream2, OnCanWrite());
354   EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _, _)).WillOnce(Return(
355       QuicTime::Delta::Zero()));
356   EXPECT_CALL(*stream6, OnCanWrite());
357   EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _, _)).WillOnce(Return(
358       QuicTime::Delta::Infinite()));
359   // stream4->OnCanWrite is not called.
360
361   // TODO(avd) change return value to 'true', since the connection
362   // can't write because it is congestion control blocked.
363   EXPECT_FALSE(session_.OnCanWrite());
364
365   // Still congestion-control blocked.
366   EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _, _)).WillOnce(Return(
367       QuicTime::Delta::Infinite()));
368   EXPECT_FALSE(session_.OnCanWrite());
369
370   // stream4->OnCanWrite is called once the connection stops being
371   // congestion-control blocked.
372   EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _, _)).WillOnce(Return(
373       QuicTime::Delta::Zero()));
374   EXPECT_CALL(*stream4, OnCanWrite());
375   EXPECT_TRUE(session_.OnCanWrite());
376 }
377
378 TEST_P(QuicSessionTest, BufferedHandshake) {
379   EXPECT_FALSE(session_.HasPendingHandshake());  // Default value.
380
381   // Test that blocking other streams does not change our status.
382   TestStream* stream2 = session_.CreateOutgoingDataStream();
383   StreamBlocker stream2_blocker(&session_, stream2->id());
384   stream2_blocker.MarkWriteBlocked();
385   EXPECT_FALSE(session_.HasPendingHandshake());
386
387   TestStream* stream3 = session_.CreateOutgoingDataStream();
388   StreamBlocker stream3_blocker(&session_, stream3->id());
389   stream3_blocker.MarkWriteBlocked();
390   EXPECT_FALSE(session_.HasPendingHandshake());
391
392   // Blocking (due to buffering of) the Crypto stream is detected.
393   session_.MarkWriteBlocked(kCryptoStreamId, kHighestPriority);
394   EXPECT_TRUE(session_.HasPendingHandshake());
395
396   TestStream* stream4 = session_.CreateOutgoingDataStream();
397   StreamBlocker stream4_blocker(&session_, stream4->id());
398   stream4_blocker.MarkWriteBlocked();
399   EXPECT_TRUE(session_.HasPendingHandshake());
400
401   InSequence s;
402   // Force most streams to re-register, which is common scenario when we block
403   // the Crypto stream, and only the crypto stream can "really" write.
404
405   // Due to prioritization, we *should* be asked to write the crypto stream
406   // first.
407   // Don't re-register the crypto stream (which signals complete writing).
408   TestCryptoStream* crypto_stream = session_.GetCryptoStream();
409   EXPECT_CALL(*crypto_stream, OnCanWrite());
410
411   // Re-register all other streams, to show they weren't able to proceed.
412   EXPECT_CALL(*stream2, OnCanWrite()).WillOnce(
413       InvokeWithoutArgs(&stream2_blocker, &StreamBlocker::MarkWriteBlocked));
414
415   EXPECT_CALL(*stream3, OnCanWrite()).WillOnce(
416       InvokeWithoutArgs(&stream3_blocker, &StreamBlocker::MarkWriteBlocked));
417
418   EXPECT_CALL(*stream4, OnCanWrite()).WillOnce(
419       InvokeWithoutArgs(&stream4_blocker, &StreamBlocker::MarkWriteBlocked));
420
421   EXPECT_FALSE(session_.OnCanWrite());
422   EXPECT_FALSE(session_.HasPendingHandshake());  // Crypto stream wrote.
423 }
424
425 TEST_P(QuicSessionTest, OnCanWriteWithClosedStream) {
426   TestStream* stream2 = session_.CreateOutgoingDataStream();
427   TestStream* stream4 = session_.CreateOutgoingDataStream();
428   TestStream* stream6 = session_.CreateOutgoingDataStream();
429
430   session_.MarkWriteBlocked(stream2->id(), kSomeMiddlePriority);
431   session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority);
432   session_.MarkWriteBlocked(stream4->id(), kSomeMiddlePriority);
433   CloseStream(stream6->id());
434
435   InSequence s;
436   EXPECT_CALL(*stream2, OnCanWrite());
437   EXPECT_CALL(*stream4, OnCanWrite());
438   EXPECT_TRUE(session_.OnCanWrite());
439 }
440
441 // Regression test for http://crbug.com/248737
442 TEST_P(QuicSessionTest, OutOfOrderHeaders) {
443   QuicSpdyCompressor compressor;
444   vector<QuicStreamFrame> frames;
445   QuicPacketHeader header;
446   header.public_header.guid = session_.guid();
447
448   TestStream* stream2 = session_.CreateOutgoingDataStream();
449   TestStream* stream4 = session_.CreateOutgoingDataStream();
450   stream2->CloseWriteSide();
451   stream4->CloseWriteSide();
452
453   // Create frame with headers for stream2.
454   string compressed_headers1 = compressor.CompressHeaders(headers_);
455   QuicStreamFrame frame1(
456       stream2->id(), false, 0, MakeIOVector(compressed_headers1));
457
458   // Create frame with headers for stream4.
459   string compressed_headers2 = compressor.CompressHeaders(headers_);
460   QuicStreamFrame frame2(
461       stream4->id(), true, 0, MakeIOVector(compressed_headers2));
462
463   // Process the second frame first.  This will cause the headers to
464   // be queued up and processed after the first frame is processed.
465   frames.push_back(frame2);
466   session_.OnStreamFrames(frames);
467
468   // Process the first frame, and un-cork the buffered headers.
469   frames[0] = frame1;
470   session_.OnStreamFrames(frames);
471
472   // Ensure that the streams actually close and we don't DCHECK.
473   connection_->CloseConnection(QUIC_CONNECTION_TIMED_OUT, true);
474 }
475
476 TEST_P(QuicSessionTest, SendGoAway) {
477   // After sending a GoAway, ensure new incoming streams cannot be created and
478   // result in a RST being sent.
479   EXPECT_CALL(*connection_,
480               SendGoAway(QUIC_PEER_GOING_AWAY, 0u, "Going Away."));
481   session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away.");
482   EXPECT_TRUE(session_.goaway_sent());
483
484   EXPECT_CALL(*connection_, SendRstStream(3u, QUIC_STREAM_PEER_GOING_AWAY, 0));
485   EXPECT_FALSE(session_.GetIncomingDataStream(3u));
486 }
487
488 TEST_P(QuicSessionTest, IncreasedTimeoutAfterCryptoHandshake) {
489   EXPECT_EQ(kDefaultInitialTimeoutSecs,
490             QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds());
491   CryptoHandshakeMessage msg;
492   session_.crypto_stream_.OnHandshakeMessage(msg);
493   EXPECT_EQ(kDefaultTimeoutSecs,
494             QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds());
495 }
496
497 TEST_P(QuicSessionTest, ZombieStream) {
498   QuicStreamId stream_id1 = version() > QUIC_VERSION_12 ? 5 : 3;
499   QuicStreamId stream_id2 = stream_id1 + 2;
500   StrictMock<MockConnection>* connection =
501       new StrictMock<MockConnection>(false, SupportedVersions(version()));
502   TestSession session(connection);
503
504   TestStream* stream1 = session.CreateOutgoingDataStream();
505   EXPECT_EQ(stream_id1, stream1->id());
506   TestStream* stream2 = session.CreateOutgoingDataStream();
507   EXPECT_EQ(stream_id2, stream2->id());
508   EXPECT_EQ(2u, session.GetNumOpenStreams());
509
510   // Reset the stream, but since the headers have not been decompressed
511   // it will become a zombie and will continue to process data
512   // until the headers are decompressed.
513   EXPECT_CALL(*connection, SendRstStream(stream_id1, QUIC_STREAM_CANCELLED, 0));
514   session.SendRstStream(stream_id1, QUIC_STREAM_CANCELLED, 0);
515
516   EXPECT_EQ(1u, session.GetNumOpenStreams());
517
518   vector<QuicStreamFrame> frames;
519   QuicPacketHeader header;
520   header.public_header.guid = session_.guid();
521
522   // Create frame with headers for stream2.
523   QuicSpdyCompressor compressor;
524   string compressed_headers1 = compressor.CompressHeaders(headers_);
525   QuicStreamFrame frame1(
526       stream1->id(), false, 0, MakeIOVector(compressed_headers1));
527
528   // Process the second frame first.  This will cause the headers to
529   // be queued up and processed after the first frame is processed.
530   frames.push_back(frame1);
531   EXPECT_FALSE(stream1->headers_decompressed());
532
533   session.OnStreamFrames(frames);
534   EXPECT_EQ(1u, session.GetNumOpenStreams());
535
536   EXPECT_TRUE(connection->connected());
537 }
538
539 TEST_P(QuicSessionTest, ZombieStreamConnectionClose) {
540   QuicStreamId stream_id1 = version() > QUIC_VERSION_12 ? 5 : 3;
541   QuicStreamId stream_id2 = stream_id1 + 2;
542   StrictMock<MockConnection>* connection =
543       new StrictMock<MockConnection>(false, SupportedVersions(version()));
544   TestSession session(connection);
545
546   TestStream* stream1 = session.CreateOutgoingDataStream();
547   EXPECT_EQ(stream_id1, stream1->id());
548   TestStream* stream2 = session.CreateOutgoingDataStream();
549   EXPECT_EQ(stream_id2, stream2->id());
550   EXPECT_EQ(2u, session.GetNumOpenStreams());
551
552   stream1->CloseWriteSide();
553   // Reset the stream, but since the headers have not been decompressed
554   // it will become a zombie and will continue to process data
555   // until the headers are decompressed.
556   EXPECT_CALL(*connection, SendRstStream(stream_id1, QUIC_STREAM_CANCELLED, 0));
557   session.SendRstStream(stream_id1, QUIC_STREAM_CANCELLED, 0);
558
559   EXPECT_EQ(1u, session.GetNumOpenStreams());
560
561   if (GetParam() > QUIC_VERSION_13) {
562     // Stream 2 will send a RST during normal termination.
563     EXPECT_CALL(*connection,
564                 SendRstStream(stream_id2, QUIC_STREAM_NO_ERROR, 0));
565   }
566   connection->CloseConnection(QUIC_CONNECTION_TIMED_OUT, false);
567
568   EXPECT_EQ(0u, session.GetNumOpenStreams());
569 }
570
571 TEST_P(QuicSessionTest, RstStreamBeforeHeadersDecompressed) {
572   QuicStreamId stream_id1 = version() > QUIC_VERSION_12 ? 5 : 3;
573   // Send two bytes of payload.
574   QuicStreamFrame data1(stream_id1, false, 0, MakeIOVector("HT"));
575   vector<QuicStreamFrame> frames;
576   frames.push_back(data1);
577   EXPECT_TRUE(session_.OnStreamFrames(frames));
578   EXPECT_EQ(1u, session_.GetNumOpenStreams());
579
580   if (version() <= QUIC_VERSION_12) {
581     // Send a reset before the headers have been decompressed.  This causes
582     // an unrecoverable compression context state.
583     EXPECT_CALL(*connection_, SendConnectionClose(
584         QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED));
585   }
586
587   QuicRstStreamFrame rst1(stream_id1, QUIC_STREAM_NO_ERROR, 0);
588   session_.OnRstStream(rst1);
589   EXPECT_EQ(0u, session_.GetNumOpenStreams());
590 }
591
592 }  // namespace
593 }  // namespace test
594 }  // namespace net