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