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