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