blob: 7fbce71a42ffdb98b7d8282e366541e79f1294d4 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// 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 "net/third_party/quiche/src/quic/tools/quic_simple_server_session.h"
6
7#include <algorithm>
8#include <memory>
9
QUICHE teama6ef0a62019-03-07 20:34:33 -050010#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
11#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
dschinazi56fb53e2019-06-21 15:30:04 -070012#include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters_proto.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050013#include "net/third_party/quiche/src/quic/core/quic_connection.h"
14#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h"
15#include "net/third_party/quiche/src/quic/core/quic_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050016#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
17#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
18#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
19#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
20#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
21#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
22#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
23#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
24#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
25#include "net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h"
26#include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h"
27#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
28#include "net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.h"
29#include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h"
30#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h"
31#include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h"
32#include "net/third_party/quiche/src/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h"
33#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
34#include "net/third_party/quiche/src/quic/tools/quic_backend_response.h"
35#include "net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h"
36#include "net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h"
37
38using testing::_;
39using testing::AtLeast;
40using testing::InSequence;
41using testing::Invoke;
42using testing::Return;
43using testing::StrictMock;
44
45namespace quic {
46namespace test {
47namespace {
renjietang2abedac2019-05-20 14:04:50 -070048
QUICHE teama6ef0a62019-03-07 20:34:33 -050049typedef QuicSimpleServerSession::PromisedStreamInfo PromisedStreamInfo;
renjietang2abedac2019-05-20 14:04:50 -070050
51const QuicByteCount kHeadersFrameHeaderLength = 2;
52const QuicByteCount kHeadersFramePayloadLength = 9;
53
QUICHE teama6ef0a62019-03-07 20:34:33 -050054} // namespace
55
56class QuicSimpleServerSessionPeer {
57 public:
58 static void SetCryptoStream(QuicSimpleServerSession* s,
59 QuicCryptoServerStream* crypto_stream) {
60 s->crypto_stream_.reset(crypto_stream);
QUICHE teama6ef0a62019-03-07 20:34:33 -050061 }
62
63 static QuicSpdyStream* CreateIncomingStream(QuicSimpleServerSession* s,
64 QuicStreamId id) {
65 return s->CreateIncomingStream(id);
66 }
67
68 static QuicSimpleServerStream* CreateOutgoingUnidirectionalStream(
69 QuicSimpleServerSession* s) {
70 return s->CreateOutgoingUnidirectionalStream();
71 }
72};
73
74namespace {
75
76const size_t kMaxStreamsForTest = 10;
77
78class MockQuicCryptoServerStream : public QuicCryptoServerStream {
79 public:
80 explicit MockQuicCryptoServerStream(
81 const QuicCryptoServerConfig* crypto_config,
82 QuicCompressedCertsCache* compressed_certs_cache,
83 QuicServerSessionBase* session,
84 QuicCryptoServerStream::Helper* helper)
85 : QuicCryptoServerStream(
86 crypto_config,
87 compressed_certs_cache,
QUICHE teama6ef0a62019-03-07 20:34:33 -050088 session,
89 helper) {}
90 MockQuicCryptoServerStream(const MockQuicCryptoServerStream&) = delete;
91 MockQuicCryptoServerStream& operator=(const MockQuicCryptoServerStream&) =
92 delete;
93 ~MockQuicCryptoServerStream() override {}
94
95 MOCK_METHOD1(SendServerConfigUpdate,
96 void(const CachedNetworkParameters* cached_network_parameters));
97
98 void set_encryption_established(bool has_established) {
99 encryption_established_override_ = has_established;
100 }
101
102 bool encryption_established() const override {
103 return QuicCryptoServerStream::encryption_established() ||
104 encryption_established_override_;
105 }
106
107 private:
108 bool encryption_established_override_ = false;
109};
110
111class MockQuicConnectionWithSendStreamData : public MockQuicConnection {
112 public:
113 MockQuicConnectionWithSendStreamData(
114 MockQuicConnectionHelper* helper,
115 MockAlarmFactory* alarm_factory,
116 Perspective perspective,
117 const ParsedQuicVersionVector& supported_versions)
118 : MockQuicConnection(helper,
119 alarm_factory,
120 perspective,
121 supported_versions) {
dschinazi17d42422019-06-18 16:35:07 -0700122 auto consume_all_data = [](QuicStreamId /*id*/, size_t write_length,
123 QuicStreamOffset /*offset*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500124 StreamSendingState state) {
125 return QuicConsumedData(write_length, state != NO_FIN);
126 };
127 ON_CALL(*this, SendStreamData(_, _, _, _))
128 .WillByDefault(Invoke(consume_all_data));
129 }
130
131 MOCK_METHOD4(SendStreamData,
132 QuicConsumedData(QuicStreamId id,
133 size_t write_length,
134 QuicStreamOffset offset,
135 StreamSendingState state));
136};
137
138class MockQuicSimpleServerSession : public QuicSimpleServerSession {
139 public:
140 MockQuicSimpleServerSession(
141 const QuicConfig& config,
142 QuicConnection* connection,
143 QuicSession::Visitor* visitor,
144 QuicCryptoServerStream::Helper* helper,
145 const QuicCryptoServerConfig* crypto_config,
146 QuicCompressedCertsCache* compressed_certs_cache,
147 QuicSimpleServerBackend* quic_simple_server_backend)
148 : QuicSimpleServerSession(config,
149 CurrentSupportedVersions(),
150 connection,
151 visitor,
152 helper,
153 crypto_config,
154 compressed_certs_cache,
155 quic_simple_server_backend) {}
156 // Methods taking non-copyable types like SpdyHeaderBlock by value cannot be
157 // mocked directly.
renjietangf4f47122019-07-22 12:08:53 -0700158 void WritePushPromise(QuicStreamId original_stream_id,
159 QuicStreamId promised_stream_id,
160 spdy::SpdyHeaderBlock headers) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500161 return WritePushPromiseMock(original_stream_id, promised_stream_id,
162 headers);
163 }
164 MOCK_METHOD3(WritePushPromiseMock,
renjietangf4f47122019-07-22 12:08:53 -0700165 void(QuicStreamId original_stream_id,
166 QuicStreamId promised_stream_id,
167 const spdy::SpdyHeaderBlock& headers));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500168
169 MOCK_METHOD1(SendBlocked, void(QuicStreamId));
170};
171
172class QuicSimpleServerSessionTest
173 : public QuicTestWithParam<ParsedQuicVersion> {
174 public:
fkastenholz3c4eabf2019-04-22 07:49:59 -0700175 // The function ensures that A) the MAX_STREAMS frames get properly deleted
QUICHE teama6ef0a62019-03-07 20:34:33 -0500176 // (since the test uses a 'did we leak memory' check ... if we just lose the
177 // frame, the test fails) and B) returns true (instead of the default, false)
178 // which ensures that the rest of the system thinks that the frame actually
179 // was transmitted.
fkastenholz3c4eabf2019-04-22 07:49:59 -0700180 bool ClearMaxStreamsControlFrame(const QuicFrame& frame) {
181 if (frame.type == MAX_STREAMS_FRAME) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500182 DeleteFrame(&const_cast<QuicFrame&>(frame));
183 return true;
184 }
185 return false;
186 }
187
188 protected:
189 QuicSimpleServerSessionTest()
190 : crypto_config_(QuicCryptoServerConfig::TESTING,
191 QuicRandom::GetInstance(),
192 crypto_test_utils::ProofSourceForTesting(),
nharper6ebe83b2019-06-13 17:43:52 -0700193 KeyExchangeSource::Default()),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500194 compressed_certs_cache_(
195 QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) {
nharperf5e68452019-05-29 17:24:18 -0700196 SetQuicFlag(FLAGS_quic_supports_tls_handshake, true);
fkastenholzd3a1de92019-05-15 07:00:07 -0700197 config_.SetMaxIncomingBidirectionalStreamsToSend(kMaxStreamsForTest);
198 QuicConfigPeer::SetReceivedMaxIncomingBidirectionalStreams(
199 &config_, kMaxStreamsForTest);
200 config_.SetMaxIncomingUnidirectionalStreamsToSend(kMaxStreamsForTest);
201 QuicConfigPeer::SetReceivedMaxIncomingUnidirectionalStreams(
202 &config_, kMaxStreamsForTest);
203
QUICHE teama6ef0a62019-03-07 20:34:33 -0500204 config_.SetInitialStreamFlowControlWindowToSend(
205 kInitialStreamFlowControlWindowForTest);
206 config_.SetInitialSessionFlowControlWindowToSend(
207 kInitialSessionFlowControlWindowForTest);
208
209 ParsedQuicVersionVector supported_versions = SupportedVersions(GetParam());
210 connection_ = new StrictMock<MockQuicConnectionWithSendStreamData>(
211 &helper_, &alarm_factory_, Perspective::IS_SERVER, supported_versions);
212 connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
213 session_ = QuicMakeUnique<MockQuicSimpleServerSession>(
214 config_, connection_, &owner_, &stream_helper_, &crypto_config_,
215 &compressed_certs_cache_, &memory_cache_backend_);
216 MockClock clock;
QUICHE teamd5af58a2019-03-14 20:35:50 -0700217 handshake_message_ = crypto_config_.AddDefaultConfig(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500218 QuicRandom::GetInstance(), &clock,
QUICHE teamd5af58a2019-03-14 20:35:50 -0700219 QuicCryptoServerConfig::ConfigOptions());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500220 session_->Initialize();
221 QuicSessionPeer::GetMutableCryptoStream(session_.get())
222 ->OnSuccessfulVersionNegotiation(supported_versions.front());
223 visitor_ = QuicConnectionPeer::GetVisitor(connection_);
224
fkastenholz305e1732019-06-18 05:01:22 -0700225 if (VersionHasIetfQuicFrames(transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500226 EXPECT_CALL(*connection_, SendControlFrame(_))
227 .WillRepeatedly(Invoke(
fkastenholz3c4eabf2019-04-22 07:49:59 -0700228 this, &QuicSimpleServerSessionTest::ClearMaxStreamsControlFrame));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500229 }
230 session_->OnConfigNegotiated();
231 }
232
233 QuicStreamId GetNthClientInitiatedBidirectionalId(int n) {
234 return GetNthClientInitiatedBidirectionalStreamId(
235 connection_->transport_version(), n);
236 }
237
238 QuicStreamId GetNthServerInitiatedUnidirectionalId(int n) {
239 return quic::test::GetNthServerInitiatedUnidirectionalStreamId(
240 connection_->transport_version(), n);
241 }
242
fkastenholz305e1732019-06-18 05:01:22 -0700243 QuicTransportVersion transport_version() const {
244 return connection_->transport_version();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500245 }
246
247 void InjectStopSending(QuicStreamId stream_id,
248 QuicRstStreamErrorCode rst_stream_code) {
249 // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
250 // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
251 // a one-way close.
fkastenholz305e1732019-06-18 05:01:22 -0700252 if (!VersionHasIetfQuicFrames(transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500253 // Only needed for version 99/IETF QUIC.
254 return;
255 }
256 EXPECT_CALL(owner_, OnStopSendingReceived(_)).Times(1);
257 QuicStopSendingFrame stop_sending(
258 kInvalidControlFrameId, stream_id,
259 static_cast<QuicApplicationErrorCode>(rst_stream_code));
260 // Expect the RESET_STREAM that is generated in response to receiving a
261 // STOP_SENDING.
262 EXPECT_CALL(*connection_, OnStreamReset(stream_id, rst_stream_code));
263 session_->OnStopSendingFrame(stop_sending);
264 }
265
266 StrictMock<MockQuicSessionVisitor> owner_;
267 StrictMock<MockQuicCryptoServerStreamHelper> stream_helper_;
268 MockQuicConnectionHelper helper_;
269 MockAlarmFactory alarm_factory_;
270 StrictMock<MockQuicConnectionWithSendStreamData>* connection_;
271 QuicConfig config_;
272 QuicCryptoServerConfig crypto_config_;
273 QuicCompressedCertsCache compressed_certs_cache_;
274 QuicMemoryCacheBackend memory_cache_backend_;
275 std::unique_ptr<MockQuicSimpleServerSession> session_;
276 std::unique_ptr<CryptoHandshakeMessage> handshake_message_;
277 QuicConnectionVisitorInterface* visitor_;
278};
279
280INSTANTIATE_TEST_SUITE_P(Tests,
281 QuicSimpleServerSessionTest,
282 ::testing::ValuesIn(AllSupportedVersions()));
283
284TEST_P(QuicSimpleServerSessionTest, CloseStreamDueToReset) {
285 // Open a stream, then reset it.
286 // Send two bytes of payload to open it.
287 QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0,
288 QuicStringPiece("HT"));
289 session_->OnStreamFrame(data1);
290 EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams());
291
292 // Receive a reset (and send a RST in response).
293 QuicRstStreamFrame rst1(kInvalidControlFrameId,
294 GetNthClientInitiatedBidirectionalId(0),
295 QUIC_ERROR_PROCESSING_STREAM, 0);
296 EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
297 EXPECT_CALL(*connection_, SendControlFrame(_));
fkastenholz305e1732019-06-18 05:01:22 -0700298 if (!VersionHasIetfQuicFrames(transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500299 // For version 99, this is covered in InjectStopSending()
300 EXPECT_CALL(*connection_,
301 OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
302 QUIC_RST_ACKNOWLEDGEMENT));
303 }
304 visitor_->OnRstStream(rst1);
305 // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
306 // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
307 // a one-way close.
308 InjectStopSending(GetNthClientInitiatedBidirectionalId(0),
309 QUIC_ERROR_PROCESSING_STREAM);
310 EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
311
312 // Send the same two bytes of payload in a new packet.
313 visitor_->OnStreamFrame(data1);
314
315 // The stream should not be re-opened.
316 EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
317 EXPECT_TRUE(connection_->connected());
318}
319
320TEST_P(QuicSimpleServerSessionTest, NeverOpenStreamDueToReset) {
321 // Send a reset (and expect the peer to send a RST in response).
322 QuicRstStreamFrame rst1(kInvalidControlFrameId,
323 GetNthClientInitiatedBidirectionalId(0),
324 QUIC_ERROR_PROCESSING_STREAM, 0);
325 EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
fkastenholz305e1732019-06-18 05:01:22 -0700326 if (!VersionHasIetfQuicFrames(transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500327 EXPECT_CALL(*connection_, SendControlFrame(_));
328 // For version 99, this is covered in InjectStopSending()
329 EXPECT_CALL(*connection_,
330 OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
331 QUIC_RST_ACKNOWLEDGEMENT));
332 }
333 visitor_->OnRstStream(rst1);
334 // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
335 // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
336 // a one-way close.
337 InjectStopSending(GetNthClientInitiatedBidirectionalId(0),
338 QUIC_ERROR_PROCESSING_STREAM);
339
340 EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
341
342 // Send two bytes of payload.
343 QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0,
344 QuicStringPiece("HT"));
345 visitor_->OnStreamFrame(data1);
346
347 // The stream should never be opened, now that the reset is received.
348 EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
349 EXPECT_TRUE(connection_->connected());
350}
351
352TEST_P(QuicSimpleServerSessionTest, AcceptClosedStream) {
353 // Send (empty) compressed headers followed by two bytes of data.
354 QuicStreamFrame frame1(GetNthClientInitiatedBidirectionalId(0), false, 0,
355 QuicStringPiece("\1\0\0\0\0\0\0\0HT"));
356 QuicStreamFrame frame2(GetNthClientInitiatedBidirectionalId(1), false, 0,
357 QuicStringPiece("\2\0\0\0\0\0\0\0HT"));
358 visitor_->OnStreamFrame(frame1);
359 visitor_->OnStreamFrame(frame2);
360 EXPECT_EQ(2u, session_->GetNumOpenIncomingStreams());
361
362 // Send a reset (and expect the peer to send a RST in response).
363 QuicRstStreamFrame rst(kInvalidControlFrameId,
364 GetNthClientInitiatedBidirectionalId(0),
365 QUIC_ERROR_PROCESSING_STREAM, 0);
366 EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
fkastenholz305e1732019-06-18 05:01:22 -0700367 if (!VersionHasIetfQuicFrames(transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500368 EXPECT_CALL(*connection_, SendControlFrame(_));
369 // For version 99, this is covered in InjectStopSending()
370 EXPECT_CALL(*connection_,
371 OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
372 QUIC_RST_ACKNOWLEDGEMENT));
373 }
374 visitor_->OnRstStream(rst);
375 // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
376 // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
377 // a one-way close.
378 InjectStopSending(GetNthClientInitiatedBidirectionalId(0),
379 QUIC_ERROR_PROCESSING_STREAM);
380
381 // If we were tracking, we'd probably want to reject this because it's data
382 // past the reset point of stream 3. As it's a closed stream we just drop the
383 // data on the floor, but accept the packet because it has data for stream 5.
384 QuicStreamFrame frame3(GetNthClientInitiatedBidirectionalId(0), false, 2,
385 QuicStringPiece("TP"));
386 QuicStreamFrame frame4(GetNthClientInitiatedBidirectionalId(1), false, 2,
387 QuicStringPiece("TP"));
388 visitor_->OnStreamFrame(frame3);
389 visitor_->OnStreamFrame(frame4);
390 // The stream should never be opened, now that the reset is received.
391 EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams());
392 EXPECT_TRUE(connection_->connected());
393}
394
395TEST_P(QuicSimpleServerSessionTest, CreateIncomingStreamDisconnected) {
396 // EXPECT_QUIC_BUG tests are expensive so only run one instance of them.
397 if (GetParam() != AllSupportedVersions()[0]) {
398 return;
399 }
400
401 // Tests that incoming stream creation fails when connection is not connected.
402 size_t initial_num_open_stream = session_->GetNumOpenIncomingStreams();
403 QuicConnectionPeer::TearDownLocalConnectionState(connection_);
404 EXPECT_QUIC_BUG(QuicSimpleServerSessionPeer::CreateIncomingStream(
405 session_.get(), GetNthClientInitiatedBidirectionalId(0)),
406 "ShouldCreateIncomingStream called when disconnected");
407 EXPECT_EQ(initial_num_open_stream, session_->GetNumOpenIncomingStreams());
408}
409
410TEST_P(QuicSimpleServerSessionTest, CreateEvenIncomingDynamicStream) {
411 // Tests that incoming stream creation fails when given stream id is even.
412 size_t initial_num_open_stream = session_->GetNumOpenIncomingStreams();
413 EXPECT_CALL(*connection_,
414 CloseConnection(QUIC_INVALID_STREAM_ID,
415 "Client created even numbered stream", _));
416 QuicSimpleServerSessionPeer::CreateIncomingStream(
417 session_.get(), GetNthServerInitiatedUnidirectionalId(0));
418 EXPECT_EQ(initial_num_open_stream, session_->GetNumOpenIncomingStreams());
419}
420
421TEST_P(QuicSimpleServerSessionTest, CreateIncomingStream) {
422 QuicSpdyStream* stream = QuicSimpleServerSessionPeer::CreateIncomingStream(
423 session_.get(), GetNthClientInitiatedBidirectionalId(0));
424 EXPECT_NE(nullptr, stream);
425 EXPECT_EQ(GetNthClientInitiatedBidirectionalId(0), stream->id());
426}
427
428TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamDisconnected) {
429 // EXPECT_QUIC_BUG tests are expensive so only run one instance of them.
430 if (GetParam() != AllSupportedVersions()[0]) {
431 return;
432 }
433
434 // Tests that outgoing stream creation fails when connection is not connected.
435 size_t initial_num_open_stream = session_->GetNumOpenOutgoingStreams();
436 QuicConnectionPeer::TearDownLocalConnectionState(connection_);
437 EXPECT_QUIC_BUG(
438 QuicSimpleServerSessionPeer::CreateOutgoingUnidirectionalStream(
439 session_.get()),
440 "ShouldCreateOutgoingUnidirectionalStream called when disconnected");
441
442 EXPECT_EQ(initial_num_open_stream, session_->GetNumOpenOutgoingStreams());
443}
444
445TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUnencrypted) {
446 // EXPECT_QUIC_BUG tests are expensive so only run one instance of them.
447 if (GetParam() != AllSupportedVersions()[0]) {
448 return;
449 }
450
451 // Tests that outgoing stream creation fails when encryption has not yet been
452 // established.
453 size_t initial_num_open_stream = session_->GetNumOpenOutgoingStreams();
454 EXPECT_QUIC_BUG(
455 QuicSimpleServerSessionPeer::CreateOutgoingUnidirectionalStream(
456 session_.get()),
457 "Encryption not established so no outgoing stream created.");
458 EXPECT_EQ(initial_num_open_stream, session_->GetNumOpenOutgoingStreams());
459}
460
461TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUptoLimit) {
462 // Tests that outgoing stream creation should not be affected by existing
463 // incoming stream and vice-versa. But when reaching the limit of max outgoing
464 // stream allowed, creation should fail.
465
466 // Receive some data to initiate a incoming stream which should not effect
467 // creating outgoing streams.
468 QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0,
469 QuicStringPiece("HT"));
470 session_->OnStreamFrame(data1);
471 EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams());
472 EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams());
473
renjietang118c8ac2019-07-30 11:43:59 -0700474 if (!VersionUsesQpack(connection_->transport_version())) {
475 session_->UnregisterStreamPriority(
476 QuicUtils::GetHeadersStreamId(connection_->transport_version()),
477 /*is_static=*/true);
478 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500479 // Assume encryption already established.
480 QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), nullptr);
481 MockQuicCryptoServerStream* crypto_stream =
482 new MockQuicCryptoServerStream(&crypto_config_, &compressed_certs_cache_,
483 session_.get(), &stream_helper_);
484 crypto_stream->set_encryption_established(true);
485 QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream);
renjietang118c8ac2019-07-30 11:43:59 -0700486 if (!VersionUsesQpack(connection_->transport_version())) {
487 session_->RegisterStreamPriority(
488 QuicUtils::GetHeadersStreamId(connection_->transport_version()),
489 /*is_static=*/true,
490 spdy::SpdyStreamPrecedence(QuicStream::kDefaultPriority));
491 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500492
493 // Create push streams till reaching the upper limit of allowed open streams.
494 for (size_t i = 0; i < kMaxStreamsForTest; ++i) {
495 QuicSpdyStream* created_stream =
496 QuicSimpleServerSessionPeer::CreateOutgoingUnidirectionalStream(
497 session_.get());
renjietang3a1bb802019-06-11 10:42:41 -0700498 if (VersionHasStreamType(connection_->transport_version())) {
499 EXPECT_EQ(GetNthServerInitiatedUnidirectionalId(i + 1),
500 created_stream->id());
501 } else {
502 EXPECT_EQ(GetNthServerInitiatedUnidirectionalId(i), created_stream->id());
503 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500504 EXPECT_EQ(i + 1, session_->GetNumOpenOutgoingStreams());
505 }
506
507 // Continuing creating push stream would fail.
508 EXPECT_EQ(nullptr,
509 QuicSimpleServerSessionPeer::CreateOutgoingUnidirectionalStream(
510 session_.get()));
511 EXPECT_EQ(kMaxStreamsForTest, session_->GetNumOpenOutgoingStreams());
512
513 // Create peer initiated stream should have no problem.
514 QuicStreamFrame data2(GetNthClientInitiatedBidirectionalId(1), false, 0,
515 QuicStringPiece("HT"));
516 session_->OnStreamFrame(data2);
517 EXPECT_EQ(2u, session_->GetNumOpenIncomingStreams());
518}
519
520TEST_P(QuicSimpleServerSessionTest, OnStreamFrameWithEvenStreamId) {
521 QuicStreamFrame frame(GetNthServerInitiatedUnidirectionalId(0), false, 0,
522 QuicStringPiece());
523 EXPECT_CALL(*connection_,
524 CloseConnection(QUIC_INVALID_STREAM_ID,
525 "Client sent data on server push stream", _));
526 session_->OnStreamFrame(frame);
527}
528
529TEST_P(QuicSimpleServerSessionTest, GetEvenIncomingError) {
renjietang880d2432019-07-16 13:14:37 -0700530 // Tests that calling GetOrCreateStream() on an outgoing stream not
QUICHE teama6ef0a62019-03-07 20:34:33 -0500531 // promised yet should result close connection.
532 EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID,
533 "Data for nonexistent stream", _));
534 EXPECT_EQ(nullptr,
renjietang880d2432019-07-16 13:14:37 -0700535 QuicSessionPeer::GetOrCreateStream(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500536 session_.get(), GetNthServerInitiatedUnidirectionalId(1)));
537}
538
539// In order to test the case where server push stream creation goes beyond
540// limit, server push streams need to be hanging there instead of
541// immediately closing after sending back response.
542// To achieve this goal, this class resets flow control windows so that large
543// responses will not be sent fully in order to prevent push streams from being
544// closed immediately.
545// Also adjust connection-level flow control window to ensure a large response
546// can cause stream-level flow control blocked but not connection-level.
547class QuicSimpleServerSessionServerPushTest
548 : public QuicSimpleServerSessionTest {
549 protected:
550 const size_t kStreamFlowControlWindowSize = 32 * 1024; // 32KB.
551
552 QuicSimpleServerSessionServerPushTest() {
553 // Reset stream level flow control window to be 32KB.
554 QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow(
555 &config_, kStreamFlowControlWindowSize);
556 // Reset connection level flow control window to be 1.5 MB which is large
557 // enough that it won't block any stream to write before stream level flow
558 // control blocks it.
559 QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(
560 &config_, kInitialSessionFlowControlWindowForTest);
561
562 ParsedQuicVersionVector supported_versions = SupportedVersions(GetParam());
563 connection_ = new StrictMock<MockQuicConnectionWithSendStreamData>(
564 &helper_, &alarm_factory_, Perspective::IS_SERVER, supported_versions);
565 session_ = QuicMakeUnique<MockQuicSimpleServerSession>(
566 config_, connection_, &owner_, &stream_helper_, &crypto_config_,
567 &compressed_certs_cache_, &memory_cache_backend_);
568 session_->Initialize();
569 QuicSessionPeer::GetMutableCryptoStream(session_.get())
570 ->OnSuccessfulVersionNegotiation(supported_versions.front());
571 // Needed to make new session flow control window and server push work.
572
fkastenholz305e1732019-06-18 05:01:22 -0700573 if (VersionHasIetfQuicFrames(transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500574 EXPECT_CALL(*connection_, SendControlFrame(_))
575 .WillRepeatedly(Invoke(this, &QuicSimpleServerSessionServerPushTest::
fkastenholz3c4eabf2019-04-22 07:49:59 -0700576 ClearMaxStreamsControlFrame));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500577 }
578 session_->OnConfigNegotiated();
579
580 visitor_ = QuicConnectionPeer::GetVisitor(connection_);
581
renjietang118c8ac2019-07-30 11:43:59 -0700582 if (!VersionUsesQpack(connection_->transport_version())) {
583 session_->UnregisterStreamPriority(
584 QuicUtils::GetHeadersStreamId(connection_->transport_version()),
585 /*is_static=*/true);
586 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500587 QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), nullptr);
588 // Assume encryption already established.
589 MockQuicCryptoServerStream* crypto_stream = new MockQuicCryptoServerStream(
590 &crypto_config_, &compressed_certs_cache_, session_.get(),
591 &stream_helper_);
592
593 crypto_stream->set_encryption_established(true);
594 QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream);
renjietang118c8ac2019-07-30 11:43:59 -0700595 if (!VersionUsesQpack(connection_->transport_version())) {
596 session_->RegisterStreamPriority(
597 QuicUtils::GetHeadersStreamId(connection_->transport_version()),
598 /*is_static=*/true,
599 spdy::SpdyStreamPrecedence(QuicStream::kDefaultPriority));
600 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500601 }
602
603 // Given |num_resources|, create this number of fake push resources and push
604 // them by sending PUSH_PROMISE for all and sending push responses for as much
605 // as possible(limited by kMaxStreamsForTest).
606 // If |num_resources| > kMaxStreamsForTest, the left over will be queued.
bnc6ca84fb2019-03-14 13:51:12 -0700607 // Returns the length of the DATA frame header, or 0 if the version does not
608 // use DATA frames.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500609 QuicByteCount PromisePushResources(size_t num_resources) {
610 // testing::InSequence seq;
611 // To prevent push streams from being closed the response need to be larger
612 // than stream flow control window so stream won't send the full body.
613 size_t body_size = 2 * kStreamFlowControlWindowSize; // 64KB.
614
vasilvvc48c8712019-03-11 13:38:16 -0700615 std::string request_url = "mail.google.com/";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500616 spdy::SpdyHeaderBlock request_headers;
vasilvvc48c8712019-03-11 13:38:16 -0700617 std::string resource_host = "www.google.com";
618 std::string partial_push_resource_path = "/server_push_src";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500619 std::list<QuicBackendResponse::ServerPushInfo> push_resources;
vasilvvc48c8712019-03-11 13:38:16 -0700620 std::string scheme = "http";
bnc6ca84fb2019-03-14 13:51:12 -0700621 QuicByteCount data_frame_header_length = 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500622 for (unsigned int i = 1; i <= num_resources; ++i) {
renjietang3a1bb802019-06-11 10:42:41 -0700623 QuicStreamId stream_id;
624 if (VersionHasStreamType(connection_->transport_version())) {
625 stream_id = GetNthServerInitiatedUnidirectionalId(i);
626 } else {
627 stream_id = GetNthServerInitiatedUnidirectionalId(i - 1);
628 }
vasilvvc48c8712019-03-11 13:38:16 -0700629 std::string path =
QUICHE teama6ef0a62019-03-07 20:34:33 -0500630 partial_push_resource_path + QuicTextUtils::Uint64ToString(i);
vasilvvc48c8712019-03-11 13:38:16 -0700631 std::string url = scheme + "://" + resource_host + path;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500632 QuicUrl resource_url = QuicUrl(url);
vasilvvc48c8712019-03-11 13:38:16 -0700633 std::string body(body_size, 'a');
634 std::string data;
bnc6ca84fb2019-03-14 13:51:12 -0700635 data_frame_header_length = 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500636 if (VersionHasDataFrameHeader(connection_->transport_version())) {
637 HttpEncoder encoder;
638 std::unique_ptr<char[]> buffer;
bnc6ca84fb2019-03-14 13:51:12 -0700639 data_frame_header_length =
QUICHE teama6ef0a62019-03-07 20:34:33 -0500640 encoder.SerializeDataFrameHeader(body.length(), &buffer);
bnc6ca84fb2019-03-14 13:51:12 -0700641 std::string header(buffer.get(), data_frame_header_length);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500642 data = header + body;
643 } else {
644 data = body;
645 }
646
647 memory_cache_backend_.AddSimpleResponse(resource_host, path, 200, data);
648 push_resources.push_back(QuicBackendResponse::ServerPushInfo(
649 resource_url, spdy::SpdyHeaderBlock(), QuicStream::kDefaultPriority,
650 body));
651 // PUSH_PROMISED are sent for all the resources.
652 EXPECT_CALL(*session_,
653 WritePushPromiseMock(GetNthClientInitiatedBidirectionalId(0),
654 stream_id, _));
655 if (i <= kMaxStreamsForTest) {
656 // |kMaxStreamsForTest| promised responses should be sent.
657 // Since flow control window is smaller than response body, not the
658 // whole body will be sent.
bnc6ca84fb2019-03-14 13:51:12 -0700659 QuicStreamOffset offset = 0;
renjietangbb1c4892019-05-24 15:58:44 -0700660 if (VersionHasStreamType(connection_->transport_version())) {
661 EXPECT_CALL(*connection_,
662 SendStreamData(stream_id, 1, offset, NO_FIN));
663 offset++;
664 }
665
renjietang2abedac2019-05-20 14:04:50 -0700666 if (VersionUsesQpack(connection_->transport_version())) {
667 EXPECT_CALL(*connection_,
668 SendStreamData(stream_id, kHeadersFrameHeaderLength,
669 offset, NO_FIN));
670 offset += kHeadersFrameHeaderLength;
671 EXPECT_CALL(*connection_,
672 SendStreamData(stream_id, kHeadersFramePayloadLength,
673 offset, NO_FIN));
674 offset += kHeadersFramePayloadLength;
675 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500676 if (VersionHasDataFrameHeader(connection_->transport_version())) {
677 EXPECT_CALL(*connection_,
bnc6ca84fb2019-03-14 13:51:12 -0700678 SendStreamData(stream_id, data_frame_header_length,
679 offset, NO_FIN));
680 offset += data_frame_header_length;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500681 }
bnc6ca84fb2019-03-14 13:51:12 -0700682 EXPECT_CALL(*connection_, SendStreamData(stream_id, _, offset, NO_FIN))
QUICHE teama6ef0a62019-03-07 20:34:33 -0500683 .WillOnce(Return(QuicConsumedData(
bnc6ca84fb2019-03-14 13:51:12 -0700684 kStreamFlowControlWindowSize - offset, false)));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500685 EXPECT_CALL(*session_, SendBlocked(stream_id));
686 }
687 }
fayang9a423762019-07-31 08:12:58 -0700688 session_->PromisePushResources(
689 request_url, push_resources, GetNthClientInitiatedBidirectionalId(0),
690 spdy::SpdyStreamPrecedence(0, spdy::kHttp2DefaultStreamWeight, false),
691 request_headers);
bnc6ca84fb2019-03-14 13:51:12 -0700692 return data_frame_header_length;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500693 }
694
renjietang2abedac2019-05-20 14:04:50 -0700695 void MaybeConsumeHeadersStreamData() {
696 if (!VersionUsesQpack(connection_->transport_version())) {
697 QuicStreamId headers_stream_id =
698 QuicUtils::GetHeadersStreamId(connection_->transport_version());
699 EXPECT_CALL(*connection_, SendStreamData(headers_stream_id, _, _, _))
700 .Times(AtLeast(1));
701 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500702 }
703};
704
705INSTANTIATE_TEST_SUITE_P(Tests,
706 QuicSimpleServerSessionServerPushTest,
707 ::testing::ValuesIn(AllSupportedVersions()));
708
709// Tests that given more than kMaxStreamsForTest resources, all their
710// PUSH_PROMISE's will be sent out and only kMaxStreamsForTest streams will be
711// opened and send push response.
712TEST_P(QuicSimpleServerSessionServerPushTest, TestPromisePushResources) {
renjietang2abedac2019-05-20 14:04:50 -0700713 MaybeConsumeHeadersStreamData();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500714 size_t num_resources = kMaxStreamsForTest + 5;
715 PromisePushResources(num_resources);
716 EXPECT_EQ(kMaxStreamsForTest, session_->GetNumOpenOutgoingStreams());
717}
718
719// Tests that after promised stream queued up, when an opened stream is marked
720// draining, a queued promised stream will become open and send push response.
721TEST_P(QuicSimpleServerSessionServerPushTest,
722 HandlePromisedPushRequestsAfterStreamDraining) {
renjietang2abedac2019-05-20 14:04:50 -0700723 MaybeConsumeHeadersStreamData();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500724 size_t num_resources = kMaxStreamsForTest + 1;
bnc6ca84fb2019-03-14 13:51:12 -0700725 QuicByteCount data_frame_header_length = PromisePushResources(num_resources);
renjietang3a1bb802019-06-11 10:42:41 -0700726 QuicStreamId next_out_going_stream_id;
727 if (VersionHasStreamType(connection_->transport_version())) {
728 next_out_going_stream_id =
729 GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 1);
730 } else {
731 next_out_going_stream_id =
732 GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest);
733 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500734
735 // After an open stream is marked draining, a new stream is expected to be
736 // created and a response sent on the stream.
bnc6ca84fb2019-03-14 13:51:12 -0700737 QuicStreamOffset offset = 0;
renjietangbb1c4892019-05-24 15:58:44 -0700738 if (VersionHasStreamType(connection_->transport_version())) {
739 EXPECT_CALL(*connection_,
740 SendStreamData(next_out_going_stream_id, 1, offset, NO_FIN));
741 offset++;
742 }
renjietang2abedac2019-05-20 14:04:50 -0700743 if (VersionUsesQpack(connection_->transport_version())) {
744 EXPECT_CALL(*connection_,
745 SendStreamData(next_out_going_stream_id,
746 kHeadersFrameHeaderLength, offset, NO_FIN));
747 offset += kHeadersFrameHeaderLength;
748 EXPECT_CALL(*connection_,
749 SendStreamData(next_out_going_stream_id,
750 kHeadersFramePayloadLength, offset, NO_FIN));
751 offset += kHeadersFramePayloadLength;
752 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500753 if (VersionHasDataFrameHeader(connection_->transport_version())) {
bnc6ca84fb2019-03-14 13:51:12 -0700754 EXPECT_CALL(*connection_,
755 SendStreamData(next_out_going_stream_id,
756 data_frame_header_length, offset, NO_FIN));
757 offset += data_frame_header_length;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500758 }
bnc6ca84fb2019-03-14 13:51:12 -0700759 EXPECT_CALL(*connection_,
760 SendStreamData(next_out_going_stream_id, _, offset, NO_FIN))
761 .WillOnce(Return(
762 QuicConsumedData(kStreamFlowControlWindowSize - offset, false)));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500763 EXPECT_CALL(*session_, SendBlocked(next_out_going_stream_id));
764
fkastenholz305e1732019-06-18 05:01:22 -0700765 if (VersionHasIetfQuicFrames(transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500766 // The PromisePushedResources call, above, will have used all available
767 // stream ids. For version 99, stream ids are not made available until
fkastenholz3c4eabf2019-04-22 07:49:59 -0700768 // a MAX_STREAMS frame is received. This emulates the reception of one.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500769 // For pre-v-99, the node monitors its own stream usage and makes streams
770 // available as it closes/etc them.
renjietang3a1bb802019-06-11 10:42:41 -0700771 // Version 99 also has unidirectional static streams, so we need to send
772 // MaxStreamFrame of the number of resources + number of static streams.
fkastenholz3c4eabf2019-04-22 07:49:59 -0700773 session_->OnMaxStreamsFrame(
renjietang3a1bb802019-06-11 10:42:41 -0700774 QuicMaxStreamsFrame(0, num_resources + 1, /*unidirectional=*/true));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500775 }
fkastenholz3c4eabf2019-04-22 07:49:59 -0700776
renjietang3a1bb802019-06-11 10:42:41 -0700777 if (VersionHasStreamType(connection_->transport_version())) {
778 session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(1));
779 } else {
780 session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(0));
781 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500782 // Number of open outgoing streams should still be the same, because a new
783 // stream is opened. And the queue should be empty.
784 EXPECT_EQ(kMaxStreamsForTest, session_->GetNumOpenOutgoingStreams());
785}
786
787// Tests that after all resources are promised, a RST frame from client can
788// prevent a promised resource to be send out.
789TEST_P(QuicSimpleServerSessionServerPushTest,
790 ResetPromisedStreamToCancelServerPush) {
renjietang2abedac2019-05-20 14:04:50 -0700791 MaybeConsumeHeadersStreamData();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500792
793 // Having two extra resources to be send later. One of them will be reset, so
794 // when opened stream become close, only one will become open.
795 size_t num_resources = kMaxStreamsForTest + 2;
fkastenholz305e1732019-06-18 05:01:22 -0700796 if (VersionHasIetfQuicFrames(transport_version())) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700797 // V99 will send out a STREAMS_BLOCKED frame when it tries to exceed the
798 // limit. This will clear the frames so that they do not block the later
QUICHE teama6ef0a62019-03-07 20:34:33 -0500799 // rst-stream frame.
800 EXPECT_CALL(*connection_, SendControlFrame(_))
bnc5b3c3be2019-06-25 10:37:09 -0700801 .WillOnce(Invoke(&ClearControlFrame));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500802 }
bnc6ca84fb2019-03-14 13:51:12 -0700803 QuicByteCount data_frame_header_length = PromisePushResources(num_resources);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500804
805 // Reset the last stream in the queue. It should be marked cancelled.
renjietang3a1bb802019-06-11 10:42:41 -0700806 QuicStreamId stream_got_reset;
807 if (VersionHasStreamType(connection_->transport_version())) {
808 stream_got_reset =
809 GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 2);
810 } else {
811 stream_got_reset =
812 GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 1);
813 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500814 QuicRstStreamFrame rst(kInvalidControlFrameId, stream_got_reset,
815 QUIC_STREAM_CANCELLED, 0);
816 EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
817 EXPECT_CALL(*connection_, SendControlFrame(_))
bnc5b3c3be2019-06-25 10:37:09 -0700818 .WillOnce(Invoke(&ClearControlFrame));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500819 EXPECT_CALL(*connection_,
820 OnStreamReset(stream_got_reset, QUIC_RST_ACKNOWLEDGEMENT));
821 visitor_->OnRstStream(rst);
822
823 // When the first 2 streams becomes draining, the two queued up stream could
824 // be created. But since one of them was marked cancelled due to RST frame,
825 // only one queued resource will be sent out.
renjietang3a1bb802019-06-11 10:42:41 -0700826 QuicStreamId stream_not_reset;
827 if (VersionHasStreamType(connection_->transport_version())) {
828 stream_not_reset =
829 GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 1);
830 } else {
831 stream_not_reset =
832 GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest);
833 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500834 InSequence s;
bnc6ca84fb2019-03-14 13:51:12 -0700835 QuicStreamOffset offset = 0;
renjietangbb1c4892019-05-24 15:58:44 -0700836 if (VersionHasStreamType(connection_->transport_version())) {
837 EXPECT_CALL(*connection_,
838 SendStreamData(stream_not_reset, 1, offset, NO_FIN));
839 offset++;
840 }
renjietang2abedac2019-05-20 14:04:50 -0700841 if (VersionUsesQpack(connection_->transport_version())) {
842 EXPECT_CALL(*connection_,
843 SendStreamData(stream_not_reset, kHeadersFrameHeaderLength,
844 offset, NO_FIN));
845 offset += kHeadersFrameHeaderLength;
846 EXPECT_CALL(*connection_,
847 SendStreamData(stream_not_reset, kHeadersFramePayloadLength,
848 offset, NO_FIN));
849 offset += kHeadersFramePayloadLength;
850 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500851 if (VersionHasDataFrameHeader(connection_->transport_version())) {
852 EXPECT_CALL(*connection_,
bnc6ca84fb2019-03-14 13:51:12 -0700853 SendStreamData(stream_not_reset, data_frame_header_length,
854 offset, NO_FIN));
855 offset += data_frame_header_length;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500856 }
bnc6ca84fb2019-03-14 13:51:12 -0700857 EXPECT_CALL(*connection_, SendStreamData(stream_not_reset, _, offset, NO_FIN))
858 .WillOnce(Return(
859 QuicConsumedData(kStreamFlowControlWindowSize - offset, false)));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500860 EXPECT_CALL(*session_, SendBlocked(stream_not_reset));
861
fkastenholz305e1732019-06-18 05:01:22 -0700862 if (VersionHasIetfQuicFrames(transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500863 // The PromisePushedResources call, above, will have used all available
864 // stream ids. For version 99, stream ids are not made available until
fkastenholz3c4eabf2019-04-22 07:49:59 -0700865 // a MAX_STREAMS frame is received. This emulates the reception of one.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500866 // For pre-v-99, the node monitors its own stream usage and makes streams
867 // available as it closes/etc them.
fkastenholz3c4eabf2019-04-22 07:49:59 -0700868 session_->OnMaxStreamsFrame(
renjietang3a1bb802019-06-11 10:42:41 -0700869 QuicMaxStreamsFrame(0, num_resources + 1, /*unidirectional=*/true));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500870 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500871 session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(1));
renjietang3a1bb802019-06-11 10:42:41 -0700872 session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(2));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500873}
874
875// Tests that closing a open outgoing stream can trigger a promised resource in
876// the queue to be send out.
877TEST_P(QuicSimpleServerSessionServerPushTest,
878 CloseStreamToHandleMorePromisedStream) {
renjietang2abedac2019-05-20 14:04:50 -0700879 MaybeConsumeHeadersStreamData();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500880 size_t num_resources = kMaxStreamsForTest + 1;
fkastenholz305e1732019-06-18 05:01:22 -0700881 if (VersionHasIetfQuicFrames(transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500882 // V99 will send out a stream-id-blocked frame when the we desired to exceed
883 // the limit. This will clear the frames so that they do not block the later
884 // rst-stream frame.
885 EXPECT_CALL(*connection_, SendControlFrame(_))
bnc5b3c3be2019-06-25 10:37:09 -0700886 .WillOnce(Invoke(&ClearControlFrame));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500887 }
bnc6ca84fb2019-03-14 13:51:12 -0700888 QuicByteCount data_frame_header_length = PromisePushResources(num_resources);
renjietang3a1bb802019-06-11 10:42:41 -0700889 QuicStreamId stream_to_open;
890 if (VersionHasStreamType(connection_->transport_version())) {
891 stream_to_open =
892 GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 1);
893 } else {
894 stream_to_open = GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest);
895 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500896
renjietang3a1bb802019-06-11 10:42:41 -0700897 // Resetting an open stream will close the stream and give space for extra
QUICHE teama6ef0a62019-03-07 20:34:33 -0500898 // stream to be opened.
renjietang3a1bb802019-06-11 10:42:41 -0700899 QuicStreamId stream_got_reset = GetNthServerInitiatedUnidirectionalId(1);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500900 EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
901 EXPECT_CALL(*connection_, SendControlFrame(_));
fkastenholz305e1732019-06-18 05:01:22 -0700902 if (!VersionHasIetfQuicFrames(transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500903 // For version 99, this is covered in InjectStopSending()
904 EXPECT_CALL(*connection_,
905 OnStreamReset(stream_got_reset, QUIC_RST_ACKNOWLEDGEMENT));
906 }
bnc6ca84fb2019-03-14 13:51:12 -0700907 QuicStreamOffset offset = 0;
renjietangbb1c4892019-05-24 15:58:44 -0700908 if (VersionHasStreamType(connection_->transport_version())) {
909 EXPECT_CALL(*connection_,
910 SendStreamData(stream_to_open, 1, offset, NO_FIN));
911 offset++;
912 }
renjietang2abedac2019-05-20 14:04:50 -0700913 if (VersionUsesQpack(connection_->transport_version())) {
914 EXPECT_CALL(*connection_,
915 SendStreamData(stream_to_open, kHeadersFrameHeaderLength,
916 offset, NO_FIN));
917 offset += kHeadersFrameHeaderLength;
918 EXPECT_CALL(*connection_,
919 SendStreamData(stream_to_open, kHeadersFramePayloadLength,
920 offset, NO_FIN));
921 offset += kHeadersFramePayloadLength;
922 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500923 if (VersionHasDataFrameHeader(connection_->transport_version())) {
924 EXPECT_CALL(*connection_,
bnc6ca84fb2019-03-14 13:51:12 -0700925 SendStreamData(stream_to_open, data_frame_header_length, offset,
926 NO_FIN));
927 offset += data_frame_header_length;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500928 }
bnc6ca84fb2019-03-14 13:51:12 -0700929 EXPECT_CALL(*connection_, SendStreamData(stream_to_open, _, offset, NO_FIN))
930 .WillOnce(Return(
931 QuicConsumedData(kStreamFlowControlWindowSize - offset, false)));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500932
933 EXPECT_CALL(*session_, SendBlocked(stream_to_open));
934 QuicRstStreamFrame rst(kInvalidControlFrameId, stream_got_reset,
935 QUIC_STREAM_CANCELLED, 0);
fkastenholz305e1732019-06-18 05:01:22 -0700936 if (VersionHasIetfQuicFrames(transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500937 // The PromisePushedResources call, above, will have used all available
938 // stream ids. For version 99, stream ids are not made available until
fkastenholz3c4eabf2019-04-22 07:49:59 -0700939 // a MAX_STREAMS frame is received. This emulates the reception of one.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500940 // For pre-v-99, the node monitors its own stream usage and makes streams
941 // available as it closes/etc them.
fkastenholz3c4eabf2019-04-22 07:49:59 -0700942 session_->OnMaxStreamsFrame(
renjietang3a1bb802019-06-11 10:42:41 -0700943 QuicMaxStreamsFrame(0, num_resources + 1, /*unidirectional=*/true));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500944 }
945 visitor_->OnRstStream(rst);
946 // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
947 // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
948 // a one-way close.
949 InjectStopSending(stream_got_reset, QUIC_STREAM_CANCELLED);
950}
951
952} // namespace
953} // namespace test
954} // namespace quic