1 // Copyright 2013 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 "quiche/quic/tools/quic_simple_server_session.h"
6
7 #include <algorithm>
8 #include <memory>
9 #include <utility>
10
11 #include "absl/strings/str_cat.h"
12 #include "quiche/quic/core/crypto/null_encrypter.h"
13 #include "quiche/quic/core/crypto/quic_crypto_server_config.h"
14 #include "quiche/quic/core/crypto/quic_random.h"
15 #include "quiche/quic/core/http/http_encoder.h"
16 #include "quiche/quic/core/proto/cached_network_parameters_proto.h"
17 #include "quiche/quic/core/quic_connection.h"
18 #include "quiche/quic/core/quic_crypto_server_stream.h"
19 #include "quiche/quic/core/quic_utils.h"
20 #include "quiche/quic/core/quic_versions.h"
21 #include "quiche/quic/core/tls_server_handshaker.h"
22 #include "quiche/quic/platform/api/quic_expect_bug.h"
23 #include "quiche/quic/platform/api/quic_flags.h"
24 #include "quiche/quic/platform/api/quic_socket_address.h"
25 #include "quiche/quic/platform/api/quic_test.h"
26 #include "quiche/quic/test_tools/crypto_test_utils.h"
27 #include "quiche/quic/test_tools/mock_quic_session_visitor.h"
28 #include "quiche/quic/test_tools/quic_config_peer.h"
29 #include "quiche/quic/test_tools/quic_connection_peer.h"
30 #include "quiche/quic/test_tools/quic_sent_packet_manager_peer.h"
31 #include "quiche/quic/test_tools/quic_session_peer.h"
32 #include "quiche/quic/test_tools/quic_spdy_session_peer.h"
33 #include "quiche/quic/test_tools/quic_stream_peer.h"
34 #include "quiche/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h"
35 #include "quiche/quic/test_tools/quic_test_utils.h"
36 #include "quiche/quic/tools/quic_backend_response.h"
37 #include "quiche/quic/tools/quic_memory_cache_backend.h"
38 #include "quiche/quic/tools/quic_simple_server_stream.h"
39
40 using testing::_;
41 using testing::AtLeast;
42 using testing::InSequence;
43 using testing::Invoke;
44 using testing::Return;
45 using testing::StrictMock;
46
47 namespace quic {
48 namespace test {
49 namespace {
50
51 // Data to be sent on a request stream. In Google QUIC, this is interpreted as
52 // DATA payload (there is no framing on request streams). In IETF QUIC, this is
53 // interpreted as HEADERS frame (type 0x1) with payload length 122 ('z'). Since
54 // no payload is included, QPACK decoder will not be invoked.
55 const char* const kStreamData = "\1z";
56
57 } // namespace
58
59 class QuicSimpleServerSessionPeer {
60 public:
SetCryptoStream(QuicSimpleServerSession * s,QuicCryptoServerStreamBase * crypto_stream)61 static void SetCryptoStream(QuicSimpleServerSession* s,
62 QuicCryptoServerStreamBase* crypto_stream) {
63 s->crypto_stream_.reset(crypto_stream);
64 }
65
CreateIncomingStream(QuicSimpleServerSession * s,QuicStreamId id)66 static QuicSpdyStream* CreateIncomingStream(QuicSimpleServerSession* s,
67 QuicStreamId id) {
68 return s->CreateIncomingStream(id);
69 }
70
CreateOutgoingUnidirectionalStream(QuicSimpleServerSession * s)71 static QuicSimpleServerStream* CreateOutgoingUnidirectionalStream(
72 QuicSimpleServerSession* s) {
73 return s->CreateOutgoingUnidirectionalStream();
74 }
75 };
76
77 namespace {
78
79 const size_t kMaxStreamsForTest = 10;
80
81 class MockQuicCryptoServerStream : public QuicCryptoServerStream {
82 public:
MockQuicCryptoServerStream(const QuicCryptoServerConfig * crypto_config,QuicCompressedCertsCache * compressed_certs_cache,QuicSession * session,QuicCryptoServerStreamBase::Helper * helper)83 explicit MockQuicCryptoServerStream(
84 const QuicCryptoServerConfig* crypto_config,
85 QuicCompressedCertsCache* compressed_certs_cache, QuicSession* session,
86 QuicCryptoServerStreamBase::Helper* helper)
87 : QuicCryptoServerStream(crypto_config, compressed_certs_cache, session,
88 helper) {}
89 MockQuicCryptoServerStream(const MockQuicCryptoServerStream&) = delete;
90 MockQuicCryptoServerStream& operator=(const MockQuicCryptoServerStream&) =
91 delete;
~MockQuicCryptoServerStream()92 ~MockQuicCryptoServerStream() override {}
93
94 MOCK_METHOD(void, SendServerConfigUpdate, (const CachedNetworkParameters*),
95 (override));
96
encryption_established() const97 bool encryption_established() const override { return true; }
98 };
99
100 class MockTlsServerHandshaker : public TlsServerHandshaker {
101 public:
MockTlsServerHandshaker(QuicSession * session,const QuicCryptoServerConfig * crypto_config)102 explicit MockTlsServerHandshaker(QuicSession* session,
103 const QuicCryptoServerConfig* crypto_config)
104 : TlsServerHandshaker(session, crypto_config) {}
105 MockTlsServerHandshaker(const MockTlsServerHandshaker&) = delete;
106 MockTlsServerHandshaker& operator=(const MockTlsServerHandshaker&) = delete;
~MockTlsServerHandshaker()107 ~MockTlsServerHandshaker() override {}
108
109 MOCK_METHOD(void, SendServerConfigUpdate, (const CachedNetworkParameters*),
110 (override));
111
encryption_established() const112 bool encryption_established() const override { return true; }
113 };
114
115 class MockQuicConnectionWithSendStreamData : public MockQuicConnection {
116 public:
MockQuicConnectionWithSendStreamData(MockQuicConnectionHelper * helper,MockAlarmFactory * alarm_factory,Perspective perspective,const ParsedQuicVersionVector & supported_versions)117 MockQuicConnectionWithSendStreamData(
118 MockQuicConnectionHelper* helper, MockAlarmFactory* alarm_factory,
119 Perspective perspective,
120 const ParsedQuicVersionVector& supported_versions)
121 : MockQuicConnection(helper, alarm_factory, perspective,
122 supported_versions) {
123 auto consume_all_data = [](QuicStreamId /*id*/, size_t write_length,
124 QuicStreamOffset /*offset*/,
125 StreamSendingState state) {
126 return QuicConsumedData(write_length, state != NO_FIN);
127 };
128 ON_CALL(*this, SendStreamData(_, _, _, _))
129 .WillByDefault(Invoke(consume_all_data));
130 }
131
132 MOCK_METHOD(QuicConsumedData, SendStreamData,
133 (QuicStreamId id, size_t write_length, QuicStreamOffset offset,
134 StreamSendingState state),
135 (override));
136 };
137
138 class MockQuicSimpleServerSession : public QuicSimpleServerSession {
139 public:
MockQuicSimpleServerSession(const QuicConfig & config,QuicConnection * connection,QuicSession::Visitor * visitor,QuicCryptoServerStreamBase::Helper * helper,const QuicCryptoServerConfig * crypto_config,QuicCompressedCertsCache * compressed_certs_cache,QuicSimpleServerBackend * quic_simple_server_backend)140 MockQuicSimpleServerSession(
141 const QuicConfig& config, QuicConnection* connection,
142 QuicSession::Visitor* visitor, QuicCryptoServerStreamBase::Helper* helper,
143 const QuicCryptoServerConfig* crypto_config,
144 QuicCompressedCertsCache* compressed_certs_cache,
145 QuicSimpleServerBackend* quic_simple_server_backend)
146 : QuicSimpleServerSession(
147 config, CurrentSupportedVersions(), connection, visitor, helper,
148 crypto_config, compressed_certs_cache, quic_simple_server_backend) {
149 }
150 MOCK_METHOD(void, SendBlocked, (QuicStreamId, QuicStreamOffset), (override));
151 MOCK_METHOD(bool, WriteControlFrame,
152 (const QuicFrame& frame, TransmissionType type), (override));
153 };
154
155 class QuicSimpleServerSessionTest
156 : public QuicTestWithParam<ParsedQuicVersion> {
157 public:
158 // The function ensures that A) the MAX_STREAMS frames get properly deleted
159 // (since the test uses a 'did we leak memory' check ... if we just lose the
160 // frame, the test fails) and B) returns true (instead of the default, false)
161 // which ensures that the rest of the system thinks that the frame actually
162 // was transmitted.
ClearMaxStreamsControlFrame(const QuicFrame & frame)163 bool ClearMaxStreamsControlFrame(const QuicFrame& frame) {
164 if (frame.type == MAX_STREAMS_FRAME) {
165 DeleteFrame(&const_cast<QuicFrame&>(frame));
166 return true;
167 }
168 return false;
169 }
170
171 protected:
QuicSimpleServerSessionTest()172 QuicSimpleServerSessionTest()
173 : crypto_config_(QuicCryptoServerConfig::TESTING,
174 QuicRandom::GetInstance(),
175 crypto_test_utils::ProofSourceForTesting(),
176 KeyExchangeSource::Default()),
177 compressed_certs_cache_(
178 QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) {
179 config_.SetMaxBidirectionalStreamsToSend(kMaxStreamsForTest);
180 QuicConfigPeer::SetReceivedMaxBidirectionalStreams(&config_,
181 kMaxStreamsForTest);
182 config_.SetMaxUnidirectionalStreamsToSend(kMaxStreamsForTest);
183
184 config_.SetInitialStreamFlowControlWindowToSend(
185 kInitialStreamFlowControlWindowForTest);
186 config_.SetInitialMaxStreamDataBytesIncomingBidirectionalToSend(
187 kInitialStreamFlowControlWindowForTest);
188 config_.SetInitialMaxStreamDataBytesOutgoingBidirectionalToSend(
189 kInitialStreamFlowControlWindowForTest);
190 config_.SetInitialMaxStreamDataBytesUnidirectionalToSend(
191 kInitialStreamFlowControlWindowForTest);
192 config_.SetInitialSessionFlowControlWindowToSend(
193 kInitialSessionFlowControlWindowForTest);
194 if (VersionUsesHttp3(transport_version())) {
195 QuicConfigPeer::SetReceivedMaxUnidirectionalStreams(
196 &config_, kMaxStreamsForTest + 3);
197 } else {
198 QuicConfigPeer::SetReceivedMaxUnidirectionalStreams(&config_,
199 kMaxStreamsForTest);
200 }
201
202 ParsedQuicVersionVector supported_versions = SupportedVersions(version());
203 connection_ = new StrictMock<MockQuicConnectionWithSendStreamData>(
204 &helper_, &alarm_factory_, Perspective::IS_SERVER, supported_versions);
205 connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
206 connection_->SetEncrypter(
207 ENCRYPTION_FORWARD_SECURE,
208 std::make_unique<NullEncrypter>(connection_->perspective()));
209 session_ = std::make_unique<MockQuicSimpleServerSession>(
210 config_, connection_, &owner_, &stream_helper_, &crypto_config_,
211 &compressed_certs_cache_, &memory_cache_backend_);
212 MockClock clock;
213 handshake_message_ = crypto_config_.AddDefaultConfig(
214 QuicRandom::GetInstance(), &clock,
215 QuicCryptoServerConfig::ConfigOptions());
216 session_->Initialize();
217
218 if (VersionHasIetfQuicFrames(transport_version())) {
219 EXPECT_CALL(*session_, WriteControlFrame(_, _))
220 .WillRepeatedly(Invoke(&ClearControlFrameWithTransmissionType));
221 }
222 session_->OnConfigNegotiated();
223 }
224
GetNthClientInitiatedBidirectionalId(int n)225 QuicStreamId GetNthClientInitiatedBidirectionalId(int n) {
226 return GetNthClientInitiatedBidirectionalStreamId(transport_version(), n);
227 }
228
GetNthServerInitiatedUnidirectionalId(int n)229 QuicStreamId GetNthServerInitiatedUnidirectionalId(int n) {
230 return quic::test::GetNthServerInitiatedUnidirectionalStreamId(
231 transport_version(), n);
232 }
233
version() const234 ParsedQuicVersion version() const { return GetParam(); }
235
transport_version() const236 QuicTransportVersion transport_version() const {
237 return version().transport_version;
238 }
239
InjectStopSending(QuicStreamId stream_id,QuicRstStreamErrorCode rst_stream_code)240 void InjectStopSending(QuicStreamId stream_id,
241 QuicRstStreamErrorCode rst_stream_code) {
242 // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
243 // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
244 // a one-way close.
245 if (!VersionHasIetfQuicFrames(transport_version())) {
246 // Only needed for version 99/IETF QUIC.
247 return;
248 }
249 EXPECT_CALL(owner_, OnStopSendingReceived(_)).Times(1);
250 QuicStopSendingFrame stop_sending(kInvalidControlFrameId, stream_id,
251 rst_stream_code);
252 // Expect the RESET_STREAM that is generated in response to receiving a
253 // STOP_SENDING.
254 EXPECT_CALL(*connection_, OnStreamReset(stream_id, rst_stream_code));
255 session_->OnStopSendingFrame(stop_sending);
256 }
257
258 StrictMock<MockQuicSessionVisitor> owner_;
259 StrictMock<MockQuicCryptoServerStreamHelper> stream_helper_;
260 MockQuicConnectionHelper helper_;
261 MockAlarmFactory alarm_factory_;
262 StrictMock<MockQuicConnectionWithSendStreamData>* connection_;
263 QuicConfig config_;
264 QuicCryptoServerConfig crypto_config_;
265 QuicCompressedCertsCache compressed_certs_cache_;
266 QuicMemoryCacheBackend memory_cache_backend_;
267 std::unique_ptr<MockQuicSimpleServerSession> session_;
268 std::unique_ptr<CryptoHandshakeMessage> handshake_message_;
269 };
270
271 INSTANTIATE_TEST_SUITE_P(Tests, QuicSimpleServerSessionTest,
272 ::testing::ValuesIn(AllSupportedVersions()),
273 ::testing::PrintToStringParamName());
274
TEST_P(QuicSimpleServerSessionTest,CloseStreamDueToReset)275 TEST_P(QuicSimpleServerSessionTest, CloseStreamDueToReset) {
276 // Send some data open a stream, then reset it.
277 QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0,
278 kStreamData);
279 session_->OnStreamFrame(data1);
280 EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
281
282 // Receive a reset (and send a RST in response).
283 QuicRstStreamFrame rst1(kInvalidControlFrameId,
284 GetNthClientInitiatedBidirectionalId(0),
285 QUIC_ERROR_PROCESSING_STREAM, 0);
286 EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
287 EXPECT_CALL(*session_, WriteControlFrame(_, _));
288
289 if (!VersionHasIetfQuicFrames(transport_version())) {
290 // For version 99, this is covered in InjectStopSending()
291 EXPECT_CALL(*connection_,
292 OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
293 QUIC_RST_ACKNOWLEDGEMENT));
294 }
295 session_->OnRstStream(rst1);
296 // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
297 // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
298 // a one-way close.
299 InjectStopSending(GetNthClientInitiatedBidirectionalId(0),
300 QUIC_ERROR_PROCESSING_STREAM);
301 EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
302
303 // Send the same two bytes of payload in a new packet.
304 session_->OnStreamFrame(data1);
305
306 // The stream should not be re-opened.
307 EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
308 EXPECT_TRUE(connection_->connected());
309 }
310
TEST_P(QuicSimpleServerSessionTest,NeverOpenStreamDueToReset)311 TEST_P(QuicSimpleServerSessionTest, NeverOpenStreamDueToReset) {
312 // Send a reset (and expect the peer to send a RST in response).
313 QuicRstStreamFrame rst1(kInvalidControlFrameId,
314 GetNthClientInitiatedBidirectionalId(0),
315 QUIC_ERROR_PROCESSING_STREAM, 0);
316 EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
317 if (!VersionHasIetfQuicFrames(transport_version())) {
318 EXPECT_CALL(*session_, WriteControlFrame(_, _));
319 // For version 99, this is covered in InjectStopSending()
320 EXPECT_CALL(*connection_,
321 OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
322 QUIC_RST_ACKNOWLEDGEMENT));
323 }
324 session_->OnRstStream(rst1);
325 // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
326 // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
327 // a one-way close.
328 InjectStopSending(GetNthClientInitiatedBidirectionalId(0),
329 QUIC_ERROR_PROCESSING_STREAM);
330
331 EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
332
333 QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0,
334 kStreamData);
335 session_->OnStreamFrame(data1);
336
337 // The stream should never be opened, now that the reset is received.
338 EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
339 EXPECT_TRUE(connection_->connected());
340 }
341
TEST_P(QuicSimpleServerSessionTest,AcceptClosedStream)342 TEST_P(QuicSimpleServerSessionTest, AcceptClosedStream) {
343 // Send some data to open two streams.
344 QuicStreamFrame frame1(GetNthClientInitiatedBidirectionalId(0), false, 0,
345 kStreamData);
346 QuicStreamFrame frame2(GetNthClientInitiatedBidirectionalId(1), false, 0,
347 kStreamData);
348 session_->OnStreamFrame(frame1);
349 session_->OnStreamFrame(frame2);
350 EXPECT_EQ(2u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
351
352 // Send a reset (and expect the peer to send a RST in response).
353 QuicRstStreamFrame rst(kInvalidControlFrameId,
354 GetNthClientInitiatedBidirectionalId(0),
355 QUIC_ERROR_PROCESSING_STREAM, 0);
356 EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
357 if (!VersionHasIetfQuicFrames(transport_version())) {
358 EXPECT_CALL(*session_, WriteControlFrame(_, _));
359 // For version 99, this is covered in InjectStopSending()
360 EXPECT_CALL(*connection_,
361 OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
362 QUIC_RST_ACKNOWLEDGEMENT));
363 }
364 session_->OnRstStream(rst);
365 // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
366 // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
367 // a one-way close.
368 InjectStopSending(GetNthClientInitiatedBidirectionalId(0),
369 QUIC_ERROR_PROCESSING_STREAM);
370
371 // If we were tracking, we'd probably want to reject this because it's data
372 // past the reset point of stream 3. As it's a closed stream we just drop the
373 // data on the floor, but accept the packet because it has data for stream 5.
374 QuicStreamFrame frame3(GetNthClientInitiatedBidirectionalId(0), false, 2,
375 kStreamData);
376 QuicStreamFrame frame4(GetNthClientInitiatedBidirectionalId(1), false, 2,
377 kStreamData);
378 session_->OnStreamFrame(frame3);
379 session_->OnStreamFrame(frame4);
380 // The stream should never be opened, now that the reset is received.
381 EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
382 EXPECT_TRUE(connection_->connected());
383 }
384
TEST_P(QuicSimpleServerSessionTest,CreateIncomingStreamDisconnected)385 TEST_P(QuicSimpleServerSessionTest, CreateIncomingStreamDisconnected) {
386 // EXPECT_QUIC_BUG tests are expensive so only run one instance of them.
387 if (version() != AllSupportedVersions()[0]) {
388 return;
389 }
390
391 // Tests that incoming stream creation fails when connection is not connected.
392 size_t initial_num_open_stream =
393 QuicSessionPeer::GetNumOpenDynamicStreams(session_.get());
394 QuicConnectionPeer::TearDownLocalConnectionState(connection_);
395 EXPECT_QUIC_BUG(QuicSimpleServerSessionPeer::CreateIncomingStream(
396 session_.get(), GetNthClientInitiatedBidirectionalId(0)),
397 "ShouldCreateIncomingStream called when disconnected");
398 EXPECT_EQ(initial_num_open_stream,
399 QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
400 }
401
TEST_P(QuicSimpleServerSessionTest,CreateIncomingStream)402 TEST_P(QuicSimpleServerSessionTest, CreateIncomingStream) {
403 QuicSpdyStream* stream = QuicSimpleServerSessionPeer::CreateIncomingStream(
404 session_.get(), GetNthClientInitiatedBidirectionalId(0));
405 EXPECT_NE(nullptr, stream);
406 EXPECT_EQ(GetNthClientInitiatedBidirectionalId(0), stream->id());
407 }
408
TEST_P(QuicSimpleServerSessionTest,CreateOutgoingDynamicStreamDisconnected)409 TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamDisconnected) {
410 // EXPECT_QUIC_BUG tests are expensive so only run one instance of them.
411 if (version() != AllSupportedVersions()[0]) {
412 return;
413 }
414
415 // Tests that outgoing stream creation fails when connection is not connected.
416 size_t initial_num_open_stream =
417 QuicSessionPeer::GetNumOpenDynamicStreams(session_.get());
418 QuicConnectionPeer::TearDownLocalConnectionState(connection_);
419 EXPECT_QUIC_BUG(
420 QuicSimpleServerSessionPeer::CreateOutgoingUnidirectionalStream(
421 session_.get()),
422 "ShouldCreateOutgoingUnidirectionalStream called when disconnected");
423
424 EXPECT_EQ(initial_num_open_stream,
425 QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
426 }
427
TEST_P(QuicSimpleServerSessionTest,CreateOutgoingDynamicStreamUnencrypted)428 TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUnencrypted) {
429 // EXPECT_QUIC_BUG tests are expensive so only run one instance of them.
430 if (version() != AllSupportedVersions()[0]) {
431 return;
432 }
433
434 // Tests that outgoing stream creation fails when encryption has not yet been
435 // established.
436 size_t initial_num_open_stream =
437 QuicSessionPeer::GetNumOpenDynamicStreams(session_.get());
438 EXPECT_QUIC_BUG(
439 QuicSimpleServerSessionPeer::CreateOutgoingUnidirectionalStream(
440 session_.get()),
441 "Encryption not established so no outgoing stream created.");
442 EXPECT_EQ(initial_num_open_stream,
443 QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
444 }
445
446 // Tests that calling GetOrCreateStream() on an outgoing stream should result in
447 // the connection being closed.
TEST_P(QuicSimpleServerSessionTest,GetEvenIncomingError)448 TEST_P(QuicSimpleServerSessionTest, GetEvenIncomingError) {
449 const size_t initial_num_open_stream =
450 QuicSessionPeer::GetNumOpenDynamicStreams(session_.get());
451 const QuicErrorCode expected_error = VersionUsesHttp3(transport_version())
452 ? QUIC_HTTP_STREAM_WRONG_DIRECTION
453 : QUIC_INVALID_STREAM_ID;
454 EXPECT_CALL(*connection_, CloseConnection(expected_error,
455 "Data for nonexistent stream", _));
456 EXPECT_EQ(nullptr,
457 QuicSessionPeer::GetOrCreateStream(
458 session_.get(), GetNthServerInitiatedUnidirectionalId(3)));
459 EXPECT_EQ(initial_num_open_stream,
460 QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
461 }
462
463 } // namespace
464 } // namespace test
465 } // namespace quic
466