1 // Copyright 2016 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 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "net/spdy/bidirectional_stream_spdy_impl.h"
11
12 #include <string>
13 #include <string_view>
14
15 #include "base/containers/span.h"
16 #include "base/run_loop.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/time/time.h"
19 #include "base/timer/mock_timer.h"
20 #include "base/timer/timer.h"
21 #include "net/base/load_timing_info.h"
22 #include "net/base/load_timing_info_test_util.h"
23 #include "net/base/net_errors.h"
24 #include "net/base/session_usage.h"
25 #include "net/dns/public/secure_dns_policy.h"
26 #include "net/http/http_request_info.h"
27 #include "net/http/http_response_headers.h"
28 #include "net/http/http_response_info.h"
29 #include "net/log/net_log.h"
30 #include "net/socket/socket_tag.h"
31 #include "net/socket/socket_test_util.h"
32 #include "net/spdy/spdy_session.h"
33 #include "net/spdy/spdy_test_util_common.h"
34 #include "net/test/cert_test_util.h"
35 #include "net/test/gtest_util.h"
36 #include "net/test/test_data_directory.h"
37 #include "net/test/test_with_task_environment.h"
38 #include "net/third_party/quiche/src/quiche/common/http/http_header_block.h"
39 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
40 #include "testing/gmock/include/gmock/gmock.h"
41 #include "testing/gtest/include/gtest/gtest.h"
42
43 using net::test::IsError;
44 using net::test::IsOk;
45
46 namespace net {
47
48 namespace {
49
50 const char kBodyData[] = "Body data";
51 const size_t kBodyDataSize = std::size(kBodyData);
52 // Size of the buffer to be allocated for each read.
53 const size_t kReadBufferSize = 4096;
54
55 // Tests the load timing of a stream that's connected and is not the first
56 // request sent on a connection.
TestLoadTimingReused(const LoadTimingInfo & load_timing_info)57 void TestLoadTimingReused(const LoadTimingInfo& load_timing_info) {
58 EXPECT_TRUE(load_timing_info.socket_reused);
59 EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
60
61 ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
62 ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
63 }
64
65 // Tests the load timing of a stream that's connected and using a fresh
66 // connection.
TestLoadTimingNotReused(const LoadTimingInfo & load_timing_info)67 void TestLoadTimingNotReused(const LoadTimingInfo& load_timing_info) {
68 EXPECT_FALSE(load_timing_info.socket_reused);
69 EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
70
71 ExpectConnectTimingHasTimes(
72 load_timing_info.connect_timing,
73 CONNECT_TIMING_HAS_SSL_TIMES | CONNECT_TIMING_HAS_DNS_TIMES);
74 ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
75 }
76
77 class TestDelegateBase : public BidirectionalStreamImpl::Delegate {
78 public:
TestDelegateBase(base::WeakPtr<SpdySession> session,IOBuffer * read_buf,int read_buf_len)79 TestDelegateBase(base::WeakPtr<SpdySession> session,
80 IOBuffer* read_buf,
81 int read_buf_len)
82 : stream_(std::make_unique<BidirectionalStreamSpdyImpl>(session,
83 NetLogSource())),
84 read_buf_(read_buf),
85 read_buf_len_(read_buf_len) {}
86
87 TestDelegateBase(const TestDelegateBase&) = delete;
88 TestDelegateBase& operator=(const TestDelegateBase&) = delete;
89
90 ~TestDelegateBase() override = default;
91
OnStreamReady(bool request_headers_sent)92 void OnStreamReady(bool request_headers_sent) override {
93 CHECK(!on_failed_called_);
94 }
95
OnHeadersReceived(const quiche::HttpHeaderBlock & response_headers)96 void OnHeadersReceived(
97 const quiche::HttpHeaderBlock& response_headers) override {
98 CHECK(!on_failed_called_);
99 CHECK(!not_expect_callback_);
100 response_headers_ = response_headers.Clone();
101 if (!do_not_start_read_)
102 StartOrContinueReading();
103 }
104
OnDataRead(int bytes_read)105 void OnDataRead(int bytes_read) override {
106 CHECK(!on_failed_called_);
107 CHECK(!not_expect_callback_);
108 on_data_read_count_++;
109 CHECK_GE(bytes_read, OK);
110 bytes_read_ += bytes_read;
111 data_received_.append(read_buf_->data(), bytes_read);
112 if (!do_not_start_read_)
113 StartOrContinueReading();
114 }
115
OnDataSent()116 void OnDataSent() override {
117 CHECK(!on_failed_called_);
118 CHECK(!not_expect_callback_);
119 on_data_sent_count_++;
120 }
121
OnTrailersReceived(const quiche::HttpHeaderBlock & trailers)122 void OnTrailersReceived(const quiche::HttpHeaderBlock& trailers) override {
123 CHECK(!on_failed_called_);
124 trailers_ = trailers.Clone();
125 if (run_until_completion_)
126 loop_->Quit();
127 }
128
OnFailed(int error)129 void OnFailed(int error) override {
130 CHECK(!on_failed_called_);
131 CHECK(!not_expect_callback_);
132 CHECK_NE(OK, error);
133 error_ = error;
134 on_failed_called_ = true;
135 if (run_until_completion_)
136 loop_->Quit();
137 }
138
Start(const BidirectionalStreamRequestInfo * request,const NetLogWithSource & net_log)139 void Start(const BidirectionalStreamRequestInfo* request,
140 const NetLogWithSource& net_log) {
141 stream_->Start(request, net_log,
142 /*send_request_headers_automatically=*/false, this,
143 std::make_unique<base::OneShotTimer>(),
144 TRAFFIC_ANNOTATION_FOR_TESTS);
145 not_expect_callback_ = false;
146 }
147
SendData(IOBuffer * data,int length,bool end_of_stream)148 void SendData(IOBuffer* data, int length, bool end_of_stream) {
149 SendvData({data}, {length}, end_of_stream);
150 }
151
SendvData(const std::vector<scoped_refptr<IOBuffer>> & data,const std::vector<int> & length,bool end_of_stream)152 void SendvData(const std::vector<scoped_refptr<IOBuffer>>& data,
153 const std::vector<int>& length,
154 bool end_of_stream) {
155 not_expect_callback_ = true;
156 stream_->SendvData(data, length, end_of_stream);
157 not_expect_callback_ = false;
158 }
159
160 // Sets whether the delegate should wait until the completion of the stream.
SetRunUntilCompletion(bool run_until_completion)161 void SetRunUntilCompletion(bool run_until_completion) {
162 run_until_completion_ = run_until_completion;
163 loop_ = std::make_unique<base::RunLoop>();
164 }
165
166 // Wait until the stream reaches completion.
WaitUntilCompletion()167 void WaitUntilCompletion() { loop_->Run(); }
168
169 // Starts or continues read data from |stream_| until there is no more
170 // byte can be read synchronously.
StartOrContinueReading()171 void StartOrContinueReading() {
172 int rv = ReadData();
173 while (rv > 0) {
174 rv = ReadData();
175 }
176 if (run_until_completion_ && rv == 0)
177 loop_->Quit();
178 }
179
180 // Calls ReadData on the |stream_| and updates internal states.
ReadData()181 int ReadData() {
182 int rv = stream_->ReadData(read_buf_.get(), read_buf_len_);
183 if (rv > 0) {
184 data_received_.append(read_buf_->data(), rv);
185 bytes_read_ += rv;
186 }
187 return rv;
188 }
189
GetProtocol() const190 NextProto GetProtocol() const { return stream_->GetProtocol(); }
191
GetTotalReceivedBytes() const192 int64_t GetTotalReceivedBytes() const {
193 return stream_->GetTotalReceivedBytes();
194 }
195
GetTotalSentBytes() const196 int64_t GetTotalSentBytes() const {
197 return stream_->GetTotalSentBytes();
198 }
199
GetLoadTimingInfo(LoadTimingInfo * load_timing_info) const200 bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const {
201 return stream_->GetLoadTimingInfo(load_timing_info);
202 }
203
204 // Const getters for internal states.
data_received() const205 const std::string& data_received() const { return data_received_; }
bytes_read() const206 int bytes_read() const { return bytes_read_; }
error() const207 int error() const { return error_; }
response_headers() const208 const quiche::HttpHeaderBlock& response_headers() const {
209 return response_headers_;
210 }
trailers() const211 const quiche::HttpHeaderBlock& trailers() const { return trailers_; }
on_data_read_count() const212 int on_data_read_count() const { return on_data_read_count_; }
on_data_sent_count() const213 int on_data_sent_count() const { return on_data_sent_count_; }
on_failed_called() const214 bool on_failed_called() const { return on_failed_called_; }
215
216 // Sets whether the delegate should automatically start reading.
set_do_not_start_read(bool do_not_start_read)217 void set_do_not_start_read(bool do_not_start_read) {
218 do_not_start_read_ = do_not_start_read;
219 }
220
221 private:
222 std::unique_ptr<BidirectionalStreamSpdyImpl> stream_;
223 scoped_refptr<IOBuffer> read_buf_;
224 int read_buf_len_;
225 std::string data_received_;
226 std::unique_ptr<base::RunLoop> loop_;
227 quiche::HttpHeaderBlock response_headers_;
228 quiche::HttpHeaderBlock trailers_;
229 int error_ = OK;
230 int bytes_read_ = 0;
231 int on_data_read_count_ = 0;
232 int on_data_sent_count_ = 0;
233 bool do_not_start_read_ = false;
234 bool run_until_completion_ = false;
235 bool not_expect_callback_ = false;
236 bool on_failed_called_ = false;
237 };
238
239 } // namespace
240
241 class BidirectionalStreamSpdyImplTest : public testing::TestWithParam<bool>,
242 public WithTaskEnvironment {
243 public:
BidirectionalStreamSpdyImplTest()244 BidirectionalStreamSpdyImplTest()
245 : default_url_(kDefaultUrl),
246 host_port_pair_(HostPortPair::FromURL(default_url_)),
247 key_(host_port_pair_,
248 PRIVACY_MODE_DISABLED,
249 ProxyChain::Direct(),
250 SessionUsage::kDestination,
251 SocketTag(),
252 NetworkAnonymizationKey(),
253 SecureDnsPolicy::kAllow,
254 /*disable_cert_verification_network_fetches=*/false),
255 ssl_data_(SSLSocketDataProvider(ASYNC, OK)) {
256 ssl_data_.next_proto = kProtoHTTP2;
257 ssl_data_.ssl_info.cert =
258 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
259 }
260
IsBrokenConnectionDetectionEnabled() const261 bool IsBrokenConnectionDetectionEnabled() const {
262 if (!session_)
263 return false;
264
265 return session_->IsBrokenConnectionDetectionEnabled();
266 }
267
268 protected:
TearDown()269 void TearDown() override {
270 if (sequenced_data_) {
271 EXPECT_TRUE(sequenced_data_->AllReadDataConsumed());
272 EXPECT_TRUE(sequenced_data_->AllWriteDataConsumed());
273 }
274 }
275
276 // Initializes the session using SequencedSocketData.
InitSession(base::span<const MockRead> reads,base::span<const MockWrite> writes)277 void InitSession(base::span<const MockRead> reads,
278 base::span<const MockWrite> writes) {
279 ASSERT_TRUE(ssl_data_.ssl_info.cert.get());
280 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data_);
281 sequenced_data_ = std::make_unique<SequencedSocketData>(reads, writes);
282 session_deps_.socket_factory->AddSocketDataProvider(sequenced_data_.get());
283 session_deps_.net_log = NetLog::Get();
284 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
285 session_ =
286 CreateSpdySession(http_session_.get(), key_, net_log_with_source_);
287 }
288
289 NetLogWithSource net_log_with_source_{
290 NetLogWithSource::Make(NetLogSourceType::NONE)};
291 SpdyTestUtil spdy_util_;
292 SpdySessionDependencies session_deps_;
293 const GURL default_url_;
294 const HostPortPair host_port_pair_;
295 const SpdySessionKey key_;
296 std::unique_ptr<SequencedSocketData> sequenced_data_;
297 std::unique_ptr<HttpNetworkSession> http_session_;
298 base::WeakPtr<SpdySession> session_;
299
300 private:
301 SSLSocketDataProvider ssl_data_;
302 };
303
TEST_F(BidirectionalStreamSpdyImplTest,SimplePostRequest)304 TEST_F(BidirectionalStreamSpdyImplTest, SimplePostRequest) {
305 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
306 kDefaultUrl, 1, kBodyDataSize, LOW, nullptr, 0));
307 spdy::SpdySerializedFrame data_frame(spdy_util_.ConstructSpdyDataFrame(
308 1, std::string_view(kBodyData, kBodyDataSize), /*fin=*/true));
309 MockWrite writes[] = {
310 CreateMockWrite(req, 0), CreateMockWrite(data_frame, 3),
311 };
312 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
313 spdy::SpdySerializedFrame response_body_frame(
314 spdy_util_.ConstructSpdyDataFrame(1, /*fin=*/true));
315 MockRead reads[] = {
316 CreateMockRead(resp, 1),
317 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
318 CreateMockRead(response_body_frame, 4), MockRead(ASYNC, 0, 5),
319 };
320 InitSession(reads, writes);
321
322 BidirectionalStreamRequestInfo request_info;
323 request_info.method = "POST";
324 request_info.url = default_url_;
325 request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength,
326 base::NumberToString(kBodyDataSize));
327
328 auto read_buffer = base::MakeRefCounted<IOBufferWithSize>(kReadBufferSize);
329 auto delegate = std::make_unique<TestDelegateBase>(
330 session_, read_buffer.get(), kReadBufferSize);
331 delegate->SetRunUntilCompletion(true);
332 delegate->Start(&request_info, net_log_with_source_);
333 sequenced_data_->RunUntilPaused();
334
335 scoped_refptr<StringIOBuffer> write_buffer =
336 base::MakeRefCounted<StringIOBuffer>(
337 std::string(kBodyData, kBodyDataSize));
338 delegate->SendData(write_buffer.get(), write_buffer->size(), true);
339 sequenced_data_->Resume();
340 base::RunLoop().RunUntilIdle();
341 delegate->WaitUntilCompletion();
342 LoadTimingInfo load_timing_info;
343 EXPECT_TRUE(delegate->GetLoadTimingInfo(&load_timing_info));
344 TestLoadTimingNotReused(load_timing_info);
345
346 EXPECT_EQ(1, delegate->on_data_read_count());
347 EXPECT_EQ(1, delegate->on_data_sent_count());
348 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
349 EXPECT_EQ(CountWriteBytes(writes), delegate->GetTotalSentBytes());
350 EXPECT_EQ(CountReadBytes(reads), delegate->GetTotalReceivedBytes());
351 }
352
TEST_F(BidirectionalStreamSpdyImplTest,LoadTimingTwoRequests)353 TEST_F(BidirectionalStreamSpdyImplTest, LoadTimingTwoRequests) {
354 spdy::SpdySerializedFrame req(
355 spdy_util_.ConstructSpdyGet(nullptr, 0, /*stream_id=*/1, LOW));
356 spdy::SpdySerializedFrame req2(
357 spdy_util_.ConstructSpdyGet(nullptr, 0, /*stream_id=*/3, LOW));
358 MockWrite writes[] = {
359 CreateMockWrite(req, 0), CreateMockWrite(req2, 2),
360 };
361 spdy::SpdySerializedFrame resp(
362 spdy_util_.ConstructSpdyGetReply(nullptr, 0, /*stream_id=*/1));
363 spdy::SpdySerializedFrame resp2(
364 spdy_util_.ConstructSpdyGetReply(nullptr, 0, /*stream_id=*/3));
365 spdy::SpdySerializedFrame resp_body(
366 spdy_util_.ConstructSpdyDataFrame(/*stream_id=*/1, /*fin=*/true));
367 spdy::SpdySerializedFrame resp_body2(
368 spdy_util_.ConstructSpdyDataFrame(/*stream_id=*/3, /*fin=*/true));
369 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(resp_body, 3),
370 CreateMockRead(resp2, 4), CreateMockRead(resp_body2, 5),
371 MockRead(ASYNC, 0, 6)};
372 InitSession(reads, writes);
373
374 BidirectionalStreamRequestInfo request_info;
375 request_info.method = "GET";
376 request_info.url = default_url_;
377 request_info.end_stream_on_headers = true;
378
379 auto read_buffer = base::MakeRefCounted<IOBufferWithSize>(kReadBufferSize);
380 auto read_buffer2 = base::MakeRefCounted<IOBufferWithSize>(kReadBufferSize);
381 auto delegate = std::make_unique<TestDelegateBase>(
382 session_, read_buffer.get(), kReadBufferSize);
383 auto delegate2 = std::make_unique<TestDelegateBase>(
384 session_, read_buffer2.get(), kReadBufferSize);
385 delegate->SetRunUntilCompletion(true);
386 delegate2->SetRunUntilCompletion(true);
387 delegate->Start(&request_info, net_log_with_source_);
388 delegate2->Start(&request_info, net_log_with_source_);
389
390 base::RunLoop().RunUntilIdle();
391 delegate->WaitUntilCompletion();
392 delegate2->WaitUntilCompletion();
393 LoadTimingInfo load_timing_info;
394 EXPECT_TRUE(delegate->GetLoadTimingInfo(&load_timing_info));
395 TestLoadTimingNotReused(load_timing_info);
396 LoadTimingInfo load_timing_info2;
397 EXPECT_TRUE(delegate2->GetLoadTimingInfo(&load_timing_info2));
398 TestLoadTimingReused(load_timing_info2);
399 }
400
TEST_F(BidirectionalStreamSpdyImplTest,SendDataAfterStreamFailed)401 TEST_F(BidirectionalStreamSpdyImplTest, SendDataAfterStreamFailed) {
402 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
403 kDefaultUrl, 1, kBodyDataSize * 3, LOW, nullptr, 0));
404 spdy::SpdySerializedFrame rst(
405 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
406
407 MockWrite writes[] = {
408 CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
409 };
410
411 const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
412 spdy::SpdySerializedFrame resp(
413 spdy_util_.ConstructSpdyGetReply(kExtraHeaders, 1, 1));
414
415 MockRead reads[] = {
416 CreateMockRead(resp, 1), MockRead(ASYNC, 0, 3),
417 };
418
419 InitSession(reads, writes);
420
421 BidirectionalStreamRequestInfo request_info;
422 request_info.method = "POST";
423 request_info.url = default_url_;
424 request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength,
425 base::NumberToString(kBodyDataSize * 3));
426
427 auto read_buffer = base::MakeRefCounted<IOBufferWithSize>(kReadBufferSize);
428 auto delegate = std::make_unique<TestDelegateBase>(
429 session_, read_buffer.get(), kReadBufferSize);
430 delegate->SetRunUntilCompletion(true);
431 delegate->Start(&request_info, net_log_with_source_);
432 base::RunLoop().RunUntilIdle();
433
434 EXPECT_TRUE(delegate->on_failed_called());
435
436 // Try to send data after OnFailed(), should not get called back.
437 scoped_refptr<StringIOBuffer> buf =
438 base::MakeRefCounted<StringIOBuffer>("dummy");
439 delegate->SendData(buf.get(), buf->size(), false);
440 base::RunLoop().RunUntilIdle();
441
442 EXPECT_THAT(delegate->error(), IsError(ERR_HTTP2_PROTOCOL_ERROR));
443 EXPECT_EQ(0, delegate->on_data_read_count());
444 EXPECT_EQ(0, delegate->on_data_sent_count());
445 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
446 // BidirectionalStreamSpdyStreamJob does not count the bytes sent for |rst|
447 // because it is sent after SpdyStream::Delegate::OnClose is called.
448 EXPECT_EQ(CountWriteBytes(base::span(writes, 1u)),
449 delegate->GetTotalSentBytes());
450 EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
451 }
452
453 INSTANTIATE_TEST_SUITE_P(BidirectionalStreamSpdyImplTests,
454 BidirectionalStreamSpdyImplTest,
455 ::testing::Bool());
456
457 // Tests that when received RST_STREAM with NO_ERROR, BidirectionalStream does
458 // not crash when processing pending writes. See crbug.com/650438.
TEST_P(BidirectionalStreamSpdyImplTest,RstWithNoErrorBeforeSendIsComplete)459 TEST_P(BidirectionalStreamSpdyImplTest, RstWithNoErrorBeforeSendIsComplete) {
460 bool is_test_sendv = GetParam();
461 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
462 kDefaultUrl, 1, kBodyDataSize * 3, LOW, nullptr, 0));
463 MockWrite writes[] = {CreateMockWrite(req, 0)};
464
465 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
466 spdy::SpdySerializedFrame rst(
467 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_NO_ERROR));
468 MockRead reads[] = {CreateMockRead(resp, 1),
469 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
470 CreateMockRead(rst, 3), MockRead(ASYNC, 0, 4)};
471
472 InitSession(reads, writes);
473
474 BidirectionalStreamRequestInfo request_info;
475 request_info.method = "POST";
476 request_info.url = default_url_;
477 request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength,
478 base::NumberToString(kBodyDataSize * 3));
479
480 auto read_buffer = base::MakeRefCounted<IOBufferWithSize>(kReadBufferSize);
481 auto delegate = std::make_unique<TestDelegateBase>(
482 session_, read_buffer.get(), kReadBufferSize);
483 delegate->SetRunUntilCompletion(true);
484 delegate->Start(&request_info, net_log_with_source_);
485 sequenced_data_->RunUntilPaused();
486 // Make a write pending before receiving RST_STREAM.
487 scoped_refptr<StringIOBuffer> write_buffer =
488 base::MakeRefCounted<StringIOBuffer>(
489 std::string(kBodyData, kBodyDataSize));
490 delegate->SendData(write_buffer.get(), write_buffer->size(), false);
491 sequenced_data_->Resume();
492 base::RunLoop().RunUntilIdle();
493
494 // Make sure OnClose() without an error completes any pending write().
495 EXPECT_EQ(1, delegate->on_data_sent_count());
496 EXPECT_FALSE(delegate->on_failed_called());
497
498 if (is_test_sendv) {
499 std::vector<scoped_refptr<IOBuffer>> three_buffers = {
500 write_buffer.get(), write_buffer.get(), write_buffer.get()};
501 std::vector<int> three_lengths = {
502 write_buffer->size(), write_buffer->size(), write_buffer->size()};
503 delegate->SendvData(three_buffers, three_lengths, /*end_of_stream=*/true);
504 base::RunLoop().RunUntilIdle();
505 } else {
506 for (size_t j = 0; j < 3; j++) {
507 delegate->SendData(write_buffer.get(), write_buffer->size(),
508 /*end_of_stream=*/j == 2);
509 base::RunLoop().RunUntilIdle();
510 }
511 }
512 delegate->WaitUntilCompletion();
513 LoadTimingInfo load_timing_info;
514 EXPECT_TRUE(delegate->GetLoadTimingInfo(&load_timing_info));
515 TestLoadTimingNotReused(load_timing_info);
516
517 EXPECT_THAT(delegate->error(), IsError(OK));
518 EXPECT_EQ(1, delegate->on_data_read_count());
519 EXPECT_EQ(is_test_sendv ? 2 : 4, delegate->on_data_sent_count());
520 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
521 EXPECT_EQ(CountWriteBytes(base::span(writes, 1u)),
522 delegate->GetTotalSentBytes());
523 // Should not count RST stream.
524 EXPECT_EQ(CountReadBytes(base::span(reads).first(std::size(reads) - 2)),
525 delegate->GetTotalReceivedBytes());
526
527 // Now call SendData again should produce an error because end of stream
528 // flag has been written.
529 if (is_test_sendv) {
530 std::vector<scoped_refptr<IOBuffer>> buffer = {write_buffer.get()};
531 std::vector<int> buffer_size = {write_buffer->size()};
532 delegate->SendvData(buffer, buffer_size, true);
533 } else {
534 delegate->SendData(write_buffer.get(), write_buffer->size(), true);
535 }
536 base::RunLoop().RunUntilIdle();
537 EXPECT_THAT(delegate->error(), IsError(ERR_UNEXPECTED));
538 EXPECT_TRUE(delegate->on_failed_called());
539 EXPECT_EQ(is_test_sendv ? 2 : 4, delegate->on_data_sent_count());
540 }
541
TEST_F(BidirectionalStreamSpdyImplTest,RequestDetectBrokenConnection)542 TEST_F(BidirectionalStreamSpdyImplTest, RequestDetectBrokenConnection) {
543 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
544 kDefaultUrl, 1, kBodyDataSize, LOW, nullptr, 0));
545 spdy::SpdySerializedFrame data_frame(spdy_util_.ConstructSpdyDataFrame(
546 1, std::string_view(kBodyData, kBodyDataSize), /*fin=*/true));
547 MockWrite writes[] = {
548 CreateMockWrite(req, 0),
549 CreateMockWrite(data_frame, 3),
550 };
551 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
552 spdy::SpdySerializedFrame response_body_frame(
553 spdy_util_.ConstructSpdyDataFrame(1, /*fin=*/true));
554 MockRead reads[] = {
555 CreateMockRead(resp, 1),
556 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
557 CreateMockRead(response_body_frame, 4),
558 MockRead(ASYNC, 0, 5),
559 };
560 InitSession(reads, writes);
561 EXPECT_FALSE(IsBrokenConnectionDetectionEnabled());
562
563 BidirectionalStreamRequestInfo request_info;
564 request_info.method = "POST";
565 request_info.url = default_url_;
566 request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength,
567 base::NumberToString(kBodyDataSize));
568 request_info.detect_broken_connection = true;
569 request_info.heartbeat_interval = base::Seconds(1);
570
571 auto read_buffer = base::MakeRefCounted<IOBufferWithSize>(kReadBufferSize);
572 auto delegate = std::make_unique<TestDelegateBase>(
573 session_, read_buffer.get(), kReadBufferSize);
574 delegate->SetRunUntilCompletion(true);
575 delegate->Start(&request_info, net_log_with_source_);
576 sequenced_data_->RunUntilPaused();
577
578 // Since we set request_info.detect_broken_connection to true, this should be
579 // enabled for the bidi stream lifetime.
580 EXPECT_TRUE(IsBrokenConnectionDetectionEnabled());
581
582 scoped_refptr<StringIOBuffer> write_buffer =
583 base::MakeRefCounted<StringIOBuffer>(
584 std::string(kBodyData, kBodyDataSize));
585 delegate->SendData(write_buffer.get(), write_buffer->size(), true);
586 sequenced_data_->Resume();
587 base::RunLoop().RunUntilIdle();
588 delegate->WaitUntilCompletion();
589 LoadTimingInfo load_timing_info;
590 EXPECT_TRUE(delegate->GetLoadTimingInfo(&load_timing_info));
591 TestLoadTimingNotReused(load_timing_info);
592
593 EXPECT_EQ(1, delegate->on_data_read_count());
594 EXPECT_EQ(1, delegate->on_data_sent_count());
595 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
596 EXPECT_EQ(CountWriteBytes(writes), delegate->GetTotalSentBytes());
597 EXPECT_EQ(CountReadBytes(reads), delegate->GetTotalReceivedBytes());
598
599 delegate.reset();
600 // Once the bidi stream has been destroyed this should go back to being
601 // disabled.
602 EXPECT_FALSE(IsBrokenConnectionDetectionEnabled());
603 }
604
605 } // namespace net
606