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