| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/spdy/bidirectional_stream_spdy_impl.h" | 5 #include "net/spdy/bidirectional_stream_spdy_impl.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/location.h" | 8 #include "base/location.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/time/time.h" | 10 #include "base/time/time.h" |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 } // namespace | 27 } // namespace |
| 28 | 28 |
| 29 BidirectionalStreamSpdyImpl::BidirectionalStreamSpdyImpl( | 29 BidirectionalStreamSpdyImpl::BidirectionalStreamSpdyImpl( |
| 30 const base::WeakPtr<SpdySession>& spdy_session) | 30 const base::WeakPtr<SpdySession>& spdy_session) |
| 31 : spdy_session_(spdy_session), | 31 : spdy_session_(spdy_session), |
| 32 request_info_(nullptr), | 32 request_info_(nullptr), |
| 33 delegate_(nullptr), | 33 delegate_(nullptr), |
| 34 negotiated_protocol_(kProtoUnknown), | 34 negotiated_protocol_(kProtoUnknown), |
| 35 more_read_data_pending_(false), | 35 more_read_data_pending_(false), |
| 36 read_buffer_len_(0), | 36 read_buffer_len_(0), |
| 37 written_end_of_stream_(false), |
| 38 write_pending_(false), |
| 37 stream_closed_(false), | 39 stream_closed_(false), |
| 38 closed_stream_status_(ERR_FAILED), | 40 closed_stream_status_(ERR_FAILED), |
| 39 closed_stream_received_bytes_(0), | 41 closed_stream_received_bytes_(0), |
| 40 closed_stream_sent_bytes_(0), | 42 closed_stream_sent_bytes_(0), |
| 41 closed_has_load_timing_info_(false), | 43 closed_has_load_timing_info_(false), |
| 42 weak_factory_(this) {} | 44 weak_factory_(this) {} |
| 43 | 45 |
| 44 BidirectionalStreamSpdyImpl::~BidirectionalStreamSpdyImpl() { | 46 BidirectionalStreamSpdyImpl::~BidirectionalStreamSpdyImpl() { |
| 45 // Sends a RST to the remote if the stream is destroyed before it completes. | 47 // Sends a RST to the remote if the stream is destroyed before it completes. |
| 46 ResetStream(); | 48 ResetStream(); |
| 49 DCHECK(!write_pending_); |
| 47 } | 50 } |
| 48 | 51 |
| 49 void BidirectionalStreamSpdyImpl::Start( | 52 void BidirectionalStreamSpdyImpl::Start( |
| 50 const BidirectionalStreamRequestInfo* request_info, | 53 const BidirectionalStreamRequestInfo* request_info, |
| 51 const NetLogWithSource& net_log, | 54 const NetLogWithSource& net_log, |
| 52 bool /*send_request_headers_automatically*/, | 55 bool /*send_request_headers_automatically*/, |
| 53 BidirectionalStreamImpl::Delegate* delegate, | 56 BidirectionalStreamImpl::Delegate* delegate, |
| 54 std::unique_ptr<base::Timer> timer) { | 57 std::unique_ptr<base::Timer> timer) { |
| 55 DCHECK(!stream_); | 58 DCHECK(!stream_); |
| 56 DCHECK(timer); | 59 DCHECK(timer); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 // called upon completion. | 103 // called upon completion. |
| 101 read_buffer_ = buf; | 104 read_buffer_ = buf; |
| 102 read_buffer_len_ = buf_len; | 105 read_buffer_len_ = buf_len; |
| 103 return ERR_IO_PENDING; | 106 return ERR_IO_PENDING; |
| 104 } | 107 } |
| 105 | 108 |
| 106 void BidirectionalStreamSpdyImpl::SendData(const scoped_refptr<IOBuffer>& data, | 109 void BidirectionalStreamSpdyImpl::SendData(const scoped_refptr<IOBuffer>& data, |
| 107 int length, | 110 int length, |
| 108 bool end_stream) { | 111 bool end_stream) { |
| 109 DCHECK(length > 0 || (length == 0 && end_stream)); | 112 DCHECK(length > 0 || (length == 0 && end_stream)); |
| 113 DCHECK(!write_pending_); |
| 110 | 114 |
| 111 if (!stream_) { | 115 if (!written_end_of_stream_) { |
| 112 LOG(ERROR) << "Trying to send data after stream has been destroyed."; | 116 LOG(ERROR) << "Writing after end of stream is written."; |
| 113 base::ThreadTaskRunnerHandle::Get()->PostTask( | 117 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 114 FROM_HERE, base::Bind(&BidirectionalStreamSpdyImpl::NotifyError, | 118 FROM_HERE, base::Bind(&BidirectionalStreamSpdyImpl::NotifyError, |
| 115 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED)); | 119 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED)); |
| 116 return; | 120 return; |
| 117 } | 121 } |
| 118 | 122 |
| 123 write_pending_ = true; |
| 124 written_end_of_stream_ = end_stream; |
| 125 if (MaybeHandleStreamClosedInSendData()) |
| 126 return; |
| 127 |
| 119 DCHECK(!stream_closed_); | 128 DCHECK(!stream_closed_); |
| 120 stream_->SendData(data.get(), length, | 129 stream_->SendData(data.get(), length, |
| 121 end_stream ? NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND); | 130 end_stream ? NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND); |
| 122 } | 131 } |
| 123 | 132 |
| 124 void BidirectionalStreamSpdyImpl::SendvData( | 133 void BidirectionalStreamSpdyImpl::SendvData( |
| 125 const std::vector<scoped_refptr<IOBuffer>>& buffers, | 134 const std::vector<scoped_refptr<IOBuffer>>& buffers, |
| 126 const std::vector<int>& lengths, | 135 const std::vector<int>& lengths, |
| 127 bool end_stream) { | 136 bool end_stream) { |
| 128 DCHECK_EQ(buffers.size(), lengths.size()); | 137 DCHECK_EQ(buffers.size(), lengths.size()); |
| 138 DCHECK(!write_pending_); |
| 129 | 139 |
| 130 if (!stream_) { | 140 if (!written_end_of_stream_) { |
| 131 LOG(ERROR) << "Trying to send data after stream has been destroyed."; | 141 LOG(ERROR) << "Writing after end of stream is written."; |
| 132 base::ThreadTaskRunnerHandle::Get()->PostTask( | 142 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 133 FROM_HERE, base::Bind(&BidirectionalStreamSpdyImpl::NotifyError, | 143 FROM_HERE, base::Bind(&BidirectionalStreamSpdyImpl::NotifyError, |
| 134 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED)); | 144 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED)); |
| 135 return; | 145 return; |
| 136 } | 146 } |
| 137 | 147 |
| 148 write_pending_ = true; |
| 149 written_end_of_stream_ = end_stream; |
| 150 if (MaybeHandleStreamClosedInSendData()) |
| 151 return; |
| 152 |
| 138 DCHECK(!stream_closed_); | 153 DCHECK(!stream_closed_); |
| 139 int total_len = 0; | 154 int total_len = 0; |
| 140 for (int len : lengths) { | 155 for (int len : lengths) { |
| 141 total_len += len; | 156 total_len += len; |
| 142 } | 157 } |
| 143 | 158 |
| 144 pending_combined_buffer_ = new net::IOBuffer(total_len); | 159 pending_combined_buffer_ = new net::IOBuffer(total_len); |
| 145 int len = 0; | 160 int len = 0; |
| 146 // TODO(xunjieli): Get rid of extra copy. Coalesce headers and data frames. | 161 // TODO(xunjieli): Get rid of extra copy. Coalesce headers and data frames. |
| 147 for (size_t i = 0; i < buffers.size(); ++i) { | 162 for (size_t i = 0; i < buffers.size(); ++i) { |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 | 276 |
| 262 if (status != OK) { | 277 if (status != OK) { |
| 263 NotifyError(status); | 278 NotifyError(status); |
| 264 return; | 279 return; |
| 265 } | 280 } |
| 266 ResetStream(); | 281 ResetStream(); |
| 267 // Complete any remaining read, as all data has been buffered. | 282 // Complete any remaining read, as all data has been buffered. |
| 268 // If user has not called ReadData (i.e |read_buffer_| is nullptr), this will | 283 // If user has not called ReadData (i.e |read_buffer_| is nullptr), this will |
| 269 // do nothing. | 284 // do nothing. |
| 270 timer_->Stop(); | 285 timer_->Stop(); |
| 286 |
| 287 // |this| might get destroyed after calling into |delegate_| in |
| 288 // DoBufferedRead(). |
| 289 auto weak_this = weak_factory_.GetWeakPtr(); |
| 271 DoBufferedRead(); | 290 DoBufferedRead(); |
| 291 if (weak_this.get() && write_pending_) |
| 292 NotifyDataSent(); |
| 272 } | 293 } |
| 273 | 294 |
| 274 int BidirectionalStreamSpdyImpl::SendRequestHeadersHelper() { | 295 int BidirectionalStreamSpdyImpl::SendRequestHeadersHelper() { |
| 275 SpdyHeaderBlock headers; | 296 SpdyHeaderBlock headers; |
| 276 HttpRequestInfo http_request_info; | 297 HttpRequestInfo http_request_info; |
| 277 http_request_info.url = request_info_->url; | 298 http_request_info.url = request_info_->url; |
| 278 http_request_info.method = request_info_->method; | 299 http_request_info.method = request_info_->method; |
| 279 http_request_info.extra_headers = request_info_->extra_headers; | 300 http_request_info.extra_headers = request_info_->extra_headers; |
| 280 | 301 |
| 281 CreateSpdyHeadersFromHttpRequest( | 302 CreateSpdyHeadersFromHttpRequest( |
| 282 http_request_info, http_request_info.extra_headers, true, &headers); | 303 http_request_info, http_request_info.extra_headers, true, &headers); |
| 304 written_end_of_stream_ = request_info_->end_stream_on_headers; |
| 283 return stream_->SendRequestHeaders(std::move(headers), | 305 return stream_->SendRequestHeaders(std::move(headers), |
| 284 request_info_->end_stream_on_headers | 306 request_info_->end_stream_on_headers |
| 285 ? NO_MORE_DATA_TO_SEND | 307 ? NO_MORE_DATA_TO_SEND |
| 286 : MORE_DATA_TO_SEND); | 308 : MORE_DATA_TO_SEND); |
| 287 } | 309 } |
| 288 | 310 |
| 289 void BidirectionalStreamSpdyImpl::OnStreamInitialized(int rv) { | 311 void BidirectionalStreamSpdyImpl::OnStreamInitialized(int rv) { |
| 290 DCHECK_NE(ERR_IO_PENDING, rv); | 312 DCHECK_NE(ERR_IO_PENDING, rv); |
| 291 if (rv == OK) { | 313 if (rv == OK) { |
| 292 stream_ = stream_request_.ReleaseStream(); | 314 stream_ = stream_request_.ReleaseStream(); |
| 293 stream_->SetDelegate(this); | 315 stream_->SetDelegate(this); |
| 294 rv = SendRequestHeadersHelper(); | 316 rv = SendRequestHeadersHelper(); |
| 295 if (rv == OK) { | 317 if (rv == OK) { |
| 296 OnRequestHeadersSent(); | 318 OnRequestHeadersSent(); |
| 297 return; | 319 return; |
| 298 } else if (rv == ERR_IO_PENDING) { | 320 } else if (rv == ERR_IO_PENDING) { |
| 299 return; | 321 return; |
| 300 } | 322 } |
| 301 } | 323 } |
| 302 NotifyError(rv); | 324 NotifyError(rv); |
| 303 } | 325 } |
| 304 | 326 |
| 305 void BidirectionalStreamSpdyImpl::NotifyError(int rv) { | 327 void BidirectionalStreamSpdyImpl::NotifyError(int rv) { |
| 306 ResetStream(); | 328 ResetStream(); |
| 329 write_pending_ = false; |
| 307 if (delegate_) { | 330 if (delegate_) { |
| 308 BidirectionalStreamImpl::Delegate* delegate = delegate_; | 331 BidirectionalStreamImpl::Delegate* delegate = delegate_; |
| 309 delegate_ = nullptr; | 332 delegate_ = nullptr; |
| 310 // Cancel any pending callback. | 333 // Cancel any pending callback. |
| 311 weak_factory_.InvalidateWeakPtrs(); | 334 weak_factory_.InvalidateWeakPtrs(); |
| 312 delegate->OnFailed(rv); | 335 delegate->OnFailed(rv); |
| 313 // |this| can be null when returned from delegate. | 336 // |this| can be null when returned from delegate. |
| 314 } | 337 } |
| 315 } | 338 } |
| 316 | 339 |
| 340 void BidirectionalStreamSpdyImpl::NotifyDataSent() { |
| 341 DCHECK(write_pending_); |
| 342 |
| 343 write_pending_ = false; |
| 344 if (delegate_) |
| 345 delegate_->OnDataSent(); |
| 346 } |
| 347 |
| 317 void BidirectionalStreamSpdyImpl::ResetStream() { | 348 void BidirectionalStreamSpdyImpl::ResetStream() { |
| 318 if (!stream_) | 349 if (!stream_) |
| 319 return; | 350 return; |
| 320 if (!stream_->IsClosed()) { | 351 if (!stream_->IsClosed()) { |
| 321 // This sends a RST to the remote. | 352 // This sends a RST to the remote. |
| 322 stream_->DetachDelegate(); | 353 stream_->DetachDelegate(); |
| 323 DCHECK(!stream_); | 354 DCHECK(!stream_); |
| 324 } else { | 355 } else { |
| 325 // Stream is already closed, so it is not legal to call DetachDelegate. | 356 // Stream is already closed, so it is not legal to call DetachDelegate. |
| 326 stream_.reset(); | 357 stream_.reset(); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 366 } | 397 } |
| 367 | 398 |
| 368 bool BidirectionalStreamSpdyImpl::ShouldWaitForMoreBufferedData() const { | 399 bool BidirectionalStreamSpdyImpl::ShouldWaitForMoreBufferedData() const { |
| 369 if (stream_closed_) | 400 if (stream_closed_) |
| 370 return false; | 401 return false; |
| 371 DCHECK_GT(read_buffer_len_, 0); | 402 DCHECK_GT(read_buffer_len_, 0); |
| 372 return read_data_queue_.GetTotalSize() < | 403 return read_data_queue_.GetTotalSize() < |
| 373 static_cast<size_t>(read_buffer_len_); | 404 static_cast<size_t>(read_buffer_len_); |
| 374 } | 405 } |
| 375 | 406 |
| 407 bool BidirectionalStreamSpdyImpl::MaybeHandleStreamClosedInSendData() { |
| 408 if (stream_) |
| 409 return false; |
| 410 // If |stream_| is closed without an error before client half closes, |
| 411 // blackhole any pending write data. crbug.com/650438. |
| 412 if (stream_closed_ && closed_stream_status_ == OK) { |
| 413 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 414 FROM_HERE, base::Bind(&BidirectionalStreamSpdyImpl::NotifyDataSent, |
| 415 weak_factory_.GetWeakPtr())); |
| 416 return true; |
| 417 } |
| 418 LOG(ERROR) << "Trying to send data after stream has been destroyed."; |
| 419 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 420 FROM_HERE, base::Bind(&BidirectionalStreamSpdyImpl::NotifyError, |
| 421 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED)); |
| 422 return true; |
| 423 } |
| 424 |
| 376 } // namespace net | 425 } // namespace net |
| OLD | NEW |