• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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