1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/quic/quic_chromium_client_stream.h"
6
7 #include <string>
8
9 #include "base/functional/bind.h"
10 #include "base/functional/callback_helpers.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/memory/raw_ptr.h"
13 #include "base/run_loop.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "net/base/io_buffer.h"
16 #include "net/base/net_errors.h"
17 #include "net/base/test_completion_callback.h"
18 #include "net/quic/quic_chromium_client_session.h"
19 #include "net/quic/quic_context.h"
20 #include "net/test/gtest_util.h"
21 #include "net/test/test_with_task_environment.h"
22 #include "net/third_party/quiche/src/quiche/quic/core/http/quic_spdy_client_session_base.h"
23 #include "net/third_party/quiche/src/quiche/quic/core/http/quic_spdy_client_stream.h"
24 #include "net/third_party/quiche/src/quiche/quic/core/http/spdy_utils.h"
25 #include "net/third_party/quiche/src/quiche/quic/core/quic_utils.h"
26 #include "net/third_party/quiche/src/quiche/quic/test_tools/crypto_test_utils.h"
27 #include "net/third_party/quiche/src/quiche/quic/test_tools/quic_config_peer.h"
28 #include "net/third_party/quiche/src/quiche/quic/test_tools/quic_connection_peer.h"
29 #include "net/third_party/quiche/src/quiche/quic/test_tools/quic_spdy_session_peer.h"
30 #include "net/third_party/quiche/src/quiche/quic/test_tools/quic_test_utils.h"
31 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
32 #include "testing/gmock/include/gmock/gmock.h"
33
34 using testing::_;
35 using testing::Return;
36
37 namespace net::test {
38 namespace {
39
40 class MockQuicClientSessionBase : public quic::QuicSpdyClientSessionBase {
41 public:
42 explicit MockQuicClientSessionBase(quic::QuicConnection* connection);
43
44 MockQuicClientSessionBase(const MockQuicClientSessionBase&) = delete;
45 MockQuicClientSessionBase& operator=(const MockQuicClientSessionBase&) =
46 delete;
47
48 ~MockQuicClientSessionBase() override;
49
GetCryptoStream() const50 const quic::QuicCryptoStream* GetCryptoStream() const override {
51 return crypto_stream_.get();
52 }
53
GetMutableCryptoStream()54 quic::QuicCryptoStream* GetMutableCryptoStream() override {
55 return crypto_stream_.get();
56 }
57
58 // From quic::QuicSession.
59 MOCK_METHOD2(OnConnectionClosed,
60 void(const quic::QuicConnectionCloseFrame& frame,
61 quic::ConnectionCloseSource source));
62 MOCK_METHOD1(CreateIncomingStream,
63 quic::QuicSpdyStream*(quic::QuicStreamId id));
64 MOCK_METHOD1(CreateIncomingStream,
65 quic::QuicSpdyStream*(quic::PendingStream* pending));
66 MOCK_METHOD0(CreateOutgoingBidirectionalStream, QuicChromiumClientStream*());
67 MOCK_METHOD0(CreateOutgoingUnidirectionalStream, QuicChromiumClientStream*());
68 MOCK_METHOD6(WritevData,
69 quic::QuicConsumedData(quic::QuicStreamId id,
70 size_t write_length,
71 quic::QuicStreamOffset offset,
72 quic::StreamSendingState state,
73 quic::TransmissionType type,
74 quic::EncryptionLevel level));
75 MOCK_METHOD2(WriteControlFrame,
76 bool(const quic::QuicFrame&, quic::TransmissionType));
77 MOCK_METHOD4(SendRstStream,
78 void(quic::QuicStreamId stream_id,
79 quic::QuicRstStreamErrorCode error,
80 quic::QuicStreamOffset bytes_written,
81 bool send_rst_only));
82
83 MOCK_METHOD2(OnStreamHeaders,
84 void(quic::QuicStreamId stream_id,
85 std::string_view headers_data));
86 MOCK_METHOD2(OnStreamHeadersPriority,
87 void(quic::QuicStreamId stream_id,
88 const spdy::SpdyStreamPrecedence& precedence));
89 MOCK_METHOD3(OnStreamHeadersComplete,
90 void(quic::QuicStreamId stream_id, bool fin, size_t frame_len));
91 MOCK_CONST_METHOD0(OneRttKeysAvailable, bool());
92 // Methods taking non-copyable types like spdy::Http2HeaderBlock by value
93 // cannot be mocked directly.
WriteHeadersOnHeadersStream(quic::QuicStreamId id,spdy::Http2HeaderBlock headers,bool fin,const spdy::SpdyStreamPrecedence & precedence,quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface> ack_listener)94 size_t WriteHeadersOnHeadersStream(
95 quic::QuicStreamId id,
96 spdy::Http2HeaderBlock headers,
97 bool fin,
98 const spdy::SpdyStreamPrecedence& precedence,
99 quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface>
100 ack_listener) override {
101 return WriteHeadersOnHeadersStreamMock(id, headers, fin, precedence,
102 std::move(ack_listener));
103 }
104 MOCK_METHOD5(WriteHeadersOnHeadersStreamMock,
105 size_t(quic::QuicStreamId id,
106 const spdy::Http2HeaderBlock& headers,
107 bool fin,
108 const spdy::SpdyStreamPrecedence& precedence,
109 const quiche::QuicheReferenceCountedPointer<
110 quic::QuicAckListenerInterface>& ack_listener));
111 MOCK_METHOD1(OnHeadersHeadOfLineBlocking, void(quic::QuicTime::Delta delta));
112
113 using quic::QuicSession::ActivateStream;
114
115 // Returns a quic::QuicConsumedData that indicates all of |write_length| (and
116 // |fin| if set) has been consumed.
117 static quic::QuicConsumedData ConsumeAllData(
118 quic::QuicStreamId id,
119 size_t write_length,
120 quic::QuicStreamOffset offset,
121 bool fin,
122 quic::QuicAckListenerInterface* ack_listener);
123
OnProofValid(const quic::QuicCryptoClientConfig::CachedState & cached)124 void OnProofValid(
125 const quic::QuicCryptoClientConfig::CachedState& cached) override {}
OnProofVerifyDetailsAvailable(const quic::ProofVerifyDetails & verify_details)126 void OnProofVerifyDetailsAvailable(
127 const quic::ProofVerifyDetails& verify_details) override {}
128
129 protected:
130 MOCK_METHOD1(ShouldCreateIncomingStream, bool(quic::QuicStreamId id));
131 MOCK_METHOD0(ShouldCreateOutgoingBidirectionalStream, bool());
132 MOCK_METHOD0(ShouldCreateOutgoingUnidirectionalStream, bool());
133
134 private:
135 std::unique_ptr<quic::QuicCryptoStream> crypto_stream_;
136 };
137
MockQuicClientSessionBase(quic::QuicConnection * connection)138 MockQuicClientSessionBase::MockQuicClientSessionBase(
139 quic::QuicConnection* connection)
140 : quic::QuicSpdyClientSessionBase(connection,
141 /*visitor=*/nullptr,
142 quic::test::DefaultQuicConfig(),
143 connection->supported_versions()) {
144 crypto_stream_ = std::make_unique<quic::test::MockQuicCryptoStream>(this);
145 Initialize();
146 ON_CALL(*this, WritevData(_, _, _, _, _, _))
147 .WillByDefault(testing::Return(quic::QuicConsumedData(0, false)));
148 }
149
150 MockQuicClientSessionBase::~MockQuicClientSessionBase() = default;
151
152 class QuicChromiumClientStreamTest
153 : public ::testing::TestWithParam<quic::ParsedQuicVersion>,
154 public WithTaskEnvironment {
155 public:
QuicChromiumClientStreamTest()156 QuicChromiumClientStreamTest()
157 : version_(GetParam()),
158 crypto_config_(
159 quic::test::crypto_test_utils::ProofVerifierForTesting()),
160 session_(new quic::test::MockQuicConnection(
161 &helper_,
162 &alarm_factory_,
163 quic::Perspective::IS_CLIENT,
164 quic::test::SupportedVersions(version_))) {
165 quic::test::QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(
166 session_.config(), quic::kMinimumFlowControlSendWindow);
167 quic::test::QuicConfigPeer::
168 SetReceivedInitialMaxStreamDataBytesOutgoingBidirectional(
169 session_.config(), quic::kMinimumFlowControlSendWindow);
170 quic::test::QuicConfigPeer::SetReceivedMaxUnidirectionalStreams(
171 session_.config(), 10);
172 session_.OnConfigNegotiated();
173 stream_ = new QuicChromiumClientStream(
174 quic::test::GetNthClientInitiatedBidirectionalStreamId(
175 version_.transport_version, 0),
176 &session_, quic::BIDIRECTIONAL, NetLogWithSource(),
177 TRAFFIC_ANNOTATION_FOR_TESTS);
178 session_.ActivateStream(base::WrapUnique(stream_.get()));
179 handle_ = stream_->CreateHandle();
180 helper_.AdvanceTime(quic::QuicTime::Delta::FromSeconds(1));
181 session_.connection()->SetEncrypter(
182 quic::ENCRYPTION_FORWARD_SECURE,
183 std::make_unique<quic::test::TaggingEncrypter>(
184 quic::ENCRYPTION_FORWARD_SECURE));
185 }
186
InitializeHeaders()187 void InitializeHeaders() {
188 headers_[":host"] = "www.google.com";
189 headers_[":path"] = "/index.hml";
190 headers_[":scheme"] = "https";
191 headers_[":status"] = "200";
192 headers_["cookie"] =
193 "__utma=208381060.1228362404.1372200928.1372200928.1372200928.1; "
194 "__utmc=160408618; "
195 "GX=DQAAAOEAAACWJYdewdE9rIrW6qw3PtVi2-d729qaa-74KqOsM1NVQblK4VhX"
196 "hoALMsy6HOdDad2Sz0flUByv7etmo3mLMidGrBoljqO9hSVA40SLqpG_iuKKSHX"
197 "RW3Np4bq0F0SDGDNsW0DSmTS9ufMRrlpARJDS7qAI6M3bghqJp4eABKZiRqebHT"
198 "pMU-RXvTI5D5oCF1vYxYofH_l1Kviuiy3oQ1kS1enqWgbhJ2t61_SNdv-1XJIS0"
199 "O3YeHLmVCs62O6zp89QwakfAWK9d3IDQvVSJzCQsvxvNIvaZFa567MawWlXg0Rh"
200 "1zFMi5vzcns38-8_Sns; "
201 "GA=v*2%2Fmem*57968640*47239936%2Fmem*57968640*47114716%2Fno-nm-"
202 "yj*15%2Fno-cc-yj*5%2Fpc-ch*133685%2Fpc-s-cr*133947%2Fpc-s-t*1339"
203 "47%2Fno-nm-yj*4%2Fno-cc-yj*1%2Fceft-as*1%2Fceft-nqas*0%2Fad-ra-c"
204 "v_p%2Fad-nr-cv_p-f*1%2Fad-v-cv_p*859%2Fad-ns-cv_p-f*1%2Ffn-v-ad%"
205 "2Fpc-t*250%2Fpc-cm*461%2Fpc-s-cr*722%2Fpc-s-t*722%2Fau_p*4"
206 "SICAID=AJKiYcHdKgxum7KMXG0ei2t1-W4OD1uW-ecNsCqC0wDuAXiDGIcT_HA2o1"
207 "3Rs1UKCuBAF9g8rWNOFbxt8PSNSHFuIhOo2t6bJAVpCsMU5Laa6lewuTMYI8MzdQP"
208 "ARHKyW-koxuhMZHUnGBJAM1gJODe0cATO_KGoX4pbbFxxJ5IicRxOrWK_5rU3cdy6"
209 "edlR9FsEdH6iujMcHkbE5l18ehJDwTWmBKBzVD87naobhMMrF6VvnDGxQVGp9Ir_b"
210 "Rgj3RWUoPumQVCxtSOBdX0GlJOEcDTNCzQIm9BSfetog_eP_TfYubKudt5eMsXmN6"
211 "QnyXHeGeK2UINUzJ-D30AFcpqYgH9_1BvYSpi7fc7_ydBU8TaD8ZRxvtnzXqj0RfG"
212 "tuHghmv3aD-uzSYJ75XDdzKdizZ86IG6Fbn1XFhYZM-fbHhm3mVEXnyRW4ZuNOLFk"
213 "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn"
214 "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr"
215 "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo ";
216 }
217
CreateResponseHeaders(const std::string & status_code)218 spdy::Http2HeaderBlock CreateResponseHeaders(const std::string& status_code) {
219 spdy::Http2HeaderBlock headers;
220 headers[":status"] = status_code;
221 return headers;
222 }
223
ReadData(std::string_view expected_data)224 void ReadData(std::string_view expected_data) {
225 auto buffer =
226 base::MakeRefCounted<IOBufferWithSize>(expected_data.length() + 1);
227 EXPECT_EQ(static_cast<int>(expected_data.length()),
228 stream_->Read(buffer.get(), expected_data.length() + 1));
229 EXPECT_EQ(expected_data,
230 std::string_view(buffer->data(), expected_data.length()));
231 }
232
ProcessHeaders(const spdy::Http2HeaderBlock & headers)233 quic::QuicHeaderList ProcessHeaders(const spdy::Http2HeaderBlock& headers) {
234 quic::QuicHeaderList h = quic::test::AsHeaderList(headers);
235 stream_->OnStreamHeaderList(false, h.uncompressed_header_bytes(), h);
236 return h;
237 }
238
ProcessTrailers(const spdy::Http2HeaderBlock & headers)239 quic::QuicHeaderList ProcessTrailers(const spdy::Http2HeaderBlock& headers) {
240 quic::QuicHeaderList h = quic::test::AsHeaderList(headers);
241 stream_->OnStreamHeaderList(true, h.uncompressed_header_bytes(), h);
242 return h;
243 }
244
ProcessHeadersFull(const spdy::Http2HeaderBlock & headers)245 quic::QuicHeaderList ProcessHeadersFull(
246 const spdy::Http2HeaderBlock& headers) {
247 quic::QuicHeaderList h = ProcessHeaders(headers);
248 TestCompletionCallback callback;
249 EXPECT_EQ(static_cast<int>(h.uncompressed_header_bytes()),
250 handle_->ReadInitialHeaders(&headers_, callback.callback()));
251 EXPECT_EQ(headers, headers_);
252 EXPECT_TRUE(stream_->header_list().empty());
253 return h;
254 }
255
GetNthClientInitiatedBidirectionalStreamId(int n)256 quic::QuicStreamId GetNthClientInitiatedBidirectionalStreamId(int n) {
257 return quic::test::GetNthClientInitiatedBidirectionalStreamId(
258 session_.connection()->transport_version(), n);
259 }
260
GetNthServerInitiatedUnidirectionalStreamId(int n)261 quic::QuicStreamId GetNthServerInitiatedUnidirectionalStreamId(int n) {
262 return quic::test::GetNthServerInitiatedUnidirectionalStreamId(
263 session_.connection()->transport_version(), n);
264 }
265
ResetStreamCallback(QuicChromiumClientStream * stream,int)266 void ResetStreamCallback(QuicChromiumClientStream* stream, int /*rv*/) {
267 stream->Reset(quic::QUIC_STREAM_CANCELLED);
268 }
269
ConstructDataHeader(size_t body_len)270 std::string ConstructDataHeader(size_t body_len) {
271 quiche::QuicheBuffer buffer = quic::HttpEncoder::SerializeDataFrameHeader(
272 body_len, quiche::SimpleBufferAllocator::Get());
273 return std::string(buffer.data(), buffer.size());
274 }
275
276 const quic::ParsedQuicVersion version_;
277 quic::QuicCryptoClientConfig crypto_config_;
278 std::unique_ptr<QuicChromiumClientStream::Handle> handle_;
279 std::unique_ptr<QuicChromiumClientStream::Handle> handle2_;
280 quic::test::MockQuicConnectionHelper helper_;
281 quic::test::MockAlarmFactory alarm_factory_;
282 MockQuicClientSessionBase session_;
283 raw_ptr<QuicChromiumClientStream> stream_;
284 spdy::Http2HeaderBlock headers_;
285 spdy::Http2HeaderBlock trailers_;
286 };
287
288 INSTANTIATE_TEST_SUITE_P(Version,
289 QuicChromiumClientStreamTest,
290 ::testing::ValuesIn(AllSupportedQuicVersions()),
291 ::testing::PrintToStringParamName());
292
TEST_P(QuicChromiumClientStreamTest,Handle)293 TEST_P(QuicChromiumClientStreamTest, Handle) {
294 testing::InSequence seq;
295 EXPECT_TRUE(handle_->IsOpen());
296 EXPECT_EQ(quic::test::GetNthClientInitiatedBidirectionalStreamId(
297 version_.transport_version, 0),
298 handle_->id());
299 EXPECT_EQ(quic::QUIC_NO_ERROR, handle_->connection_error());
300 EXPECT_EQ(quic::QUIC_STREAM_NO_ERROR, handle_->stream_error());
301 EXPECT_TRUE(handle_->IsFirstStream());
302 EXPECT_FALSE(handle_->IsDoneReading());
303 EXPECT_FALSE(handle_->fin_sent());
304 EXPECT_FALSE(handle_->fin_received());
305 EXPECT_EQ(0u, handle_->stream_bytes_read());
306 EXPECT_EQ(0u, handle_->stream_bytes_written());
307 EXPECT_EQ(0u, handle_->NumBytesConsumed());
308
309 InitializeHeaders();
310 quic::QuicStreamOffset offset = 0;
311 ProcessHeadersFull(headers_);
312 quic::QuicStreamFrame frame2(
313 quic::test::GetNthClientInitiatedBidirectionalStreamId(
314 version_.transport_version, 0),
315 true, offset, std::string_view());
316 stream_->OnStreamFrame(frame2);
317 EXPECT_TRUE(handle_->fin_received());
318 handle_->OnFinRead();
319
320 const char kData1[] = "hello world";
321 const size_t kDataLen = std::size(kData1);
322
323 // All data written.
324 std::string header = ConstructDataHeader(kDataLen);
325 EXPECT_CALL(session_,
326 WritevData(stream_->id(), _, _, _, quic::NOT_RETRANSMISSION, _))
327 .WillOnce(Return(quic::QuicConsumedData(header.length(), false)));
328 EXPECT_CALL(session_,
329 WritevData(stream_->id(), _, _, _, quic::NOT_RETRANSMISSION, _))
330 .WillOnce(Return(quic::QuicConsumedData(kDataLen, true)));
331 TestCompletionCallback callback;
332 EXPECT_EQ(OK, handle_->WriteStreamData(base::StringPiece(kData1, kDataLen),
333 true, callback.callback()));
334
335 EXPECT_FALSE(handle_->IsOpen());
336 EXPECT_EQ(quic::test::GetNthClientInitiatedBidirectionalStreamId(
337 version_.transport_version, 0),
338 handle_->id());
339 EXPECT_EQ(quic::QUIC_NO_ERROR, handle_->connection_error());
340 EXPECT_EQ(quic::QUIC_STREAM_NO_ERROR, handle_->stream_error());
341 EXPECT_TRUE(handle_->IsFirstStream());
342 EXPECT_TRUE(handle_->IsDoneReading());
343 EXPECT_TRUE(handle_->fin_sent());
344 EXPECT_TRUE(handle_->fin_received());
345 EXPECT_EQ(0u, handle_->stream_bytes_read());
346 EXPECT_EQ(header.length() + kDataLen, handle_->stream_bytes_written());
347 EXPECT_EQ(0u, handle_->NumBytesConsumed());
348
349 EXPECT_EQ(ERR_CONNECTION_CLOSED,
350 handle_->WriteStreamData(base::StringPiece(kData1, kDataLen), true,
351 callback.callback()));
352
353 std::vector<scoped_refptr<IOBuffer>> buffers = {
354 base::MakeRefCounted<IOBufferWithSize>(10)};
355 std::vector<int> lengths = {10};
356 EXPECT_EQ(
357 ERR_CONNECTION_CLOSED,
358 handle_->WritevStreamData(buffers, lengths, true, callback.callback()));
359
360 spdy::Http2HeaderBlock headers;
361 EXPECT_EQ(0, handle_->WriteHeaders(std::move(headers), true, nullptr));
362 }
363
TEST_P(QuicChromiumClientStreamTest,HandleAfterConnectionClose)364 TEST_P(QuicChromiumClientStreamTest, HandleAfterConnectionClose) {
365 quic::test::QuicConnectionPeer::TearDownLocalConnectionState(
366 session_.connection());
367 stream_->OnConnectionClosed(quic::QUIC_INVALID_FRAME_DATA,
368 quic::ConnectionCloseSource::FROM_PEER);
369
370 EXPECT_FALSE(handle_->IsOpen());
371 EXPECT_EQ(quic::QUIC_INVALID_FRAME_DATA, handle_->connection_error());
372 }
373
TEST_P(QuicChromiumClientStreamTest,HandleAfterStreamReset)374 TEST_P(QuicChromiumClientStreamTest, HandleAfterStreamReset) {
375 // Make a STOP_SENDING frame and pass it to QUIC. We need both a REST_STREAM
376 // and a STOP_SENDING to effect a closed stream.
377 quic::QuicStopSendingFrame stop_sending_frame(
378 quic::kInvalidControlFrameId,
379 quic::test::GetNthClientInitiatedBidirectionalStreamId(
380 version_.transport_version, 0),
381 quic::QUIC_STREAM_CANCELLED);
382 session_.OnStopSendingFrame(stop_sending_frame);
383
384 // Verify that the Handle still behaves correctly after the stream is reset.
385 quic::QuicRstStreamFrame rst(
386 quic::kInvalidControlFrameId,
387 quic::test::GetNthClientInitiatedBidirectionalStreamId(
388 version_.transport_version, 0),
389 quic::QUIC_STREAM_CANCELLED, 0);
390
391 stream_->OnStreamReset(rst);
392 EXPECT_FALSE(handle_->IsOpen());
393 EXPECT_EQ(quic::QUIC_STREAM_CANCELLED, handle_->stream_error());
394 }
395
TEST_P(QuicChromiumClientStreamTest,OnFinRead)396 TEST_P(QuicChromiumClientStreamTest, OnFinRead) {
397 InitializeHeaders();
398 quic::QuicStreamOffset offset = 0;
399 ProcessHeadersFull(headers_);
400 quic::QuicStreamFrame frame2(
401 quic::test::GetNthClientInitiatedBidirectionalStreamId(
402 version_.transport_version, 0),
403 true, offset, std::string_view());
404 stream_->OnStreamFrame(frame2);
405 }
406
TEST_P(QuicChromiumClientStreamTest,OnDataAvailable)407 TEST_P(QuicChromiumClientStreamTest, OnDataAvailable) {
408 InitializeHeaders();
409 ProcessHeadersFull(headers_);
410
411 const char data[] = "hello world!";
412 int data_len = strlen(data);
413 size_t offset = 0;
414 std::string header = ConstructDataHeader(data_len);
415 stream_->OnStreamFrame(quic::QuicStreamFrame(
416 quic::test::GetNthClientInitiatedBidirectionalStreamId(
417 version_.transport_version, 0),
418 /*fin=*/false,
419 /*offset=*/offset, header));
420 offset += header.length();
421 stream_->OnStreamFrame(quic::QuicStreamFrame(
422 quic::test::GetNthClientInitiatedBidirectionalStreamId(
423 version_.transport_version, 0),
424 /*fin=*/false,
425 /*offset=*/offset, data));
426
427 // Read the body and verify that it arrives correctly.
428 TestCompletionCallback callback;
429 auto buffer = base::MakeRefCounted<IOBufferWithSize>(2 * data_len);
430 EXPECT_EQ(data_len,
431 handle_->ReadBody(buffer.get(), 2 * data_len, callback.callback()));
432 EXPECT_EQ(std::string_view(data), std::string_view(buffer->data(), data_len));
433 }
434
TEST_P(QuicChromiumClientStreamTest,OnDataAvailableAfterReadBody)435 TEST_P(QuicChromiumClientStreamTest, OnDataAvailableAfterReadBody) {
436 InitializeHeaders();
437 ProcessHeadersFull(headers_);
438
439 const char data[] = "hello world!";
440 int data_len = strlen(data);
441
442 // Start to read the body.
443 TestCompletionCallback callback;
444 auto buffer = base::MakeRefCounted<IOBufferWithSize>(2 * data_len);
445 EXPECT_EQ(ERR_IO_PENDING,
446 handle_->ReadBody(buffer.get(), 2 * data_len, callback.callback()));
447
448 size_t offset = 0;
449 std::string header = ConstructDataHeader(data_len);
450 stream_->OnStreamFrame(quic::QuicStreamFrame(
451 quic::test::GetNthClientInitiatedBidirectionalStreamId(
452 version_.transport_version, 0),
453 /*fin=*/false,
454 /*offset=*/offset, header));
455 offset += header.length();
456
457 stream_->OnStreamFrame(quic::QuicStreamFrame(
458 quic::test::GetNthClientInitiatedBidirectionalStreamId(
459 version_.transport_version, 0),
460 /*fin=*/false,
461 /*offset=*/offset, data));
462
463 EXPECT_EQ(data_len, callback.WaitForResult());
464 EXPECT_EQ(std::string_view(data), std::string_view(buffer->data(), data_len));
465 base::RunLoop().RunUntilIdle();
466 }
467
TEST_P(QuicChromiumClientStreamTest,ProcessHeadersWithError)468 TEST_P(QuicChromiumClientStreamTest, ProcessHeadersWithError) {
469 spdy::Http2HeaderBlock bad_headers;
470 bad_headers["NAME"] = "...";
471
472 EXPECT_CALL(
473 *static_cast<quic::test::MockQuicConnection*>(session_.connection()),
474 OnStreamReset(quic::test::GetNthClientInitiatedBidirectionalStreamId(
475 version_.transport_version, 0),
476 quic::QUIC_BAD_APPLICATION_PAYLOAD));
477
478 auto headers = quic::test::AsHeaderList(bad_headers);
479 stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
480 headers);
481
482 base::RunLoop().RunUntilIdle();
483 }
484
TEST_P(QuicChromiumClientStreamTest,OnDataAvailableWithError)485 TEST_P(QuicChromiumClientStreamTest, OnDataAvailableWithError) {
486 InitializeHeaders();
487 auto headers = quic::test::AsHeaderList(headers_);
488 ProcessHeadersFull(headers_);
489
490 const char data[] = "hello world!";
491 int data_len = strlen(data);
492
493 // Start to read the body.
494 TestCompletionCallback callback;
495 auto buffer = base::MakeRefCounted<IOBufferWithSize>(2 * data_len);
496 EXPECT_EQ(
497 ERR_IO_PENDING,
498 handle_->ReadBody(
499 buffer.get(), 2 * data_len,
500 base::BindOnce(&QuicChromiumClientStreamTest::ResetStreamCallback,
501 base::Unretained(this), stream_)));
502
503 EXPECT_CALL(
504 *static_cast<quic::test::MockQuicConnection*>(session_.connection()),
505 OnStreamReset(quic::test::GetNthClientInitiatedBidirectionalStreamId(
506 version_.transport_version, 0),
507 quic::QUIC_STREAM_CANCELLED));
508
509 // Receive the data and close the stream during the callback.
510 size_t offset = 0;
511 std::string header = ConstructDataHeader(data_len);
512 stream_->OnStreamFrame(quic::QuicStreamFrame(
513 quic::test::GetNthClientInitiatedBidirectionalStreamId(
514 version_.transport_version, 0),
515 /*fin=*/false,
516 /*offset=*/offset, header));
517 offset += header.length();
518 stream_->OnStreamFrame(quic::QuicStreamFrame(
519 quic::test::GetNthClientInitiatedBidirectionalStreamId(
520 version_.transport_version, 0),
521 /*fin=*/false,
522 /*offset=*/0, data));
523
524 base::RunLoop().RunUntilIdle();
525 }
526
TEST_P(QuicChromiumClientStreamTest,OnError)527 TEST_P(QuicChromiumClientStreamTest, OnError) {
528 // EXPECT_CALL(delegate_, OnError(ERR_INTERNET_DISCONNECTED)).Times(1);
529
530 stream_->OnError(ERR_INTERNET_DISCONNECTED);
531 stream_->OnError(ERR_INTERNET_DISCONNECTED);
532 }
533
TEST_P(QuicChromiumClientStreamTest,OnTrailers)534 TEST_P(QuicChromiumClientStreamTest, OnTrailers) {
535 InitializeHeaders();
536 ProcessHeadersFull(headers_);
537
538 const char data[] = "hello world!";
539 int data_len = strlen(data);
540 size_t offset = 0;
541 std::string header = ConstructDataHeader(data_len);
542 stream_->OnStreamFrame(quic::QuicStreamFrame(
543 quic::test::GetNthClientInitiatedBidirectionalStreamId(
544 version_.transport_version, 0),
545 /*fin=*/false,
546 /*offset=*/offset, header));
547 offset += header.length();
548 stream_->OnStreamFrame(quic::QuicStreamFrame(
549 quic::test::GetNthClientInitiatedBidirectionalStreamId(
550 version_.transport_version, 0),
551 /*fin=*/false,
552 /*offset=*/offset, data));
553
554 // Read the body and verify that it arrives correctly.
555 TestCompletionCallback callback;
556 auto buffer = base::MakeRefCounted<IOBufferWithSize>(2 * data_len);
557 EXPECT_EQ(data_len,
558 handle_->ReadBody(buffer.get(), 2 * data_len, callback.callback()));
559 EXPECT_EQ(std::string_view(data), std::string_view(buffer->data(), data_len));
560
561 spdy::Http2HeaderBlock trailers;
562 trailers["bar"] = "foo";
563
564 auto t = ProcessTrailers(trailers);
565
566 TestCompletionCallback trailers_callback;
567 EXPECT_EQ(
568 static_cast<int>(t.uncompressed_header_bytes()),
569 handle_->ReadTrailingHeaders(&trailers_, trailers_callback.callback()));
570
571 // Read the body and verify that it arrives correctly.
572 EXPECT_EQ(0,
573 handle_->ReadBody(buffer.get(), 2 * data_len, callback.callback()));
574
575 EXPECT_EQ(trailers, trailers_);
576 base::RunLoop().RunUntilIdle();
577 }
578
579 // Tests that trailers are marked as consumed only before delegate is to be
580 // immediately notified about trailers.
TEST_P(QuicChromiumClientStreamTest,MarkTrailersConsumedWhenNotifyDelegate)581 TEST_P(QuicChromiumClientStreamTest, MarkTrailersConsumedWhenNotifyDelegate) {
582 InitializeHeaders();
583 ProcessHeadersFull(headers_);
584
585 const char data[] = "hello world!";
586 int data_len = strlen(data);
587 size_t offset = 0;
588 std::string header = ConstructDataHeader(data_len);
589 stream_->OnStreamFrame(quic::QuicStreamFrame(
590 quic::test::GetNthClientInitiatedBidirectionalStreamId(
591 version_.transport_version, 0),
592 /*fin=*/false,
593 /*offset=*/offset, header));
594 offset += header.length();
595 stream_->OnStreamFrame(quic::QuicStreamFrame(
596 quic::test::GetNthClientInitiatedBidirectionalStreamId(
597 version_.transport_version, 0),
598 /*fin=*/false,
599 /*offset=*/offset, data));
600
601 // Read the body and verify that it arrives correctly.
602 TestCompletionCallback callback;
603 auto buffer = base::MakeRefCounted<IOBufferWithSize>(2 * data_len);
604 EXPECT_EQ(data_len,
605 handle_->ReadBody(buffer.get(), 2 * data_len, callback.callback()));
606 EXPECT_EQ(std::string_view(data), std::string_view(buffer->data(), data_len));
607
608 // Read again, and it will be pending.
609 EXPECT_THAT(
610 handle_->ReadBody(buffer.get(), 2 * data_len, callback.callback()),
611 IsError(ERR_IO_PENDING));
612
613 spdy::Http2HeaderBlock trailers;
614 trailers["bar"] = "foo";
615 quic::QuicHeaderList t = ProcessTrailers(trailers);
616 EXPECT_FALSE(stream_->IsDoneReading());
617
618 EXPECT_EQ(static_cast<int>(t.uncompressed_header_bytes()),
619 handle_->ReadTrailingHeaders(&trailers_, callback.callback()));
620
621 // Read the body and verify that it arrives correctly.
622 EXPECT_EQ(0, callback.WaitForResult());
623
624 // Make sure the stream is properly closed since trailers and data are all
625 // consumed.
626 EXPECT_TRUE(stream_->IsDoneReading());
627 EXPECT_EQ(trailers, trailers_);
628
629 base::RunLoop().RunUntilIdle();
630 }
631
632 // Test that if Read() is called after response body is read and after trailers
633 // are received but not yet delivered, Read() will return ERR_IO_PENDING instead
634 // of 0 (EOF).
TEST_P(QuicChromiumClientStreamTest,ReadAfterTrailersReceivedButNotDelivered)635 TEST_P(QuicChromiumClientStreamTest, ReadAfterTrailersReceivedButNotDelivered) {
636 InitializeHeaders();
637 ProcessHeadersFull(headers_);
638
639 const char data[] = "hello world!";
640 int data_len = strlen(data);
641 size_t offset = 0;
642 std::string header = ConstructDataHeader(data_len);
643 stream_->OnStreamFrame(quic::QuicStreamFrame(
644 quic::test::GetNthClientInitiatedBidirectionalStreamId(
645 version_.transport_version, 0),
646 /*fin=*/false,
647 /*offset=*/offset, header));
648 offset += header.length();
649 stream_->OnStreamFrame(quic::QuicStreamFrame(
650 quic::test::GetNthClientInitiatedBidirectionalStreamId(
651 version_.transport_version, 0),
652 /*fin=*/false,
653 /*offset=*/offset, data));
654
655 // Read the body and verify that it arrives correctly.
656 TestCompletionCallback callback;
657 auto buffer = base::MakeRefCounted<IOBufferWithSize>(2 * data_len);
658 EXPECT_EQ(data_len,
659 handle_->ReadBody(buffer.get(), 2 * data_len, callback.callback()));
660 EXPECT_EQ(std::string_view(data), std::string_view(buffer->data(), data_len));
661
662 // Deliver trailers. Delegate notification is posted asynchronously.
663 spdy::Http2HeaderBlock trailers;
664 trailers["bar"] = "foo";
665
666 quic::QuicHeaderList t = ProcessTrailers(trailers);
667
668 EXPECT_FALSE(stream_->IsDoneReading());
669 // Read again, it return ERR_IO_PENDING.
670 EXPECT_THAT(
671 handle_->ReadBody(buffer.get(), 2 * data_len, callback.callback()),
672 IsError(ERR_IO_PENDING));
673
674 // Trailers are not delivered
675 EXPECT_FALSE(stream_->IsDoneReading());
676
677 TestCompletionCallback callback2;
678 EXPECT_EQ(static_cast<int>(t.uncompressed_header_bytes()),
679 handle_->ReadTrailingHeaders(&trailers_, callback2.callback()));
680
681 // Read the body and verify that it arrives correctly.
682 // OnDataAvailable() should follow right after and Read() will return 0.
683 EXPECT_EQ(0, callback.WaitForResult());
684
685 // Make sure the stream is properly closed since trailers and data are all
686 // consumed.
687 EXPECT_TRUE(stream_->IsDoneReading());
688
689 EXPECT_EQ(trailers, trailers_);
690
691 base::RunLoop().RunUntilIdle();
692 }
693
TEST_P(QuicChromiumClientStreamTest,WriteStreamData)694 TEST_P(QuicChromiumClientStreamTest, WriteStreamData) {
695 testing::InSequence seq;
696 const char kData1[] = "hello world";
697 const size_t kDataLen = std::size(kData1);
698
699 // All data written.
700 std::string header = ConstructDataHeader(kDataLen);
701 EXPECT_CALL(session_,
702 WritevData(stream_->id(), _, _, _, quic::NOT_RETRANSMISSION, _))
703 .WillOnce(Return(quic::QuicConsumedData(header.length(), false)));
704 EXPECT_CALL(session_,
705 WritevData(stream_->id(), _, _, _, quic::NOT_RETRANSMISSION, _))
706 .WillOnce(Return(quic::QuicConsumedData(kDataLen, true)));
707 TestCompletionCallback callback;
708 EXPECT_EQ(OK, handle_->WriteStreamData(base::StringPiece(kData1, kDataLen),
709 true, callback.callback()));
710 }
711
TEST_P(QuicChromiumClientStreamTest,WriteStreamDataAsync)712 TEST_P(QuicChromiumClientStreamTest, WriteStreamDataAsync) {
713 testing::InSequence seq;
714 const char kData1[] = "hello world";
715 const size_t kDataLen = std::size(kData1);
716
717 // No data written.
718 EXPECT_CALL(session_,
719 WritevData(stream_->id(), _, _, _, quic::NOT_RETRANSMISSION, _))
720 .WillOnce(Return(quic::QuicConsumedData(0, false)));
721 TestCompletionCallback callback;
722 EXPECT_EQ(ERR_IO_PENDING,
723 handle_->WriteStreamData(base::StringPiece(kData1, kDataLen), true,
724 callback.callback()));
725 ASSERT_FALSE(callback.have_result());
726
727 // All data written.
728 std::string header = ConstructDataHeader(kDataLen);
729 EXPECT_CALL(session_,
730 WritevData(stream_->id(), _, _, _, quic::NOT_RETRANSMISSION, _))
731 .WillOnce(Return(quic::QuicConsumedData(header.length(), false)));
732 EXPECT_CALL(session_,
733 WritevData(stream_->id(), _, _, _, quic::NOT_RETRANSMISSION, _))
734 .WillOnce(Return(quic::QuicConsumedData(kDataLen, true)));
735 stream_->OnCanWrite();
736 // Do 2 writes in version 99.
737 stream_->OnCanWrite();
738 ASSERT_TRUE(callback.have_result());
739 EXPECT_THAT(callback.WaitForResult(), IsOk());
740 }
741
TEST_P(QuicChromiumClientStreamTest,WritevStreamData)742 TEST_P(QuicChromiumClientStreamTest, WritevStreamData) {
743 testing::InSequence seq;
744 scoped_refptr<StringIOBuffer> buf1 =
745 base::MakeRefCounted<StringIOBuffer>("hello world!");
746 scoped_refptr<StringIOBuffer> buf2 =
747 base::MakeRefCounted<StringIOBuffer>("Just a small payload");
748
749 // All data written.
750 std::string header = ConstructDataHeader(buf1->size());
751 EXPECT_CALL(session_,
752 WritevData(stream_->id(), _, _, _, quic::NOT_RETRANSMISSION, _))
753 .WillOnce(Return(quic::QuicConsumedData(header.length(), false)));
754 EXPECT_CALL(session_,
755 WritevData(stream_->id(), _, _, _, quic::NOT_RETRANSMISSION, _))
756 .WillOnce(Return(quic::QuicConsumedData(buf1->size(), false)));
757 header = ConstructDataHeader(buf2->size());
758 EXPECT_CALL(session_,
759 WritevData(stream_->id(), _, _, _, quic::NOT_RETRANSMISSION, _))
760 .WillOnce(Return(quic::QuicConsumedData(header.length(), false)));
761 EXPECT_CALL(session_,
762 WritevData(stream_->id(), _, _, _, quic::NOT_RETRANSMISSION, _))
763 .WillOnce(Return(quic::QuicConsumedData(buf2->size(), true)));
764 TestCompletionCallback callback;
765 EXPECT_EQ(
766 OK, handle_->WritevStreamData({buf1, buf2}, {buf1->size(), buf2->size()},
767 true, callback.callback()));
768 }
769
TEST_P(QuicChromiumClientStreamTest,WritevStreamDataAsync)770 TEST_P(QuicChromiumClientStreamTest, WritevStreamDataAsync) {
771 testing::InSequence seq;
772 scoped_refptr<StringIOBuffer> buf1 =
773 base::MakeRefCounted<StringIOBuffer>("hello world!");
774 scoped_refptr<StringIOBuffer> buf2 =
775 base::MakeRefCounted<StringIOBuffer>("Just a small payload");
776
777 // Only a part of the data is written.
778 std::string header = ConstructDataHeader(buf1->size());
779 EXPECT_CALL(session_,
780 WritevData(stream_->id(), _, _, _, quic::NOT_RETRANSMISSION, _))
781 .WillOnce(Return(quic::QuicConsumedData(header.length(), false)));
782 EXPECT_CALL(session_,
783 WritevData(stream_->id(), _, _, _, quic::NOT_RETRANSMISSION, _))
784 // First piece of data is written.
785 .WillOnce(Return(quic::QuicConsumedData(buf1->size(), false)));
786 // Second piece of data is queued.
787 EXPECT_CALL(session_,
788 WritevData(stream_->id(), _, _, _, quic::NOT_RETRANSMISSION, _))
789 .WillOnce(Return(quic::QuicConsumedData(0, false)));
790 TestCompletionCallback callback;
791 EXPECT_EQ(ERR_IO_PENDING,
792 handle_->WritevStreamData({buf1.get(), buf2.get()},
793 {buf1->size(), buf2->size()}, true,
794 callback.callback()));
795 ASSERT_FALSE(callback.have_result());
796
797 // The second piece of data is written.
798 header = ConstructDataHeader(buf2->size());
799 EXPECT_CALL(session_,
800 WritevData(stream_->id(), _, _, _, quic::NOT_RETRANSMISSION, _))
801 .WillOnce(Return(quic::QuicConsumedData(header.length(), false)));
802 EXPECT_CALL(session_,
803 WritevData(stream_->id(), _, _, _, quic::NOT_RETRANSMISSION, _))
804 .WillOnce(Return(quic::QuicConsumedData(buf2->size(), true)));
805 stream_->OnCanWrite();
806 stream_->OnCanWrite();
807 ASSERT_TRUE(callback.have_result());
808 EXPECT_THAT(callback.WaitForResult(), IsOk());
809 }
810
TEST_P(QuicChromiumClientStreamTest,HeadersBeforeHandle)811 TEST_P(QuicChromiumClientStreamTest, HeadersBeforeHandle) {
812 // We don't use stream_ because we want an incoming server push
813 // stream.
814 quic::QuicStreamId stream_id = GetNthServerInitiatedUnidirectionalStreamId(0);
815 QuicChromiumClientStream* stream2 = new QuicChromiumClientStream(
816 stream_id, &session_, quic::READ_UNIDIRECTIONAL, NetLogWithSource(),
817 TRAFFIC_ANNOTATION_FOR_TESTS);
818 session_.ActivateStream(base::WrapUnique(stream2));
819
820 InitializeHeaders();
821
822 // Receive the headers before the delegate is set.
823 quic::QuicHeaderList header_list = quic::test::AsHeaderList(headers_);
824 stream2->OnStreamHeaderList(true, header_list.uncompressed_header_bytes(),
825 header_list);
826
827 // Now set the delegate and verify that the headers are delivered.
828 handle2_ = stream2->CreateHandle();
829 TestCompletionCallback callback;
830 EXPECT_EQ(static_cast<int>(header_list.uncompressed_header_bytes()),
831 handle2_->ReadInitialHeaders(&headers_, callback.callback()));
832 EXPECT_EQ(headers_, headers_);
833 }
834
TEST_P(QuicChromiumClientStreamTest,HeadersAndDataBeforeHandle)835 TEST_P(QuicChromiumClientStreamTest, HeadersAndDataBeforeHandle) {
836 // We don't use stream_ because we want an incoming server push
837 // stream.
838 quic::QuicStreamId stream_id = GetNthServerInitiatedUnidirectionalStreamId(0);
839 QuicChromiumClientStream* stream2 = new QuicChromiumClientStream(
840 stream_id, &session_, quic::READ_UNIDIRECTIONAL, NetLogWithSource(),
841 TRAFFIC_ANNOTATION_FOR_TESTS);
842 session_.ActivateStream(base::WrapUnique(stream2));
843
844 InitializeHeaders();
845
846 // Receive the headers and data before the delegate is set.
847 quic::QuicHeaderList header_list = quic::test::AsHeaderList(headers_);
848 stream2->OnStreamHeaderList(false, header_list.uncompressed_header_bytes(),
849 header_list);
850 const char data[] = "hello world!";
851
852 size_t offset = 0;
853 std::string header = ConstructDataHeader(strlen(data));
854 stream2->OnStreamFrame(quic::QuicStreamFrame(stream_id,
855 /*fin=*/false,
856 /*offset=*/offset, header));
857 offset += header.length();
858 stream2->OnStreamFrame(quic::QuicStreamFrame(stream_id, /*fin=*/false,
859 /*offset=*/offset, data));
860
861 // Now set the delegate and verify that the headers are delivered, but
862 // not the data, which needs to be read explicitly.
863 handle2_ = stream2->CreateHandle();
864 TestCompletionCallback callback;
865 EXPECT_EQ(static_cast<int>(header_list.uncompressed_header_bytes()),
866 handle2_->ReadInitialHeaders(&headers_, callback.callback()));
867 EXPECT_EQ(headers_, headers_);
868 base::RunLoop().RunUntilIdle();
869
870 // Now explicitly read the data.
871 int data_len = std::size(data) - 1;
872 auto buffer = base::MakeRefCounted<IOBufferWithSize>(data_len + 1);
873 ASSERT_EQ(data_len, stream2->Read(buffer.get(), data_len + 1));
874 EXPECT_EQ(std::string_view(data), std::string_view(buffer->data(), data_len));
875 }
876
877 // Regression test for https://crbug.com/1043531.
TEST_P(QuicChromiumClientStreamTest,ResetOnEmptyResponseHeaders)878 TEST_P(QuicChromiumClientStreamTest, ResetOnEmptyResponseHeaders) {
879 const spdy::Http2HeaderBlock empty_response_headers;
880 ProcessHeaders(empty_response_headers);
881
882 // Empty headers are allowed by QuicSpdyStream,
883 // but an error is generated by QuicChromiumClientStream.
884 int rv = handle_->ReadInitialHeaders(&headers_, CompletionOnceCallback());
885 EXPECT_THAT(rv, IsError(net::ERR_QUIC_PROTOCOL_ERROR));
886 }
887
888 // Tests that the stream resets when it receives an invalid ":status"
889 // pseudo-header value.
TEST_P(QuicChromiumClientStreamTest,InvalidStatus)890 TEST_P(QuicChromiumClientStreamTest, InvalidStatus) {
891 spdy::Http2HeaderBlock headers = CreateResponseHeaders("xxx");
892
893 EXPECT_CALL(
894 *static_cast<quic::test::MockQuicConnection*>(session_.connection()),
895 OnStreamReset(quic::test::GetNthClientInitiatedBidirectionalStreamId(
896 version_.transport_version, 0),
897 quic::QUIC_BAD_APPLICATION_PAYLOAD));
898
899 ProcessHeaders(headers);
900 EXPECT_FALSE(handle_->IsOpen());
901 EXPECT_EQ(quic::QUIC_BAD_APPLICATION_PAYLOAD, handle_->stream_error());
902 }
903
904 // Tests that the stream resets when it receives 101 Switching Protocols.
TEST_P(QuicChromiumClientStreamTest,SwitchingProtocolsResponse)905 TEST_P(QuicChromiumClientStreamTest, SwitchingProtocolsResponse) {
906 spdy::Http2HeaderBlock informational_headers = CreateResponseHeaders("101");
907
908 EXPECT_CALL(
909 *static_cast<quic::test::MockQuicConnection*>(session_.connection()),
910 OnStreamReset(quic::test::GetNthClientInitiatedBidirectionalStreamId(
911 version_.transport_version, 0),
912 quic::QUIC_BAD_APPLICATION_PAYLOAD));
913
914 ProcessHeaders(informational_headers);
915 EXPECT_FALSE(handle_->IsOpen());
916 EXPECT_EQ(quic::QUIC_BAD_APPLICATION_PAYLOAD, handle_->stream_error());
917 }
918
919 // Tests that the stream ignores 100 Continue response.
TEST_P(QuicChromiumClientStreamTest,ContinueResponse)920 TEST_P(QuicChromiumClientStreamTest, ContinueResponse) {
921 spdy::Http2HeaderBlock informational_headers = CreateResponseHeaders("100");
922
923 // This informational headers should be ignored.
924 ProcessHeaders(informational_headers);
925
926 // Pass the initial headers.
927 InitializeHeaders();
928 quic::QuicHeaderList header_list = ProcessHeaders(headers_);
929
930 // Read the initial headers.
931 spdy::Http2HeaderBlock response_headers;
932 // Pass DoNothing because the initial headers is already available and the
933 // callback won't be called.
934 EXPECT_EQ(static_cast<int>(header_list.uncompressed_header_bytes()),
935 handle_->ReadInitialHeaders(&response_headers, base::DoNothing()));
936 base::RunLoop().RunUntilIdle();
937
938 EXPECT_EQ(response_headers, headers_);
939 }
940
941 // Tests that the stream handles 103 Early Hints responses.
TEST_P(QuicChromiumClientStreamTest,EarlyHintsResponses)942 TEST_P(QuicChromiumClientStreamTest, EarlyHintsResponses) {
943 // Pass Two Early Hints responses to the stream.
944 spdy::Http2HeaderBlock hints1_headers = CreateResponseHeaders("103");
945 hints1_headers["x-header1"] = "foo";
946 quic::QuicHeaderList header_list = ProcessHeaders(hints1_headers);
947 const size_t hints1_bytes = header_list.uncompressed_header_bytes();
948
949 spdy::Http2HeaderBlock hints2_headers = CreateResponseHeaders("103");
950 hints2_headers["x-header2"] = "foobarbaz";
951 header_list = ProcessHeaders(hints2_headers);
952 const size_t hints2_bytes = header_list.uncompressed_header_bytes();
953
954 // Pass the initial headers to the stream.
955 InitializeHeaders();
956 header_list = ProcessHeaders(headers_);
957 const size_t initial_headers_bytes = header_list.uncompressed_header_bytes();
958
959 spdy::Http2HeaderBlock headers;
960
961 // Read headers. The first two reads should return Early Hints.
962 EXPECT_EQ(static_cast<int>(hints1_bytes),
963 handle_->ReadInitialHeaders(&headers, base::DoNothing()));
964 base::RunLoop().RunUntilIdle();
965 EXPECT_EQ(headers, hints1_headers);
966 base::TimeTicks first_early_hints_time = handle_->first_early_hints_time();
967 EXPECT_FALSE(first_early_hints_time.is_null());
968
969 EXPECT_EQ(static_cast<int>(hints2_bytes),
970 handle_->ReadInitialHeaders(&headers, base::DoNothing()));
971 base::RunLoop().RunUntilIdle();
972 EXPECT_EQ(headers, hints2_headers);
973 EXPECT_EQ(first_early_hints_time, handle_->first_early_hints_time());
974
975 // The third read should return the initial headers.
976 EXPECT_EQ(static_cast<int>(initial_headers_bytes),
977 handle_->ReadInitialHeaders(&headers, base::DoNothing()));
978 base::RunLoop().RunUntilIdle();
979 EXPECT_EQ(headers, headers_);
980 }
981
982 // Tests that pending reads for Early Hints work.
TEST_P(QuicChromiumClientStreamTest,EarlyHintsAsync)983 TEST_P(QuicChromiumClientStreamTest, EarlyHintsAsync) {
984 spdy::Http2HeaderBlock headers;
985 TestCompletionCallback hints_callback;
986
987 // Try to read headers. The read should be blocked.
988 EXPECT_EQ(ERR_IO_PENDING,
989 handle_->ReadInitialHeaders(&headers, hints_callback.callback()));
990
991 // Pass an Early Hints and the initial headers.
992 spdy::Http2HeaderBlock hints_headers = CreateResponseHeaders("103");
993 hints_headers["x-header1"] = "foo";
994 quic::QuicHeaderList header_list = ProcessHeaders(hints_headers);
995 const size_t hints_bytes = header_list.uncompressed_header_bytes();
996 InitializeHeaders();
997 header_list = ProcessHeaders(headers_);
998 const size_t initial_headers_bytes = header_list.uncompressed_header_bytes();
999
1000 // Wait for the pending headers read. The result should be the Early Hints.
1001 const int hints_result = hints_callback.WaitForResult();
1002 EXPECT_EQ(hints_result, static_cast<int>(hints_bytes));
1003 EXPECT_EQ(headers, hints_headers);
1004
1005 // Second read should return the initial headers.
1006 EXPECT_EQ(static_cast<int>(initial_headers_bytes),
1007 handle_->ReadInitialHeaders(&headers, base::DoNothing()));
1008 EXPECT_EQ(headers, headers_);
1009 }
1010
1011 // Tests that Early Hints after the initial headers is treated as an error.
TEST_P(QuicChromiumClientStreamTest,EarlyHintsAfterInitialHeaders)1012 TEST_P(QuicChromiumClientStreamTest, EarlyHintsAfterInitialHeaders) {
1013 InitializeHeaders();
1014 ProcessHeadersFull(headers_);
1015
1016 // Early Hints after the initial headers are treated as trailers, and it
1017 // should result in an error because trailers must not contain pseudo-headers
1018 // like ":status".
1019 EXPECT_CALL(
1020 *static_cast<quic::test::MockQuicConnection*>(session_.connection()),
1021 CloseConnection(
1022 quic::QUIC_INVALID_HEADERS_STREAM_DATA, _,
1023 quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET));
1024
1025 spdy::Http2HeaderBlock hints_headers;
1026 hints_headers[":status"] = "103";
1027 ProcessHeaders(hints_headers);
1028 base::RunLoop().RunUntilIdle();
1029 }
1030
1031 // Similar to the above test but don't read the initial headers.
TEST_P(QuicChromiumClientStreamTest,EarlyHintsAfterInitialHeadersWithoutRead)1032 TEST_P(QuicChromiumClientStreamTest, EarlyHintsAfterInitialHeadersWithoutRead) {
1033 InitializeHeaders();
1034 ProcessHeaders(headers_);
1035
1036 // Early Hints after the initial headers are treated as trailers, and it
1037 // should result in an error because trailers must not contain pseudo-headers
1038 // like ":status".
1039 EXPECT_CALL(
1040 *static_cast<quic::test::MockQuicConnection*>(session_.connection()),
1041 CloseConnection(
1042 quic::QUIC_INVALID_HEADERS_STREAM_DATA, _,
1043 quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET));
1044
1045 spdy::Http2HeaderBlock hints_headers;
1046 hints_headers[":status"] = "103";
1047 ProcessHeaders(hints_headers);
1048 base::RunLoop().RunUntilIdle();
1049 }
1050
1051 // Regression test for https://crbug.com/1248970. Write an Early Hints headers,
1052 // an initial response headers and trailers in succession without reading in
1053 // the middle of writings.
TEST_P(QuicChromiumClientStreamTest,TrailersAfterEarlyHintsWithoutRead)1054 TEST_P(QuicChromiumClientStreamTest, TrailersAfterEarlyHintsWithoutRead) {
1055 // Process an Early Hints response headers on the stream.
1056 spdy::Http2HeaderBlock hints_headers = CreateResponseHeaders("103");
1057 quic::QuicHeaderList hints_header_list = ProcessHeaders(hints_headers);
1058
1059 // Process an initial response headers on the stream.
1060 InitializeHeaders();
1061 quic::QuicHeaderList header_list = ProcessHeaders(headers_);
1062
1063 // Process a trailer headers on the stream. This should not hit any DCHECK.
1064 spdy::Http2HeaderBlock trailers;
1065 trailers["bar"] = "foo";
1066 quic::QuicHeaderList trailer_header_list = ProcessTrailers(trailers);
1067 base::RunLoop().RunUntilIdle();
1068
1069 // Read the Early Hints response from the handle.
1070 {
1071 spdy::Http2HeaderBlock headers;
1072 TestCompletionCallback callback;
1073 EXPECT_EQ(static_cast<int>(hints_header_list.uncompressed_header_bytes()),
1074 handle_->ReadInitialHeaders(&headers, callback.callback()));
1075 EXPECT_EQ(headers, hints_headers);
1076 }
1077
1078 // Read the initial headers from the handle.
1079 {
1080 spdy::Http2HeaderBlock headers;
1081 TestCompletionCallback callback;
1082 EXPECT_EQ(static_cast<int>(header_list.uncompressed_header_bytes()),
1083 handle_->ReadInitialHeaders(&headers, callback.callback()));
1084 EXPECT_EQ(headers, headers_);
1085 }
1086
1087 // Read trailers from the handle.
1088 {
1089 spdy::Http2HeaderBlock headers;
1090 TestCompletionCallback callback;
1091 EXPECT_EQ(static_cast<int>(trailer_header_list.uncompressed_header_bytes()),
1092 handle_->ReadTrailingHeaders(&headers, callback.callback()));
1093 EXPECT_EQ(headers, trailers);
1094 }
1095 }
1096
1097 } // namespace
1098 } // namespace net::test
1099