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/third_party/quiche/src/quic/core/http/quic_spdy_client_session.h"
6
7 #include <memory>
8 #include <string>
9 #include <utility>
10 #include <vector>
11
12 #include "net/third_party/quiche/src/quic/core/crypto/null_decrypter.h"
13 #include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h"
14 #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h"
15 #include "net/third_party/quiche/src/quic/core/http/spdy_server_push_utils.h"
16 #include "net/third_party/quiche/src/quic/core/quic_utils.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_ptr_util.h"
19 #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
20 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
21 #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
22 #include "net/third_party/quiche/src/quic/test_tools/mock_quic_spdy_client_stream.h"
23 #include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h"
24 #include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
25 #include "net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h"
26 #include "net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.h"
27 #include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h"
28 #include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h"
29 #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
30 #include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h"
31 #include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
32 #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
33
34 using spdy::SpdyHeaderBlock;
35 using testing::_;
36 using testing::AnyNumber;
37 using testing::AtLeast;
38 using testing::AtMost;
39 using testing::Invoke;
40 using testing::Truly;
41
42 namespace quic {
43 namespace test {
44 namespace {
45
46 const char kServerHostname[] = "test.example.com";
47 const uint16_t kPort = 443;
48
49 class TestQuicSpdyClientSession : public QuicSpdyClientSession {
50 public:
TestQuicSpdyClientSession(const QuicConfig & config,const ParsedQuicVersionVector & supported_versions,QuicConnection * connection,const QuicServerId & server_id,QuicCryptoClientConfig * crypto_config,QuicClientPushPromiseIndex * push_promise_index)51 explicit TestQuicSpdyClientSession(
52 const QuicConfig& config,
53 const ParsedQuicVersionVector& supported_versions,
54 QuicConnection* connection,
55 const QuicServerId& server_id,
56 QuicCryptoClientConfig* crypto_config,
57 QuicClientPushPromiseIndex* push_promise_index)
58 : QuicSpdyClientSession(config,
59 supported_versions,
60 connection,
61 server_id,
62 crypto_config,
63 push_promise_index) {}
64
CreateClientStream()65 std::unique_ptr<QuicSpdyClientStream> CreateClientStream() override {
66 return std::make_unique<MockQuicSpdyClientStream>(
67 GetNextOutgoingBidirectionalStreamId(), this, BIDIRECTIONAL);
68 }
69
CreateIncomingStream(QuicStreamId id)70 MockQuicSpdyClientStream* CreateIncomingStream(QuicStreamId id) override {
71 if (!ShouldCreateIncomingStream(id)) {
72 return nullptr;
73 }
74 MockQuicSpdyClientStream* stream =
75 new MockQuicSpdyClientStream(id, this, READ_UNIDIRECTIONAL);
76 ActivateStream(QuicWrapUnique(stream));
77 return stream;
78 }
79 };
80
81 class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> {
82 protected:
QuicSpdyClientSessionTest()83 QuicSpdyClientSessionTest()
84 : crypto_config_(crypto_test_utils::ProofVerifierForTesting()),
85 promised_stream_id_(
86 QuicUtils::GetInvalidStreamId(GetParam().transport_version)),
87 associated_stream_id_(
88 QuicUtils::GetInvalidStreamId(GetParam().transport_version)) {
89 Initialize();
90 // Advance the time, because timers do not like uninitialized times.
91 connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
92 }
93
~QuicSpdyClientSessionTest()94 ~QuicSpdyClientSessionTest() override {
95 // Session must be destroyed before promised_by_url_
96 session_.reset(nullptr);
97 }
98
Initialize()99 void Initialize() {
100 session_.reset();
101 connection_ = new PacketSavingConnection(&helper_, &alarm_factory_,
102 Perspective::IS_CLIENT,
103 SupportedVersions(GetParam()));
104 session_ = std::make_unique<TestQuicSpdyClientSession>(
105 DefaultQuicConfig(), SupportedVersions(GetParam()), connection_,
106 QuicServerId(kServerHostname, kPort, false), &crypto_config_,
107 &push_promise_index_);
108 session_->Initialize();
109 push_promise_[":path"] = "/bar";
110 push_promise_[":authority"] = "www.google.com";
111 push_promise_[":method"] = "GET";
112 push_promise_[":scheme"] = "https";
113 promise_url_ =
114 SpdyServerPushUtils::GetPromisedUrlFromHeaders(push_promise_);
115 promised_stream_id_ = GetNthServerInitiatedUnidirectionalStreamId(
116 connection_->transport_version(), 0);
117 associated_stream_id_ = GetNthClientInitiatedBidirectionalStreamId(
118 connection_->transport_version(), 0);
119 }
120
121 // The function ensures that A) the MAX_STREAMS frames get properly deleted
122 // (since the test uses a 'did we leak memory' check ... if we just lose the
123 // frame, the test fails) and B) returns true (instead of the default, false)
124 // which ensures that the rest of the system thinks that the frame actually
125 // was transmitted.
ClearMaxStreamsControlFrame(const QuicFrame & frame)126 bool ClearMaxStreamsControlFrame(const QuicFrame& frame) {
127 if (frame.type == MAX_STREAMS_FRAME) {
128 DeleteFrame(&const_cast<QuicFrame&>(frame));
129 return true;
130 }
131 return false;
132 }
133
134 public:
ClearStreamsBlockedControlFrame(const QuicFrame & frame)135 bool ClearStreamsBlockedControlFrame(const QuicFrame& frame) {
136 if (frame.type == STREAMS_BLOCKED_FRAME) {
137 DeleteFrame(&const_cast<QuicFrame&>(frame));
138 return true;
139 }
140 return false;
141 }
142
143 protected:
CompleteCryptoHandshake()144 void CompleteCryptoHandshake() {
145 CompleteCryptoHandshake(kDefaultMaxStreamsPerConnection);
146 }
147
CompleteCryptoHandshake(uint32_t server_max_incoming_streams)148 void CompleteCryptoHandshake(uint32_t server_max_incoming_streams) {
149 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
150 EXPECT_CALL(*connection_, SendControlFrame(_))
151 .Times(testing::AnyNumber())
152 .WillRepeatedly(Invoke(
153 this, &QuicSpdyClientSessionTest::ClearMaxStreamsControlFrame));
154 }
155 session_->CryptoConnect();
156 QuicCryptoClientStream* stream = static_cast<QuicCryptoClientStream*>(
157 session_->GetMutableCryptoStream());
158 QuicConfig config = DefaultQuicConfig();
159 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
160 config.SetMaxUnidirectionalStreamsToSend(
161 server_max_incoming_streams +
162 session_->num_expected_unidirectional_static_streams());
163 config.SetMaxBidirectionalStreamsToSend(server_max_incoming_streams);
164 } else {
165 config.SetMaxBidirectionalStreamsToSend(server_max_incoming_streams);
166 }
167 std::unique_ptr<QuicCryptoServerConfig> crypto_config =
168 crypto_test_utils::CryptoServerConfigForTesting();
169 crypto_test_utils::HandshakeWithFakeServer(
170 &config, crypto_config.get(), &helper_, &alarm_factory_, connection_,
171 stream, AlpnForVersion(connection_->version()));
172 }
173
174 QuicCryptoClientConfig crypto_config_;
175 MockQuicConnectionHelper helper_;
176 MockAlarmFactory alarm_factory_;
177 PacketSavingConnection* connection_;
178 std::unique_ptr<TestQuicSpdyClientSession> session_;
179 QuicClientPushPromiseIndex push_promise_index_;
180 SpdyHeaderBlock push_promise_;
181 std::string promise_url_;
182 QuicStreamId promised_stream_id_;
183 QuicStreamId associated_stream_id_;
184 };
185
186 INSTANTIATE_TEST_SUITE_P(Tests,
187 QuicSpdyClientSessionTest,
188 ::testing::ValuesIn(AllSupportedVersions()),
189 ::testing::PrintToStringParamName());
190
TEST_P(QuicSpdyClientSessionTest,CryptoConnect)191 TEST_P(QuicSpdyClientSessionTest, CryptoConnect) {
192 CompleteCryptoHandshake();
193 }
194
TEST_P(QuicSpdyClientSessionTest,NoEncryptionAfterInitialEncryption)195 TEST_P(QuicSpdyClientSessionTest, NoEncryptionAfterInitialEncryption) {
196 if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
197 // This test relies on resumption and is QUIC crypto specific, so it is
198 // disabled for TLS.
199 // TODO(nharper): Add support for resumption to the TLS handshake, and fix
200 // this test to not rely on QUIC crypto.
201 return;
202 }
203 // Complete a handshake in order to prime the crypto config for 0-RTT.
204 CompleteCryptoHandshake();
205
206 // Now create a second session using the same crypto config.
207 Initialize();
208
209 EXPECT_CALL(*connection_, OnCanWrite());
210 // Starting the handshake should move immediately to encryption
211 // established and will allow streams to be created.
212 session_->CryptoConnect();
213 EXPECT_TRUE(session_->IsEncryptionEstablished());
214 QuicSpdyClientStream* stream = session_->CreateOutgoingBidirectionalStream();
215 ASSERT_TRUE(stream != nullptr);
216 EXPECT_FALSE(QuicUtils::IsCryptoStreamId(connection_->transport_version(),
217 stream->id()));
218
219 // Process an "inchoate" REJ from the server which will cause
220 // an inchoate CHLO to be sent and will leave the encryption level
221 // at NONE.
222 CryptoHandshakeMessage rej;
223 crypto_test_utils::FillInDummyReject(&rej);
224 EXPECT_TRUE(session_->IsEncryptionEstablished());
225 crypto_test_utils::SendHandshakeMessageToStream(
226 session_->GetMutableCryptoStream(), rej, Perspective::IS_CLIENT);
227 EXPECT_FALSE(session_->IsEncryptionEstablished());
228 EXPECT_EQ(ENCRYPTION_INITIAL,
229 QuicPacketCreatorPeer::GetEncryptionLevel(
230 QuicConnectionPeer::GetPacketCreator(connection_)));
231 // Verify that no new streams may be created.
232 EXPECT_TRUE(session_->CreateOutgoingBidirectionalStream() == nullptr);
233 // Verify that no data may be send on existing streams.
234 char data[] = "hello world";
235 EXPECT_QUIC_BUG(
236 session_->WritevData(stream->id(), QUICHE_ARRAYSIZE(data), 0, NO_FIN,
237 NOT_RETRANSMISSION, QuicheNullOpt),
238 "Client: Try to send data of stream");
239 }
240
TEST_P(QuicSpdyClientSessionTest,MaxNumStreamsWithNoFinOrRst)241 TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithNoFinOrRst) {
242 if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
243 // This test relies on the MIDS transport parameter, which is not yet
244 // supported in TLS 1.3.
245 // TODO(nharper): Add support for Transport Parameters in the TLS handshake.
246 return;
247 }
248
249 uint32_t kServerMaxIncomingStreams = 1;
250 CompleteCryptoHandshake(kServerMaxIncomingStreams);
251
252 QuicSpdyClientStream* stream = session_->CreateOutgoingBidirectionalStream();
253 ASSERT_TRUE(stream);
254 EXPECT_FALSE(session_->CreateOutgoingBidirectionalStream());
255
256 // Close the stream, but without having received a FIN or a RST_STREAM
257 // or MAX_STREAMS (V99) and check that a new one can not be created.
258 session_->CloseStream(stream->id());
259 EXPECT_EQ(1u, session_->GetNumOpenOutgoingStreams());
260
261 stream = session_->CreateOutgoingBidirectionalStream();
262 EXPECT_FALSE(stream);
263
264 if (VersionHasIetfQuicFrames(GetParam().transport_version)) {
265 EXPECT_EQ(1u,
266 QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_)
267 ->outgoing_stream_count());
268 }
269 }
270
TEST_P(QuicSpdyClientSessionTest,MaxNumStreamsWithRst)271 TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithRst) {
272 if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
273 // This test relies on the MIDS transport parameter, which is not yet
274 // supported in TLS 1.3.
275 // TODO(nharper): Add support for Transport Parameters in the TLS handshake.
276 return;
277 }
278
279 uint32_t kServerMaxIncomingStreams = 1;
280 CompleteCryptoHandshake(kServerMaxIncomingStreams);
281
282 QuicSpdyClientStream* stream = session_->CreateOutgoingBidirectionalStream();
283 ASSERT_NE(nullptr, stream);
284 EXPECT_EQ(nullptr, session_->CreateOutgoingBidirectionalStream());
285
286 // Close the stream and receive an RST frame to remove the unfinished stream
287 session_->CloseStream(stream->id());
288 session_->OnRstStream(QuicRstStreamFrame(kInvalidControlFrameId, stream->id(),
289 QUIC_RST_ACKNOWLEDGEMENT, 0));
290 // Check that a new one can be created.
291 EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams());
292 if (VersionHasIetfQuicFrames(GetParam().transport_version)) {
293 // In V99 the stream limit increases only if we get a MAX_STREAMS
294 // frame; pretend we got one.
295
296 QuicMaxStreamsFrame frame(0, 2,
297 /*unidirectional=*/false);
298 session_->OnMaxStreamsFrame(frame);
299 }
300 stream = session_->CreateOutgoingBidirectionalStream();
301 EXPECT_NE(nullptr, stream);
302 if (VersionHasIetfQuicFrames(GetParam().transport_version)) {
303 // Ensure that we have 2 total streams, 1 open and 1 closed.
304 QuicStreamCount expected_stream_count = 2;
305 EXPECT_EQ(expected_stream_count,
306 QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_)
307 ->outgoing_stream_count());
308 }
309 }
310
TEST_P(QuicSpdyClientSessionTest,ResetAndTrailers)311 TEST_P(QuicSpdyClientSessionTest, ResetAndTrailers) {
312 if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
313 // This test relies on the MIDS transport parameter, which is not yet
314 // supported in TLS 1.3.
315 // TODO(nharper): Add support for Transport Parameters in the TLS handshake.
316 return;
317 }
318 // Tests the situation in which the client sends a RST at the same time that
319 // the server sends trailing headers (trailers). Receipt of the trailers by
320 // the client should result in all outstanding stream state being tidied up
321 // (including flow control, and number of available outgoing streams).
322 uint32_t kServerMaxIncomingStreams = 1;
323 CompleteCryptoHandshake(kServerMaxIncomingStreams);
324
325 QuicSpdyClientStream* stream = session_->CreateOutgoingBidirectionalStream();
326 ASSERT_NE(nullptr, stream);
327
328 if (VersionHasIetfQuicFrames(GetParam().transport_version)) {
329 // For v99, trying to open a stream and failing due to lack
330 // of stream ids will result in a STREAMS_BLOCKED. Make
331 // sure we get one. Also clear out the frame because if it's
332 // left sitting, the later SendRstStream will not actually
333 // transmit the RST_STREAM because the connection will be in write-blocked
334 // state. This means that the SendControlFrame that is expected w.r.t. the
335 // RST_STREAM, below, will not be satisfied.
336 EXPECT_CALL(*connection_, SendControlFrame(_))
337 .WillOnce(Invoke(
338 this, &QuicSpdyClientSessionTest::ClearStreamsBlockedControlFrame));
339 }
340
341 EXPECT_EQ(nullptr, session_->CreateOutgoingBidirectionalStream());
342
343 QuicStreamId stream_id = stream->id();
344
345 EXPECT_CALL(*connection_, SendControlFrame(_))
346 .Times(AtLeast(1))
347 .WillRepeatedly(Invoke(&ClearControlFrame));
348 EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(1);
349 session_->SendRstStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0);
350
351 // A new stream cannot be created as the reset stream still counts as an open
352 // outgoing stream until closed by the server.
353 EXPECT_EQ(1u, session_->GetNumOpenOutgoingStreams());
354 stream = session_->CreateOutgoingBidirectionalStream();
355 EXPECT_EQ(nullptr, stream);
356
357 // The stream receives trailers with final byte offset: this is one of three
358 // ways that a peer can signal the end of a stream (the others being RST,
359 // stream data + FIN).
360 QuicHeaderList trailers;
361 trailers.OnHeaderBlockStart();
362 trailers.OnHeader(kFinalOffsetHeaderKey, "0");
363 trailers.OnHeaderBlockEnd(0, 0);
364 session_->OnStreamHeaderList(stream_id, /*fin=*/false, 0, trailers);
365
366 // The stream is now complete from the client's perspective, and it should
367 // be able to create a new outgoing stream.
368 EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams());
369 if (VersionHasIetfQuicFrames(GetParam().transport_version)) {
370 QuicMaxStreamsFrame frame(0, 2,
371 /*unidirectional=*/false);
372
373 session_->OnMaxStreamsFrame(frame);
374 }
375 stream = session_->CreateOutgoingBidirectionalStream();
376 EXPECT_NE(nullptr, stream);
377 if (VersionHasIetfQuicFrames(GetParam().transport_version)) {
378 // Ensure that we have 2 open streams.
379 QuicStreamCount expected_stream_count = 2;
380 EXPECT_EQ(expected_stream_count,
381 QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_)
382 ->outgoing_stream_count());
383 }
384 }
385
TEST_P(QuicSpdyClientSessionTest,ReceivedMalformedTrailersAfterSendingRst)386 TEST_P(QuicSpdyClientSessionTest, ReceivedMalformedTrailersAfterSendingRst) {
387 // Tests the situation where the client has sent a RST to the server, and has
388 // received trailing headers with a malformed final byte offset value.
389 CompleteCryptoHandshake();
390
391 QuicSpdyClientStream* stream = session_->CreateOutgoingBidirectionalStream();
392 ASSERT_NE(nullptr, stream);
393
394 // Send the RST, which results in the stream being closed locally (but some
395 // state remains while the client waits for a response from the server).
396 QuicStreamId stream_id = stream->id();
397 EXPECT_CALL(*connection_, SendControlFrame(_))
398 .Times(AtLeast(1))
399 .WillRepeatedly(Invoke(&ClearControlFrame));
400 EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(1);
401 session_->SendRstStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0);
402
403 // The stream receives trailers with final byte offset, but the header value
404 // is non-numeric and should be treated as malformed.
405 QuicHeaderList trailers;
406 trailers.OnHeaderBlockStart();
407 trailers.OnHeader(kFinalOffsetHeaderKey, "invalid non-numeric value");
408 trailers.OnHeaderBlockEnd(0, 0);
409
410 EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(1);
411 session_->OnStreamHeaderList(stream_id, /*fin=*/false, 0, trailers);
412 }
413
TEST_P(QuicSpdyClientSessionTest,OnStreamHeaderListWithStaticStream)414 TEST_P(QuicSpdyClientSessionTest, OnStreamHeaderListWithStaticStream) {
415 // Test situation where OnStreamHeaderList is called by stream with static id.
416 CompleteCryptoHandshake();
417
418 QuicHeaderList trailers;
419 trailers.OnHeaderBlockStart();
420 trailers.OnHeader(kFinalOffsetHeaderKey, "0");
421 trailers.OnHeaderBlockEnd(0, 0);
422
423 // Initialize H/3 control stream.
424 QuicStreamId id;
425 if (VersionUsesHttp3(connection_->transport_version())) {
426 id = GetNthServerInitiatedUnidirectionalStreamId(
427 connection_->transport_version(), 3);
428 char type[] = {0x00};
429
430 QuicStreamFrame data1(id, false, 0, quiche::QuicheStringPiece(type, 1));
431 session_->OnStreamFrame(data1);
432 } else {
433 id = QuicUtils::GetHeadersStreamId(connection_->transport_version());
434 }
435
436 EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
437 "stream is static", _))
438 .Times(1);
439 session_->OnStreamHeaderList(id,
440 /*fin=*/false, 0, trailers);
441 }
442
TEST_P(QuicSpdyClientSessionTest,OnPromiseHeaderListWithStaticStream)443 TEST_P(QuicSpdyClientSessionTest, OnPromiseHeaderListWithStaticStream) {
444 // Test situation where OnPromiseHeaderList is called by stream with static
445 // id.
446 CompleteCryptoHandshake();
447
448 QuicHeaderList trailers;
449 trailers.OnHeaderBlockStart();
450 trailers.OnHeader(kFinalOffsetHeaderKey, "0");
451 trailers.OnHeaderBlockEnd(0, 0);
452
453 // Initialize H/3 control stream.
454 QuicStreamId id;
455 if (VersionUsesHttp3(connection_->transport_version())) {
456 id = GetNthServerInitiatedUnidirectionalStreamId(
457 connection_->transport_version(), 3);
458 char type[] = {0x00};
459
460 QuicStreamFrame data1(id, false, 0, quiche::QuicheStringPiece(type, 1));
461 session_->OnStreamFrame(data1);
462 } else {
463 id = QuicUtils::GetHeadersStreamId(connection_->transport_version());
464 }
465 EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
466 "stream is static", _))
467 .Times(1);
468 session_->OnPromiseHeaderList(id, promised_stream_id_, 0, trailers);
469 }
470
TEST_P(QuicSpdyClientSessionTest,GoAwayReceived)471 TEST_P(QuicSpdyClientSessionTest, GoAwayReceived) {
472 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
473 return;
474 }
475 CompleteCryptoHandshake();
476
477 // After receiving a GoAway, I should no longer be able to create outgoing
478 // streams.
479 session_->connection()->OnGoAwayFrame(QuicGoAwayFrame(
480 kInvalidControlFrameId, QUIC_PEER_GOING_AWAY, 1u, "Going away."));
481 EXPECT_EQ(nullptr, session_->CreateOutgoingBidirectionalStream());
482 }
483
CheckForDecryptionError(QuicFramer * framer)484 static bool CheckForDecryptionError(QuicFramer* framer) {
485 return framer->error() == QUIC_DECRYPTION_FAILURE;
486 }
487
488 // Various sorts of invalid packets that should not cause a connection
489 // to be closed.
TEST_P(QuicSpdyClientSessionTest,InvalidPacketReceived)490 TEST_P(QuicSpdyClientSessionTest, InvalidPacketReceived) {
491 QuicSocketAddress server_address(TestPeerIPAddress(), kTestPort);
492 QuicSocketAddress client_address(TestPeerIPAddress(), kTestPort);
493
494 EXPECT_CALL(*connection_, ProcessUdpPacket(server_address, client_address, _))
495 .WillRepeatedly(Invoke(static_cast<MockQuicConnection*>(connection_),
496 &MockQuicConnection::ReallyProcessUdpPacket));
497 EXPECT_CALL(*connection_, OnCanWrite()).Times(AnyNumber());
498 EXPECT_CALL(*connection_, OnError(_)).Times(1);
499
500 // Verify that empty packets don't close the connection.
501 QuicReceivedPacket zero_length_packet(nullptr, 0, QuicTime::Zero(), false);
502 EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
503 session_->ProcessUdpPacket(client_address, server_address,
504 zero_length_packet);
505
506 // Verifiy that small, invalid packets don't close the connection.
507 char buf[2] = {0x00, 0x01};
508 QuicConnectionId connection_id = session_->connection()->connection_id();
509 QuicReceivedPacket valid_packet(buf, 2, QuicTime::Zero(), false);
510 // Close connection shouldn't be called.
511 EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
512 EXPECT_CALL(*connection_, OnError(_)).Times(AtMost(1));
513 session_->ProcessUdpPacket(client_address, server_address, valid_packet);
514
515 // Verify that a non-decryptable packet doesn't close the connection.
516 QuicFramerPeer::SetLastSerializedServerConnectionId(
517 QuicConnectionPeer::GetFramer(connection_), connection_id);
518 ParsedQuicVersionVector versions = SupportedVersions(GetParam());
519 QuicConnectionId destination_connection_id = EmptyQuicConnectionId();
520 QuicConnectionId source_connection_id = connection_id;
521 std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
522 destination_connection_id, source_connection_id, false, false, 100,
523 "data", true, CONNECTION_ID_ABSENT, CONNECTION_ID_ABSENT,
524 PACKET_4BYTE_PACKET_NUMBER, &versions, Perspective::IS_SERVER));
525 std::unique_ptr<QuicReceivedPacket> received(
526 ConstructReceivedPacket(*packet, QuicTime::Zero()));
527 // Change the last byte of the encrypted data.
528 *(const_cast<char*>(received->data() + received->length() - 1)) += 1;
529 EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
530 EXPECT_CALL(*connection_, OnError(Truly(CheckForDecryptionError))).Times(1);
531 session_->ProcessUdpPacket(client_address, server_address, *received);
532 }
533
534 // A packet with invalid framing should cause a connection to be closed.
TEST_P(QuicSpdyClientSessionTest,InvalidFramedPacketReceived)535 TEST_P(QuicSpdyClientSessionTest, InvalidFramedPacketReceived) {
536 const ParsedQuicVersion version = GetParam();
537 if (version.handshake_protocol == PROTOCOL_TLS1_3) {
538 // TODO(nharper, b/112643533): Figure out why this test fails when TLS is
539 // enabled and fix it.
540 return;
541 }
542 QuicSocketAddress server_address(TestPeerIPAddress(), kTestPort);
543 QuicSocketAddress client_address(TestPeerIPAddress(), kTestPort);
544 if (version.KnowsWhichDecrypterToUse()) {
545 connection_->InstallDecrypter(
546 ENCRYPTION_FORWARD_SECURE,
547 std::make_unique<NullDecrypter>(Perspective::IS_CLIENT));
548 } else {
549 connection_->SetDecrypter(
550 ENCRYPTION_FORWARD_SECURE,
551 std::make_unique<NullDecrypter>(Perspective::IS_CLIENT));
552 }
553
554 EXPECT_CALL(*connection_, ProcessUdpPacket(server_address, client_address, _))
555 .WillRepeatedly(Invoke(static_cast<MockQuicConnection*>(connection_),
556 &MockQuicConnection::ReallyProcessUdpPacket));
557 EXPECT_CALL(*connection_, OnError(_)).Times(1);
558
559 // Verify that a decryptable packet with bad frames does close the connection.
560 QuicConnectionId destination_connection_id =
561 session_->connection()->connection_id();
562 QuicConnectionId source_connection_id = EmptyQuicConnectionId();
563 QuicFramerPeer::SetLastSerializedServerConnectionId(
564 QuicConnectionPeer::GetFramer(connection_), destination_connection_id);
565 bool version_flag = false;
566 QuicConnectionIdIncluded scid_included = CONNECTION_ID_ABSENT;
567 if (VersionHasIetfInvariantHeader(version.transport_version)) {
568 version_flag = true;
569 source_connection_id = destination_connection_id;
570 scid_included = CONNECTION_ID_PRESENT;
571 }
572 std::unique_ptr<QuicEncryptedPacket> packet(ConstructMisFramedEncryptedPacket(
573 destination_connection_id, source_connection_id, version_flag, false, 100,
574 "data", CONNECTION_ID_ABSENT, scid_included, PACKET_4BYTE_PACKET_NUMBER,
575 version, Perspective::IS_SERVER));
576 std::unique_ptr<QuicReceivedPacket> received(
577 ConstructReceivedPacket(*packet, QuicTime::Zero()));
578 EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(1);
579 session_->ProcessUdpPacket(client_address, server_address, *received);
580 }
581
TEST_P(QuicSpdyClientSessionTest,PushPromiseOnPromiseHeaders)582 TEST_P(QuicSpdyClientSessionTest, PushPromiseOnPromiseHeaders) {
583 // Initialize crypto before the client session will create a stream.
584 CompleteCryptoHandshake();
585
586 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
587 session_->SetMaxPushId(GetNthServerInitiatedUnidirectionalStreamId(
588 connection_->transport_version(), 10));
589 }
590
591 MockQuicSpdyClientStream* stream = static_cast<MockQuicSpdyClientStream*>(
592 session_->CreateOutgoingBidirectionalStream());
593
594 EXPECT_CALL(*stream, OnPromiseHeaderList(_, _, _));
595 session_->OnPromiseHeaderList(associated_stream_id_, promised_stream_id_, 0,
596 QuicHeaderList());
597 }
598
TEST_P(QuicSpdyClientSessionTest,PushPromiseStreamIdTooHigh)599 TEST_P(QuicSpdyClientSessionTest, PushPromiseStreamIdTooHigh) {
600 // Initialize crypto before the client session will create a stream.
601 CompleteCryptoHandshake();
602 QuicStreamId stream_id =
603 QuicSessionPeer::GetNextOutgoingBidirectionalStreamId(session_.get());
604 QuicSessionPeer::ActivateStream(
605 session_.get(), std::make_unique<QuicSpdyClientStream>(
606 stream_id, session_.get(), BIDIRECTIONAL));
607
608 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
609 session_->SetMaxPushId(GetNthServerInitiatedUnidirectionalStreamId(
610 connection_->transport_version(), 10));
611 // TODO(b/136295430) Use PushId to represent Push IDs instead of
612 // QuicStreamId.
613 EXPECT_CALL(
614 *connection_,
615 CloseConnection(QUIC_INVALID_STREAM_ID,
616 "Received push stream id higher than MAX_PUSH_ID.", _));
617 }
618 auto promise_id = GetNthServerInitiatedUnidirectionalStreamId(
619 connection_->transport_version(), 11);
620 auto headers = QuicHeaderList();
621 headers.OnHeaderBlockStart();
622 headers.OnHeader(":path", "/bar");
623 headers.OnHeader(":authority", "www.google.com");
624 headers.OnHeader(":method", "GET");
625 headers.OnHeader(":scheme", "https");
626 headers.OnHeaderBlockEnd(0, 0);
627 session_->OnPromiseHeaderList(stream_id, promise_id, 0, headers);
628 }
629
TEST_P(QuicSpdyClientSessionTest,PushPromiseOnPromiseHeadersAlreadyClosed)630 TEST_P(QuicSpdyClientSessionTest, PushPromiseOnPromiseHeadersAlreadyClosed) {
631 // Initialize crypto before the client session will create a stream.
632 CompleteCryptoHandshake();
633
634 session_->CreateOutgoingBidirectionalStream();
635
636 EXPECT_CALL(*connection_, SendControlFrame(_));
637 EXPECT_CALL(*connection_,
638 OnStreamReset(promised_stream_id_, QUIC_REFUSED_STREAM));
639 session_->ResetPromised(promised_stream_id_, QUIC_REFUSED_STREAM);
640
641 session_->OnPromiseHeaderList(associated_stream_id_, promised_stream_id_, 0,
642 QuicHeaderList());
643 }
644
TEST_P(QuicSpdyClientSessionTest,PushPromiseOutOfOrder)645 TEST_P(QuicSpdyClientSessionTest, PushPromiseOutOfOrder) {
646 // Initialize crypto before the client session will create a stream.
647 CompleteCryptoHandshake();
648
649 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
650 session_->SetMaxPushId(GetNthServerInitiatedUnidirectionalStreamId(
651 connection_->transport_version(), 10));
652 }
653
654 MockQuicSpdyClientStream* stream = static_cast<MockQuicSpdyClientStream*>(
655 session_->CreateOutgoingBidirectionalStream());
656
657 EXPECT_CALL(*stream, OnPromiseHeaderList(promised_stream_id_, _, _));
658 session_->OnPromiseHeaderList(associated_stream_id_, promised_stream_id_, 0,
659 QuicHeaderList());
660 associated_stream_id_ +=
661 QuicUtils::StreamIdDelta(connection_->transport_version());
662 EXPECT_CALL(*connection_,
663 CloseConnection(QUIC_INVALID_STREAM_ID,
664 "Received push stream id lesser or equal to the"
665 " last accepted before",
666 _));
667 session_->OnPromiseHeaderList(associated_stream_id_, promised_stream_id_, 0,
668 QuicHeaderList());
669 }
670
TEST_P(QuicSpdyClientSessionTest,PushPromiseOutgoingStreamId)671 TEST_P(QuicSpdyClientSessionTest, PushPromiseOutgoingStreamId) {
672 // Initialize crypto before the client session will create a stream.
673 CompleteCryptoHandshake();
674
675 MockQuicSpdyClientStream* stream = static_cast<MockQuicSpdyClientStream*>(
676 session_->CreateOutgoingBidirectionalStream());
677
678 // Promise an illegal (outgoing) stream id.
679 promised_stream_id_ = GetNthClientInitiatedBidirectionalStreamId(
680 connection_->transport_version(), 0);
681 EXPECT_CALL(
682 *connection_,
683 CloseConnection(QUIC_INVALID_STREAM_ID,
684 "Received push stream id for outgoing stream.", _));
685
686 session_->OnPromiseHeaderList(stream->id(), promised_stream_id_, 0,
687 QuicHeaderList());
688 }
689
TEST_P(QuicSpdyClientSessionTest,PushPromiseHandlePromise)690 TEST_P(QuicSpdyClientSessionTest, PushPromiseHandlePromise) {
691 // Initialize crypto before the client session will create a stream.
692 CompleteCryptoHandshake();
693
694 session_->CreateOutgoingBidirectionalStream();
695
696 EXPECT_TRUE(session_->HandlePromised(associated_stream_id_,
697 promised_stream_id_, push_promise_));
698
699 EXPECT_NE(session_->GetPromisedById(promised_stream_id_), nullptr);
700 EXPECT_NE(session_->GetPromisedByUrl(promise_url_), nullptr);
701 }
702
TEST_P(QuicSpdyClientSessionTest,PushPromiseAlreadyClosed)703 TEST_P(QuicSpdyClientSessionTest, PushPromiseAlreadyClosed) {
704 // Initialize crypto before the client session will create a stream.
705 CompleteCryptoHandshake();
706
707 session_->CreateOutgoingBidirectionalStream();
708 session_->GetOrCreateStream(promised_stream_id_);
709
710 EXPECT_CALL(*connection_, SendControlFrame(_));
711 EXPECT_CALL(*connection_,
712 OnStreamReset(promised_stream_id_, QUIC_REFUSED_STREAM));
713
714 session_->ResetPromised(promised_stream_id_, QUIC_REFUSED_STREAM);
715 SpdyHeaderBlock promise_headers;
716 EXPECT_FALSE(session_->HandlePromised(associated_stream_id_,
717 promised_stream_id_, promise_headers));
718
719 // Verify that the promise was not created.
720 EXPECT_EQ(session_->GetPromisedById(promised_stream_id_), nullptr);
721 EXPECT_EQ(session_->GetPromisedByUrl(promise_url_), nullptr);
722 }
723
TEST_P(QuicSpdyClientSessionTest,PushPromiseDuplicateUrl)724 TEST_P(QuicSpdyClientSessionTest, PushPromiseDuplicateUrl) {
725 // Initialize crypto before the client session will create a stream.
726 CompleteCryptoHandshake();
727
728 session_->CreateOutgoingBidirectionalStream();
729
730 EXPECT_TRUE(session_->HandlePromised(associated_stream_id_,
731 promised_stream_id_, push_promise_));
732
733 EXPECT_NE(session_->GetPromisedById(promised_stream_id_), nullptr);
734 EXPECT_NE(session_->GetPromisedByUrl(promise_url_), nullptr);
735
736 promised_stream_id_ +=
737 QuicUtils::StreamIdDelta(connection_->transport_version());
738 EXPECT_CALL(*connection_, SendControlFrame(_));
739 EXPECT_CALL(*connection_,
740 OnStreamReset(promised_stream_id_, QUIC_DUPLICATE_PROMISE_URL));
741
742 EXPECT_FALSE(session_->HandlePromised(associated_stream_id_,
743 promised_stream_id_, push_promise_));
744
745 // Verify that the promise was not created.
746 EXPECT_EQ(session_->GetPromisedById(promised_stream_id_), nullptr);
747 }
748
TEST_P(QuicSpdyClientSessionTest,ReceivingPromiseEnhanceYourCalm)749 TEST_P(QuicSpdyClientSessionTest, ReceivingPromiseEnhanceYourCalm) {
750 for (size_t i = 0u; i < session_->get_max_promises(); i++) {
751 push_promise_[":path"] = quiche::QuicheStringPrintf("/bar%zu", i);
752
753 QuicStreamId id =
754 promised_stream_id_ +
755 i * QuicUtils::StreamIdDelta(connection_->transport_version());
756
757 EXPECT_TRUE(
758 session_->HandlePromised(associated_stream_id_, id, push_promise_));
759
760 // Verify that the promise is in the unclaimed streams map.
761 std::string promise_url(
762 SpdyServerPushUtils::GetPromisedUrlFromHeaders(push_promise_));
763 EXPECT_NE(session_->GetPromisedByUrl(promise_url), nullptr);
764 EXPECT_NE(session_->GetPromisedById(id), nullptr);
765 }
766
767 // One more promise, this should be refused.
768 int i = session_->get_max_promises();
769 push_promise_[":path"] = quiche::QuicheStringPrintf("/bar%d", i);
770
771 QuicStreamId id =
772 promised_stream_id_ +
773 i * QuicUtils::StreamIdDelta(connection_->transport_version());
774 EXPECT_CALL(*connection_, SendControlFrame(_));
775 EXPECT_CALL(*connection_, OnStreamReset(id, QUIC_REFUSED_STREAM));
776 EXPECT_FALSE(
777 session_->HandlePromised(associated_stream_id_, id, push_promise_));
778
779 // Verify that the promise was not created.
780 std::string promise_url(
781 SpdyServerPushUtils::GetPromisedUrlFromHeaders(push_promise_));
782 EXPECT_EQ(session_->GetPromisedById(id), nullptr);
783 EXPECT_EQ(session_->GetPromisedByUrl(promise_url), nullptr);
784 }
785
TEST_P(QuicSpdyClientSessionTest,IsClosedTrueAfterResetPromisedAlreadyOpen)786 TEST_P(QuicSpdyClientSessionTest, IsClosedTrueAfterResetPromisedAlreadyOpen) {
787 // Initialize crypto before the client session will create a stream.
788 CompleteCryptoHandshake();
789
790 session_->GetOrCreateStream(promised_stream_id_);
791 EXPECT_CALL(*connection_, SendControlFrame(_));
792 EXPECT_CALL(*connection_,
793 OnStreamReset(promised_stream_id_, QUIC_REFUSED_STREAM));
794 session_->ResetPromised(promised_stream_id_, QUIC_REFUSED_STREAM);
795 EXPECT_TRUE(session_->IsClosedStream(promised_stream_id_));
796 }
797
TEST_P(QuicSpdyClientSessionTest,IsClosedTrueAfterResetPromisedNonexistant)798 TEST_P(QuicSpdyClientSessionTest, IsClosedTrueAfterResetPromisedNonexistant) {
799 // Initialize crypto before the client session will create a stream.
800 CompleteCryptoHandshake();
801
802 EXPECT_CALL(*connection_, SendControlFrame(_));
803 EXPECT_CALL(*connection_,
804 OnStreamReset(promised_stream_id_, QUIC_REFUSED_STREAM));
805 session_->ResetPromised(promised_stream_id_, QUIC_REFUSED_STREAM);
806 EXPECT_TRUE(session_->IsClosedStream(promised_stream_id_));
807 }
808
TEST_P(QuicSpdyClientSessionTest,OnInitialHeadersCompleteIsPush)809 TEST_P(QuicSpdyClientSessionTest, OnInitialHeadersCompleteIsPush) {
810 // Initialize crypto before the client session will create a stream.
811 CompleteCryptoHandshake();
812 session_->GetOrCreateStream(promised_stream_id_);
813 EXPECT_TRUE(session_->HandlePromised(associated_stream_id_,
814 promised_stream_id_, push_promise_));
815 EXPECT_NE(session_->GetPromisedById(promised_stream_id_), nullptr);
816 EXPECT_NE(session_->GetPromisedStream(promised_stream_id_), nullptr);
817 EXPECT_NE(session_->GetPromisedByUrl(promise_url_), nullptr);
818
819 session_->OnInitialHeadersComplete(promised_stream_id_, SpdyHeaderBlock());
820 }
821
TEST_P(QuicSpdyClientSessionTest,OnInitialHeadersCompleteIsNotPush)822 TEST_P(QuicSpdyClientSessionTest, OnInitialHeadersCompleteIsNotPush) {
823 // Initialize crypto before the client session will create a stream.
824 CompleteCryptoHandshake();
825 session_->CreateOutgoingBidirectionalStream();
826 session_->OnInitialHeadersComplete(promised_stream_id_, SpdyHeaderBlock());
827 }
828
TEST_P(QuicSpdyClientSessionTest,DeletePromised)829 TEST_P(QuicSpdyClientSessionTest, DeletePromised) {
830 // Initialize crypto before the client session will create a stream.
831 CompleteCryptoHandshake();
832 session_->GetOrCreateStream(promised_stream_id_);
833 EXPECT_TRUE(session_->HandlePromised(associated_stream_id_,
834 promised_stream_id_, push_promise_));
835 QuicClientPromisedInfo* promised =
836 session_->GetPromisedById(promised_stream_id_);
837 EXPECT_NE(promised, nullptr);
838 EXPECT_NE(session_->GetPromisedStream(promised_stream_id_), nullptr);
839 EXPECT_NE(session_->GetPromisedByUrl(promise_url_), nullptr);
840
841 session_->DeletePromised(promised);
842 EXPECT_EQ(session_->GetPromisedById(promised_stream_id_), nullptr);
843 EXPECT_EQ(session_->GetPromisedByUrl(promise_url_), nullptr);
844 }
845
TEST_P(QuicSpdyClientSessionTest,ResetPromised)846 TEST_P(QuicSpdyClientSessionTest, ResetPromised) {
847 // Initialize crypto before the client session will create a stream.
848 CompleteCryptoHandshake();
849 session_->GetOrCreateStream(promised_stream_id_);
850 EXPECT_TRUE(session_->HandlePromised(associated_stream_id_,
851 promised_stream_id_, push_promise_));
852 EXPECT_CALL(*connection_, SendControlFrame(_));
853 EXPECT_CALL(*connection_,
854 OnStreamReset(promised_stream_id_, QUIC_STREAM_PEER_GOING_AWAY));
855 session_->SendRstStream(promised_stream_id_, QUIC_STREAM_PEER_GOING_AWAY, 0);
856 QuicClientPromisedInfo* promised =
857 session_->GetPromisedById(promised_stream_id_);
858 EXPECT_NE(promised, nullptr);
859 EXPECT_NE(session_->GetPromisedByUrl(promise_url_), nullptr);
860 EXPECT_EQ(session_->GetPromisedStream(promised_stream_id_), nullptr);
861 }
862
TEST_P(QuicSpdyClientSessionTest,PushPromiseInvalidMethod)863 TEST_P(QuicSpdyClientSessionTest, PushPromiseInvalidMethod) {
864 // Initialize crypto before the client session will create a stream.
865 CompleteCryptoHandshake();
866
867 session_->CreateOutgoingBidirectionalStream();
868
869 EXPECT_CALL(*connection_, SendControlFrame(_));
870 EXPECT_CALL(*connection_,
871 OnStreamReset(promised_stream_id_, QUIC_INVALID_PROMISE_METHOD));
872
873 push_promise_[":method"] = "POST";
874 EXPECT_FALSE(session_->HandlePromised(associated_stream_id_,
875 promised_stream_id_, push_promise_));
876
877 EXPECT_EQ(session_->GetPromisedById(promised_stream_id_), nullptr);
878 EXPECT_EQ(session_->GetPromisedByUrl(promise_url_), nullptr);
879 }
880
TEST_P(QuicSpdyClientSessionTest,PushPromiseInvalidHost)881 TEST_P(QuicSpdyClientSessionTest, PushPromiseInvalidHost) {
882 // Initialize crypto before the client session will create a stream.
883 CompleteCryptoHandshake();
884
885 session_->CreateOutgoingBidirectionalStream();
886
887 EXPECT_CALL(*connection_, SendControlFrame(_));
888 EXPECT_CALL(*connection_,
889 OnStreamReset(promised_stream_id_, QUIC_INVALID_PROMISE_URL));
890
891 push_promise_[":authority"] = "";
892 EXPECT_FALSE(session_->HandlePromised(associated_stream_id_,
893 promised_stream_id_, push_promise_));
894
895 EXPECT_EQ(session_->GetPromisedById(promised_stream_id_), nullptr);
896 EXPECT_EQ(session_->GetPromisedByUrl(promise_url_), nullptr);
897 }
898
TEST_P(QuicSpdyClientSessionTest,TryToCreateServerInitiatedBidirectionalStream)899 TEST_P(QuicSpdyClientSessionTest,
900 TryToCreateServerInitiatedBidirectionalStream) {
901 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
902 EXPECT_CALL(
903 *connection_,
904 CloseConnection(QUIC_HTTP_SERVER_INITIATED_BIDIRECTIONAL_STREAM, _, _));
905 } else {
906 EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
907 }
908 session_->GetOrCreateStream(GetNthServerInitiatedBidirectionalStreamId(
909 connection_->transport_version(), 0));
910 }
911
TEST_P(QuicSpdyClientSessionTest,TooManyPushPromises)912 TEST_P(QuicSpdyClientSessionTest, TooManyPushPromises) {
913 // Initialize crypto before the client session will create a stream.
914 CompleteCryptoHandshake();
915 QuicStreamId stream_id =
916 QuicSessionPeer::GetNextOutgoingBidirectionalStreamId(session_.get());
917 QuicSessionPeer::ActivateStream(
918 session_.get(), std::make_unique<QuicSpdyClientStream>(
919 stream_id, session_.get(), BIDIRECTIONAL));
920
921 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
922 session_->SetMaxPushId(kMaxQuicStreamId);
923 }
924
925 EXPECT_CALL(*connection_, OnStreamReset(_, QUIC_REFUSED_STREAM));
926
927 for (size_t promise_count = 0; promise_count <= session_->get_max_promises();
928 promise_count++) {
929 auto promise_id = GetNthServerInitiatedUnidirectionalStreamId(
930 connection_->transport_version(), promise_count);
931 auto headers = QuicHeaderList();
932 headers.OnHeaderBlockStart();
933 headers.OnHeader(":path", quiche::QuicheStrCat("/", promise_count));
934 headers.OnHeader(":authority", "www.google.com");
935 headers.OnHeader(":method", "GET");
936 headers.OnHeader(":scheme", "https");
937 headers.OnHeaderBlockEnd(0, 0);
938 session_->OnPromiseHeaderList(stream_id, promise_id, 0, headers);
939 }
940 }
941
942 } // namespace
943 } // namespace test
944 } // namespace quic
945