| 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 |