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