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