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