OLD | NEW |
| (Empty) |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
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 <memory> | |
8 | |
9 #include "base/macros.h" | |
10 #include "base/memory/ptr_util.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 "net/base/load_timing_info.h" | |
16 #include "net/base/load_timing_info_test_util.h" | |
17 #include "net/base/net_errors.h" | |
18 #include "net/http/http_request_info.h" | |
19 #include "net/http/http_response_headers.h" | |
20 #include "net/http/http_response_info.h" | |
21 #include "net/log/test_net_log.h" | |
22 #include "net/socket/socket_test_util.h" | |
23 #include "net/spdy/platform/api/spdy_string.h" | |
24 #include "net/spdy/spdy_session.h" | |
25 #include "net/spdy/spdy_test_util_common.h" | |
26 #include "net/test/cert_test_util.h" | |
27 #include "net/test/gtest_util.h" | |
28 #include "net/test/test_data_directory.h" | |
29 #include "testing/gmock/include/gmock/gmock.h" | |
30 #include "testing/gtest/include/gtest/gtest.h" | |
31 | |
32 using net::test::IsError; | |
33 using net::test::IsOk; | |
34 | |
35 namespace net { | |
36 | |
37 namespace { | |
38 | |
39 const char kBodyData[] = "Body data"; | |
40 const size_t kBodyDataSize = arraysize(kBodyData); | |
41 // Size of the buffer to be allocated for each read. | |
42 const size_t kReadBufferSize = 4096; | |
43 | |
44 // Tests the load timing of a stream that's connected and is not the first | |
45 // request sent on a connection. | |
46 void TestLoadTimingReused(const LoadTimingInfo& load_timing_info) { | |
47 EXPECT_TRUE(load_timing_info.socket_reused); | |
48 EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id); | |
49 | |
50 ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing); | |
51 ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info); | |
52 } | |
53 | |
54 // Tests the load timing of a stream that's connected and using a fresh | |
55 // connection. | |
56 void TestLoadTimingNotReused(const LoadTimingInfo& load_timing_info) { | |
57 EXPECT_FALSE(load_timing_info.socket_reused); | |
58 EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id); | |
59 | |
60 ExpectConnectTimingHasTimes( | |
61 load_timing_info.connect_timing, | |
62 CONNECT_TIMING_HAS_SSL_TIMES | CONNECT_TIMING_HAS_DNS_TIMES); | |
63 ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info); | |
64 } | |
65 | |
66 class TestDelegateBase : public BidirectionalStreamImpl::Delegate { | |
67 public: | |
68 TestDelegateBase(base::WeakPtr<SpdySession> session, | |
69 IOBuffer* read_buf, | |
70 int read_buf_len) | |
71 : stream_(new BidirectionalStreamSpdyImpl(session, NetLogSource())), | |
72 read_buf_(read_buf), | |
73 read_buf_len_(read_buf_len), | |
74 loop_(nullptr), | |
75 error_(OK), | |
76 bytes_read_(0), | |
77 on_data_read_count_(0), | |
78 on_data_sent_count_(0), | |
79 do_not_start_read_(false), | |
80 run_until_completion_(false), | |
81 not_expect_callback_(false), | |
82 on_failed_called_(false) {} | |
83 | |
84 ~TestDelegateBase() override {} | |
85 | |
86 void OnStreamReady(bool request_headers_sent) override { | |
87 CHECK(!on_failed_called_); | |
88 } | |
89 | |
90 void OnHeadersReceived(const SpdyHeaderBlock& 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 | |
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 | |
109 void OnDataSent() override { | |
110 CHECK(!on_failed_called_); | |
111 CHECK(!not_expect_callback_); | |
112 on_data_sent_count_++; | |
113 } | |
114 | |
115 void OnTrailersReceived(const SpdyHeaderBlock& trailers) override { | |
116 CHECK(!on_failed_called_); | |
117 trailers_ = trailers.Clone(); | |
118 if (run_until_completion_) | |
119 loop_->Quit(); | |
120 } | |
121 | |
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 | |
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 base::MakeUnique<base::Timer>(false, false)); | |
137 not_expect_callback_ = false; | |
138 } | |
139 | |
140 void SendData(IOBuffer* data, int length, bool end_of_stream) { | |
141 not_expect_callback_ = true; | |
142 stream_->SendData(data, length, end_of_stream); | |
143 not_expect_callback_ = false; | |
144 } | |
145 | |
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. | |
155 void SetRunUntilCompletion(bool run_until_completion) { | |
156 run_until_completion_ = run_until_completion; | |
157 loop_.reset(new base::RunLoop); | |
158 } | |
159 | |
160 // Wait until the stream reaches completion. | |
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. | |
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. | |
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 | |
184 NextProto GetProtocol() const { return stream_->GetProtocol(); } | |
185 | |
186 int64_t GetTotalReceivedBytes() const { | |
187 return stream_->GetTotalReceivedBytes(); | |
188 } | |
189 | |
190 int64_t GetTotalSentBytes() const { | |
191 return stream_->GetTotalSentBytes(); | |
192 } | |
193 | |
194 bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const { | |
195 return stream_->GetLoadTimingInfo(load_timing_info); | |
196 } | |
197 | |
198 // Const getters for internal states. | |
199 const SpdyString& data_received() const { return data_received_; } | |
200 int bytes_read() const { return bytes_read_; } | |
201 int error() const { return error_; } | |
202 const SpdyHeaderBlock& response_headers() const { return response_headers_; } | |
203 const SpdyHeaderBlock& trailers() const { return trailers_; } | |
204 int on_data_read_count() const { return on_data_read_count_; } | |
205 int on_data_sent_count() const { return on_data_sent_count_; } | |
206 bool on_failed_called() const { return on_failed_called_; } | |
207 | |
208 // Sets whether the delegate should automatically start reading. | |
209 void set_do_not_start_read(bool do_not_start_read) { | |
210 do_not_start_read_ = do_not_start_read; | |
211 } | |
212 | |
213 private: | |
214 std::unique_ptr<BidirectionalStreamSpdyImpl> stream_; | |
215 scoped_refptr<IOBuffer> read_buf_; | |
216 int read_buf_len_; | |
217 SpdyString data_received_; | |
218 std::unique_ptr<base::RunLoop> loop_; | |
219 SpdyHeaderBlock response_headers_; | |
220 SpdyHeaderBlock trailers_; | |
221 int error_; | |
222 int bytes_read_; | |
223 int on_data_read_count_; | |
224 int on_data_sent_count_; | |
225 bool do_not_start_read_; | |
226 bool run_until_completion_; | |
227 bool not_expect_callback_; | |
228 bool on_failed_called_; | |
229 | |
230 DISALLOW_COPY_AND_ASSIGN(TestDelegateBase); | |
231 }; | |
232 | |
233 } // namespace | |
234 | |
235 class BidirectionalStreamSpdyImplTest : public testing::TestWithParam<bool> { | |
236 public: | |
237 BidirectionalStreamSpdyImplTest() | |
238 : default_url_(kDefaultUrl), | |
239 host_port_pair_(HostPortPair::FromURL(default_url_)), | |
240 key_(host_port_pair_, ProxyServer::Direct(), PRIVACY_MODE_DISABLED), | |
241 ssl_data_(SSLSocketDataProvider(ASYNC, OK)) { | |
242 ssl_data_.next_proto = kProtoHTTP2; | |
243 ssl_data_.cert = ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"); | |
244 } | |
245 | |
246 protected: | |
247 void TearDown() override { | |
248 if (sequenced_data_) { | |
249 EXPECT_TRUE(sequenced_data_->AllReadDataConsumed()); | |
250 EXPECT_TRUE(sequenced_data_->AllWriteDataConsumed()); | |
251 } | |
252 } | |
253 | |
254 // Initializes the session using SequencedSocketData. | |
255 void InitSession(MockRead* reads, | |
256 size_t reads_count, | |
257 MockWrite* writes, | |
258 size_t writes_count) { | |
259 ASSERT_TRUE(ssl_data_.cert.get()); | |
260 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data_); | |
261 sequenced_data_.reset( | |
262 new SequencedSocketData(reads, reads_count, writes, writes_count)); | |
263 session_deps_.socket_factory->AddSocketDataProvider(sequenced_data_.get()); | |
264 session_deps_.net_log = net_log_.bound().net_log(); | |
265 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_); | |
266 session_ = | |
267 CreateSecureSpdySession(http_session_.get(), key_, net_log_.bound()); | |
268 } | |
269 | |
270 BoundTestNetLog net_log_; | |
271 SpdyTestUtil spdy_util_; | |
272 SpdySessionDependencies session_deps_; | |
273 const GURL default_url_; | |
274 const HostPortPair host_port_pair_; | |
275 const SpdySessionKey key_; | |
276 std::unique_ptr<SequencedSocketData> sequenced_data_; | |
277 std::unique_ptr<HttpNetworkSession> http_session_; | |
278 base::WeakPtr<SpdySession> session_; | |
279 | |
280 private: | |
281 SSLSocketDataProvider ssl_data_; | |
282 }; | |
283 | |
284 TEST_F(BidirectionalStreamSpdyImplTest, SimplePostRequest) { | |
285 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
286 kDefaultUrl, 1, kBodyDataSize, LOW, nullptr, 0)); | |
287 SpdySerializedFrame data_frame(spdy_util_.ConstructSpdyDataFrame( | |
288 1, kBodyData, kBodyDataSize, /*fin=*/true)); | |
289 MockWrite writes[] = { | |
290 CreateMockWrite(req, 0), CreateMockWrite(data_frame, 3), | |
291 }; | |
292 SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0)); | |
293 SpdySerializedFrame response_body_frame( | |
294 spdy_util_.ConstructSpdyDataFrame(1, /*fin=*/true)); | |
295 MockRead reads[] = { | |
296 CreateMockRead(resp, 1), | |
297 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause. | |
298 CreateMockRead(response_body_frame, 4), MockRead(ASYNC, 0, 5), | |
299 }; | |
300 InitSession(reads, arraysize(reads), writes, arraysize(writes)); | |
301 | |
302 BidirectionalStreamRequestInfo request_info; | |
303 request_info.method = "POST"; | |
304 request_info.url = default_url_; | |
305 request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength, | |
306 base::SizeTToString(kBodyDataSize)); | |
307 | |
308 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); | |
309 std::unique_ptr<TestDelegateBase> delegate( | |
310 new TestDelegateBase(session_, read_buffer.get(), kReadBufferSize)); | |
311 delegate->SetRunUntilCompletion(true); | |
312 delegate->Start(&request_info, net_log_.bound()); | |
313 sequenced_data_->RunUntilPaused(); | |
314 | |
315 scoped_refptr<StringIOBuffer> write_buffer( | |
316 new StringIOBuffer(SpdyString(kBodyData, kBodyDataSize))); | |
317 delegate->SendData(write_buffer.get(), write_buffer->size(), true); | |
318 sequenced_data_->Resume(); | |
319 base::RunLoop().RunUntilIdle(); | |
320 delegate->WaitUntilCompletion(); | |
321 LoadTimingInfo load_timing_info; | |
322 EXPECT_TRUE(delegate->GetLoadTimingInfo(&load_timing_info)); | |
323 TestLoadTimingNotReused(load_timing_info); | |
324 | |
325 EXPECT_EQ(1, delegate->on_data_read_count()); | |
326 EXPECT_EQ(1, delegate->on_data_sent_count()); | |
327 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol()); | |
328 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), | |
329 delegate->GetTotalSentBytes()); | |
330 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)), | |
331 delegate->GetTotalReceivedBytes()); | |
332 } | |
333 | |
334 TEST_F(BidirectionalStreamSpdyImplTest, LoadTimingTwoRequests) { | |
335 SpdySerializedFrame req( | |
336 spdy_util_.ConstructSpdyGet(nullptr, 0, /*stream_id=*/1, LOW, true)); | |
337 SpdySerializedFrame req2( | |
338 spdy_util_.ConstructSpdyGet(nullptr, 0, /*stream_id=*/3, LOW, true)); | |
339 MockWrite writes[] = { | |
340 CreateMockWrite(req, 0), CreateMockWrite(req2, 2), | |
341 }; | |
342 SpdySerializedFrame resp( | |
343 spdy_util_.ConstructSpdyGetReply(nullptr, 0, /*stream_id=*/1)); | |
344 SpdySerializedFrame resp2( | |
345 spdy_util_.ConstructSpdyGetReply(nullptr, 0, /*stream_id=*/3)); | |
346 SpdySerializedFrame resp_body( | |
347 spdy_util_.ConstructSpdyDataFrame(/*stream_id=*/1, /*fin=*/true)); | |
348 SpdySerializedFrame resp_body2( | |
349 spdy_util_.ConstructSpdyDataFrame(/*stream_id=*/3, /*fin=*/true)); | |
350 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(resp_body, 3), | |
351 CreateMockRead(resp2, 4), CreateMockRead(resp_body2, 5), | |
352 MockRead(ASYNC, 0, 6)}; | |
353 InitSession(reads, arraysize(reads), writes, arraysize(writes)); | |
354 | |
355 BidirectionalStreamRequestInfo request_info; | |
356 request_info.method = "GET"; | |
357 request_info.url = default_url_; | |
358 request_info.end_stream_on_headers = true; | |
359 | |
360 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); | |
361 scoped_refptr<IOBuffer> read_buffer2(new IOBuffer(kReadBufferSize)); | |
362 std::unique_ptr<TestDelegateBase> delegate( | |
363 new TestDelegateBase(session_, read_buffer.get(), kReadBufferSize)); | |
364 std::unique_ptr<TestDelegateBase> delegate2( | |
365 new TestDelegateBase(session_, read_buffer2.get(), kReadBufferSize)); | |
366 delegate->SetRunUntilCompletion(true); | |
367 delegate2->SetRunUntilCompletion(true); | |
368 delegate->Start(&request_info, net_log_.bound()); | |
369 delegate2->Start(&request_info, net_log_.bound()); | |
370 | |
371 base::RunLoop().RunUntilIdle(); | |
372 delegate->WaitUntilCompletion(); | |
373 delegate2->WaitUntilCompletion(); | |
374 LoadTimingInfo load_timing_info; | |
375 EXPECT_TRUE(delegate->GetLoadTimingInfo(&load_timing_info)); | |
376 TestLoadTimingNotReused(load_timing_info); | |
377 LoadTimingInfo load_timing_info2; | |
378 EXPECT_TRUE(delegate2->GetLoadTimingInfo(&load_timing_info2)); | |
379 TestLoadTimingReused(load_timing_info2); | |
380 } | |
381 | |
382 TEST_F(BidirectionalStreamSpdyImplTest, SendDataAfterStreamFailed) { | |
383 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
384 kDefaultUrl, 1, kBodyDataSize * 3, LOW, nullptr, 0)); | |
385 SpdySerializedFrame rst( | |
386 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_PROTOCOL_ERROR)); | |
387 | |
388 MockWrite writes[] = { | |
389 CreateMockWrite(req, 0), CreateMockWrite(rst, 2), | |
390 }; | |
391 | |
392 const char* const kExtraHeaders[] = {"X-UpperCase", "yes"}; | |
393 SpdySerializedFrame resp( | |
394 spdy_util_.ConstructSpdyGetReply(kExtraHeaders, 1, 1)); | |
395 | |
396 MockRead reads[] = { | |
397 CreateMockRead(resp, 1), MockRead(ASYNC, 0, 3), | |
398 }; | |
399 | |
400 InitSession(reads, arraysize(reads), writes, arraysize(writes)); | |
401 | |
402 BidirectionalStreamRequestInfo request_info; | |
403 request_info.method = "POST"; | |
404 request_info.url = default_url_; | |
405 request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength, | |
406 base::SizeTToString(kBodyDataSize * 3)); | |
407 | |
408 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); | |
409 std::unique_ptr<TestDelegateBase> delegate( | |
410 new TestDelegateBase(session_, read_buffer.get(), kReadBufferSize)); | |
411 delegate->SetRunUntilCompletion(true); | |
412 delegate->Start(&request_info, net_log_.bound()); | |
413 base::RunLoop().RunUntilIdle(); | |
414 | |
415 EXPECT_TRUE(delegate->on_failed_called()); | |
416 | |
417 // Try to send data after OnFailed(), should not get called back. | |
418 scoped_refptr<StringIOBuffer> buf(new StringIOBuffer("dummy")); | |
419 delegate->SendData(buf.get(), buf->size(), false); | |
420 base::RunLoop().RunUntilIdle(); | |
421 | |
422 EXPECT_THAT(delegate->error(), IsError(ERR_SPDY_PROTOCOL_ERROR)); | |
423 EXPECT_EQ(0, delegate->on_data_read_count()); | |
424 EXPECT_EQ(0, delegate->on_data_sent_count()); | |
425 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol()); | |
426 // BidirectionalStreamSpdyStreamJob does not count the bytes sent for |rst| | |
427 // because it is sent after SpdyStream::Delegate::OnClose is called. | |
428 EXPECT_EQ(CountWriteBytes(writes, 1), delegate->GetTotalSentBytes()); | |
429 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)), | |
430 delegate->GetTotalReceivedBytes()); | |
431 } | |
432 | |
433 INSTANTIATE_TEST_CASE_P(BidirectionalStreamSpdyImplTests, | |
434 BidirectionalStreamSpdyImplTest, | |
435 ::testing::Bool()); | |
436 | |
437 // Tests that when received RST_STREAM with NO_ERROR, BidirectionalStream does | |
438 // not crash when processing pending writes. See crbug.com/650438. | |
439 TEST_P(BidirectionalStreamSpdyImplTest, RstWithNoErrorBeforeSendIsComplete) { | |
440 bool is_test_sendv = GetParam(); | |
441 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
442 kDefaultUrl, 1, kBodyDataSize * 3, LOW, nullptr, 0)); | |
443 MockWrite writes[] = {CreateMockWrite(req, 0)}; | |
444 | |
445 SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0)); | |
446 SpdySerializedFrame rst( | |
447 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_NO_ERROR)); | |
448 MockRead reads[] = {CreateMockRead(resp, 1), | |
449 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause. | |
450 CreateMockRead(rst, 3), MockRead(ASYNC, 0, 4)}; | |
451 | |
452 InitSession(reads, arraysize(reads), writes, arraysize(writes)); | |
453 | |
454 BidirectionalStreamRequestInfo request_info; | |
455 request_info.method = "POST"; | |
456 request_info.url = default_url_; | |
457 request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength, | |
458 base::SizeTToString(kBodyDataSize * 3)); | |
459 | |
460 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); | |
461 std::unique_ptr<TestDelegateBase> delegate( | |
462 new TestDelegateBase(session_, read_buffer.get(), kReadBufferSize)); | |
463 delegate->SetRunUntilCompletion(true); | |
464 delegate->Start(&request_info, net_log_.bound()); | |
465 sequenced_data_->RunUntilPaused(); | |
466 // Make a write pending before receiving RST_STREAM. | |
467 scoped_refptr<StringIOBuffer> write_buffer( | |
468 new StringIOBuffer(SpdyString(kBodyData, kBodyDataSize))); | |
469 delegate->SendData(write_buffer.get(), write_buffer->size(), false); | |
470 sequenced_data_->Resume(); | |
471 base::RunLoop().RunUntilIdle(); | |
472 | |
473 // Make sure OnClose() without an error completes any pending write(). | |
474 EXPECT_EQ(1, delegate->on_data_sent_count()); | |
475 EXPECT_FALSE(delegate->on_failed_called()); | |
476 | |
477 if (is_test_sendv) { | |
478 std::vector<scoped_refptr<IOBuffer>> three_buffers = { | |
479 write_buffer.get(), write_buffer.get(), write_buffer.get()}; | |
480 std::vector<int> three_lengths = { | |
481 write_buffer->size(), write_buffer->size(), write_buffer->size()}; | |
482 delegate->SendvData(three_buffers, three_lengths, /*end_of_stream=*/true); | |
483 base::RunLoop().RunUntilIdle(); | |
484 } else { | |
485 for (size_t j = 0; j < 3; j++) { | |
486 delegate->SendData(write_buffer.get(), write_buffer->size(), | |
487 /*end_of_stream=*/j == 2); | |
488 base::RunLoop().RunUntilIdle(); | |
489 } | |
490 } | |
491 delegate->WaitUntilCompletion(); | |
492 LoadTimingInfo load_timing_info; | |
493 EXPECT_TRUE(delegate->GetLoadTimingInfo(&load_timing_info)); | |
494 TestLoadTimingNotReused(load_timing_info); | |
495 | |
496 EXPECT_THAT(delegate->error(), IsError(OK)); | |
497 EXPECT_EQ(1, delegate->on_data_read_count()); | |
498 EXPECT_EQ(is_test_sendv ? 2 : 4, delegate->on_data_sent_count()); | |
499 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol()); | |
500 EXPECT_EQ(CountWriteBytes(writes, 1), delegate->GetTotalSentBytes()); | |
501 // Should not count RST stream. | |
502 EXPECT_EQ(CountReadBytes(reads, arraysize(reads) - 2), | |
503 delegate->GetTotalReceivedBytes()); | |
504 | |
505 // Now call SendData again should produce an error because end of stream | |
506 // flag has been written. | |
507 if (is_test_sendv) { | |
508 std::vector<scoped_refptr<IOBuffer>> buffer = {write_buffer.get()}; | |
509 std::vector<int> buffer_size = {write_buffer->size()}; | |
510 delegate->SendvData(buffer, buffer_size, true); | |
511 } else { | |
512 delegate->SendData(write_buffer.get(), write_buffer->size(), true); | |
513 } | |
514 base::RunLoop().RunUntilIdle(); | |
515 EXPECT_THAT(delegate->error(), IsError(ERR_UNEXPECTED)); | |
516 EXPECT_TRUE(delegate->on_failed_called()); | |
517 EXPECT_EQ(is_test_sendv ? 2 : 4, delegate->on_data_sent_count()); | |
518 } | |
519 | |
520 } // namespace net | |
OLD | NEW |