Chromium Code Reviews| 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 |
|
kapishnikov
2016/10/31 17:03:07
Should we add DCHECK(!written_end_of_stream_) here
xunjieli
2016/10/31 17:18:03
The newly added test will crash instead of having
| |
| 111 if (!stream_) { | 115 write_pending_ = true; |
| 112 LOG(ERROR) << "Trying to send data after stream has been destroyed."; | 116 if (MaybeHandleStreamClosedInSendData()) { |
| 113 base::ThreadTaskRunnerHandle::Get()->PostTask( | 117 written_end_of_stream_ = end_stream; |
| 114 FROM_HERE, base::Bind(&BidirectionalStreamSpdyImpl::NotifyError, | |
| 115 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED)); | |
| 116 return; | 118 return; |
| 117 } | 119 } |
| 118 | 120 |
| 119 DCHECK(!stream_closed_); | 121 DCHECK(!stream_closed_); |
| 122 written_end_of_stream_ = end_stream; | |
| 123 | |
| 120 stream_->SendData(data.get(), length, | 124 stream_->SendData(data.get(), length, |
| 121 end_stream ? NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND); | 125 end_stream ? NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND); |
| 122 } | 126 } |
| 123 | 127 |
| 124 void BidirectionalStreamSpdyImpl::SendvData( | 128 void BidirectionalStreamSpdyImpl::SendvData( |
| 125 const std::vector<scoped_refptr<IOBuffer>>& buffers, | 129 const std::vector<scoped_refptr<IOBuffer>>& buffers, |
| 126 const std::vector<int>& lengths, | 130 const std::vector<int>& lengths, |
| 127 bool end_stream) { | 131 bool end_stream) { |
| 128 DCHECK_EQ(buffers.size(), lengths.size()); | 132 DCHECK_EQ(buffers.size(), lengths.size()); |
| 133 DCHECK(!write_pending_); | |
| 129 | 134 |
|
kapishnikov
2016/10/31 17:03:07
Same DCHECK(!written_end_of_stream_) here
xunjieli
2016/10/31 17:18:02
Same as above. The newly added test will crash. We
| |
| 130 if (!stream_) { | 135 write_pending_ = true; |
| 131 LOG(ERROR) << "Trying to send data after stream has been destroyed."; | 136 if (MaybeHandleStreamClosedInSendData()) { |
| 132 base::ThreadTaskRunnerHandle::Get()->PostTask( | 137 written_end_of_stream_ = end_stream; |
| 133 FROM_HERE, base::Bind(&BidirectionalStreamSpdyImpl::NotifyError, | |
| 134 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED)); | |
| 135 return; | 138 return; |
| 136 } | 139 } |
| 137 | 140 |
| 138 DCHECK(!stream_closed_); | 141 DCHECK(!stream_closed_); |
| 142 written_end_of_stream_ = end_stream; | |
| 143 | |
| 139 int total_len = 0; | 144 int total_len = 0; |
| 140 for (int len : lengths) { | 145 for (int len : lengths) { |
| 141 total_len += len; | 146 total_len += len; |
| 142 } | 147 } |
| 143 | 148 |
| 144 pending_combined_buffer_ = new net::IOBuffer(total_len); | 149 pending_combined_buffer_ = new net::IOBuffer(total_len); |
| 145 int len = 0; | 150 int len = 0; |
| 146 // TODO(xunjieli): Get rid of extra copy. Coalesce headers and data frames. | 151 // TODO(xunjieli): Get rid of extra copy. Coalesce headers and data frames. |
| 147 for (size_t i = 0; i < buffers.size(); ++i) { | 152 for (size_t i = 0; i < buffers.size(); ++i) { |
| 148 memcpy(pending_combined_buffer_->data() + len, buffers[i]->data(), | 153 memcpy(pending_combined_buffer_->data() + len, buffers[i]->data(), |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 261 | 266 |
| 262 if (status != OK) { | 267 if (status != OK) { |
| 263 NotifyError(status); | 268 NotifyError(status); |
| 264 return; | 269 return; |
| 265 } | 270 } |
| 266 ResetStream(); | 271 ResetStream(); |
| 267 // Complete any remaining read, as all data has been buffered. | 272 // 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 | 273 // If user has not called ReadData (i.e |read_buffer_| is nullptr), this will |
| 269 // do nothing. | 274 // do nothing. |
| 270 timer_->Stop(); | 275 timer_->Stop(); |
| 276 | |
| 277 // |this| might get destroyed after calling into |delegate_| in | |
| 278 // DoBufferedRead(). | |
| 279 auto weak_this = weak_factory_.GetWeakPtr(); | |
| 271 DoBufferedRead(); | 280 DoBufferedRead(); |
| 281 if (weak_this.get() && write_pending_) | |
| 282 NotifyDataSent(); | |
| 272 } | 283 } |
| 273 | 284 |
| 274 int BidirectionalStreamSpdyImpl::SendRequestHeadersHelper() { | 285 int BidirectionalStreamSpdyImpl::SendRequestHeadersHelper() { |
| 275 SpdyHeaderBlock headers; | 286 SpdyHeaderBlock headers; |
| 276 HttpRequestInfo http_request_info; | 287 HttpRequestInfo http_request_info; |
| 277 http_request_info.url = request_info_->url; | 288 http_request_info.url = request_info_->url; |
| 278 http_request_info.method = request_info_->method; | 289 http_request_info.method = request_info_->method; |
| 279 http_request_info.extra_headers = request_info_->extra_headers; | 290 http_request_info.extra_headers = request_info_->extra_headers; |
| 280 | 291 |
| 281 CreateSpdyHeadersFromHttpRequest( | 292 CreateSpdyHeadersFromHttpRequest( |
| 282 http_request_info, http_request_info.extra_headers, true, &headers); | 293 http_request_info, http_request_info.extra_headers, true, &headers); |
| 294 written_end_of_stream_ = request_info_->end_stream_on_headers; | |
| 283 return stream_->SendRequestHeaders(std::move(headers), | 295 return stream_->SendRequestHeaders(std::move(headers), |
| 284 request_info_->end_stream_on_headers | 296 request_info_->end_stream_on_headers |
| 285 ? NO_MORE_DATA_TO_SEND | 297 ? NO_MORE_DATA_TO_SEND |
| 286 : MORE_DATA_TO_SEND); | 298 : MORE_DATA_TO_SEND); |
| 287 } | 299 } |
| 288 | 300 |
| 289 void BidirectionalStreamSpdyImpl::OnStreamInitialized(int rv) { | 301 void BidirectionalStreamSpdyImpl::OnStreamInitialized(int rv) { |
| 290 DCHECK_NE(ERR_IO_PENDING, rv); | 302 DCHECK_NE(ERR_IO_PENDING, rv); |
| 291 if (rv == OK) { | 303 if (rv == OK) { |
| 292 stream_ = stream_request_.ReleaseStream(); | 304 stream_ = stream_request_.ReleaseStream(); |
| 293 stream_->SetDelegate(this); | 305 stream_->SetDelegate(this); |
| 294 rv = SendRequestHeadersHelper(); | 306 rv = SendRequestHeadersHelper(); |
| 295 if (rv == OK) { | 307 if (rv == OK) { |
| 296 OnRequestHeadersSent(); | 308 OnRequestHeadersSent(); |
| 297 return; | 309 return; |
| 298 } else if (rv == ERR_IO_PENDING) { | 310 } else if (rv == ERR_IO_PENDING) { |
| 299 return; | 311 return; |
| 300 } | 312 } |
| 301 } | 313 } |
| 302 NotifyError(rv); | 314 NotifyError(rv); |
| 303 } | 315 } |
| 304 | 316 |
| 305 void BidirectionalStreamSpdyImpl::NotifyError(int rv) { | 317 void BidirectionalStreamSpdyImpl::NotifyError(int rv) { |
| 306 ResetStream(); | 318 ResetStream(); |
| 319 write_pending_ = false; | |
| 307 if (delegate_) { | 320 if (delegate_) { |
| 308 BidirectionalStreamImpl::Delegate* delegate = delegate_; | 321 BidirectionalStreamImpl::Delegate* delegate = delegate_; |
| 309 delegate_ = nullptr; | 322 delegate_ = nullptr; |
| 310 // Cancel any pending callback. | 323 // Cancel any pending callback. |
| 311 weak_factory_.InvalidateWeakPtrs(); | 324 weak_factory_.InvalidateWeakPtrs(); |
| 312 delegate->OnFailed(rv); | 325 delegate->OnFailed(rv); |
| 313 // |this| can be null when returned from delegate. | 326 // |this| can be null when returned from delegate. |
| 314 } | 327 } |
| 315 } | 328 } |
| 316 | 329 |
| 330 void BidirectionalStreamSpdyImpl::NotifyDataSent() { | |
| 331 DCHECK(write_pending_); | |
| 332 | |
| 333 write_pending_ = false; | |
| 334 if (delegate_) | |
| 335 delegate_->OnDataSent(); | |
| 336 } | |
| 337 | |
| 317 void BidirectionalStreamSpdyImpl::ResetStream() { | 338 void BidirectionalStreamSpdyImpl::ResetStream() { |
| 318 if (!stream_) | 339 if (!stream_) |
| 319 return; | 340 return; |
| 320 if (!stream_->IsClosed()) { | 341 if (!stream_->IsClosed()) { |
| 321 // This sends a RST to the remote. | 342 // This sends a RST to the remote. |
| 322 stream_->DetachDelegate(); | 343 stream_->DetachDelegate(); |
| 323 DCHECK(!stream_); | 344 DCHECK(!stream_); |
| 324 } else { | 345 } else { |
| 325 // Stream is already closed, so it is not legal to call DetachDelegate. | 346 // Stream is already closed, so it is not legal to call DetachDelegate. |
| 326 stream_.reset(); | 347 stream_.reset(); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 366 } | 387 } |
| 367 | 388 |
| 368 bool BidirectionalStreamSpdyImpl::ShouldWaitForMoreBufferedData() const { | 389 bool BidirectionalStreamSpdyImpl::ShouldWaitForMoreBufferedData() const { |
| 369 if (stream_closed_) | 390 if (stream_closed_) |
| 370 return false; | 391 return false; |
| 371 DCHECK_GT(read_buffer_len_, 0); | 392 DCHECK_GT(read_buffer_len_, 0); |
| 372 return read_data_queue_.GetTotalSize() < | 393 return read_data_queue_.GetTotalSize() < |
| 373 static_cast<size_t>(read_buffer_len_); | 394 static_cast<size_t>(read_buffer_len_); |
| 374 } | 395 } |
| 375 | 396 |
| 397 bool BidirectionalStreamSpdyImpl::MaybeHandleStreamClosedInSendData() { | |
| 398 if (stream_) | |
| 399 return false; | |
| 400 // If |stream_| is closed without an error before client half closes, | |
| 401 // blackhole any pending write data. crbug.com/650438. | |
| 402 if (!written_end_of_stream_ && stream_closed_ && | |
|
kapishnikov
2016/10/31 17:03:07
To make the code easier to understand, I think we
xunjieli
2016/10/31 17:18:02
Done.
| |
| 403 closed_stream_status_ == OK) { | |
| 404 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 405 FROM_HERE, base::Bind(&BidirectionalStreamSpdyImpl::NotifyDataSent, | |
| 406 weak_factory_.GetWeakPtr())); | |
| 407 return true; | |
| 408 } | |
| 409 LOG(ERROR) << "Trying to send data after stream has been destroyed."; | |
| 410 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 411 FROM_HERE, base::Bind(&BidirectionalStreamSpdyImpl::NotifyError, | |
| 412 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED)); | |
| 413 return true; | |
| 414 } | |
| 415 | |
| 376 } // namespace net | 416 } // namespace net |
| OLD | NEW |