Chromium Code Reviews| Index: net/quic/bidirectional_stream_quic_impl.cc |
| diff --git a/net/quic/bidirectional_stream_quic_impl.cc b/net/quic/bidirectional_stream_quic_impl.cc |
| index d34221050ca481d15ff41c5a0aeb7a1ce47d639b..f407598460a00c975e1454e092c0d4dbbe0742f6 100644 |
| --- a/net/quic/bidirectional_stream_quic_impl.cc |
| +++ b/net/quic/bidirectional_stream_quic_impl.cc |
| @@ -75,7 +75,15 @@ void BidirectionalStreamQuicImpl::Start( |
| void BidirectionalStreamQuicImpl::SendRequestHeaders() { |
| DCHECK(!has_sent_headers_); |
| - DCHECK(stream_); |
| + |
| + if (!stream_) { |
| + LOG(ERROR) |
| + << "Trying to send request headers after stream has been destroyed."; |
| + base::ThreadTaskRunnerHandle::Get()->PostTask( |
| + FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError, |
| + weak_factory_.GetWeakPtr(), ERR_UNEXPECTED)); |
| + return; |
| + } |
| SpdyHeaderBlock headers; |
| HttpRequestInfo http_request_info; |
| @@ -119,9 +127,16 @@ int BidirectionalStreamQuicImpl::ReadData(IOBuffer* buffer, int buffer_len) { |
| void BidirectionalStreamQuicImpl::SendData(const scoped_refptr<IOBuffer>& data, |
| int length, |
| bool end_stream) { |
| - DCHECK(stream_); |
| DCHECK(length > 0 || (length == 0 && end_stream)); |
| + if (!stream_) { |
| + LOG(ERROR) << "Trying to send data after stream has been destroyed."; |
| + base::ThreadTaskRunnerHandle::Get()->PostTask( |
| + FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError, |
| + weak_factory_.GetWeakPtr(), ERR_UNEXPECTED)); |
| + return; |
| + } |
| + |
| std::unique_ptr<QuicConnection::ScopedPacketBundler> bundler; |
| if (!has_sent_headers_) { |
| DCHECK(!send_request_headers_automatically_); |
| @@ -149,9 +164,16 @@ void BidirectionalStreamQuicImpl::SendvData( |
| const std::vector<scoped_refptr<IOBuffer>>& buffers, |
| const std::vector<int>& lengths, |
| bool end_stream) { |
| - DCHECK(stream_); |
| DCHECK_EQ(buffers.size(), lengths.size()); |
| + if (!stream_) { |
| + LOG(ERROR) << "Trying to send data after stream has been destroyed."; |
| + base::ThreadTaskRunnerHandle::Get()->PostTask( |
| + FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError, |
| + weak_factory_.GetWeakPtr(), ERR_UNEXPECTED)); |
| + return; |
| + } |
| + |
| QuicConnection::ScopedPacketBundler bundler( |
| session_->connection(), QuicConnection::SEND_ACK_IF_PENDING); |
| if (!has_sent_headers_) { |
| @@ -173,11 +195,14 @@ void BidirectionalStreamQuicImpl::SendvData( |
| } |
| void BidirectionalStreamQuicImpl::Cancel() { |
| - if (stream_) { |
| - stream_->SetDelegate(nullptr); |
| - stream_->Reset(QUIC_STREAM_CANCELLED); |
| - ResetStream(); |
| - } |
| + if (!stream_) |
| + return; |
| + stream_->SetDelegate(nullptr); |
|
kapishnikov
2016/06/03 20:10:08
ResetStream() calls "stream_->SetDelegate(nullptr)
xunjieli
2016/06/03 20:28:36
Great catch!
|
| + stream_->Reset(QUIC_STREAM_CANCELLED); |
| + delegate_ = nullptr; |
|
kapishnikov
2016/06/03 20:10:08
Should we unconditionally set "delegate_ = nullptr
xunjieli
2016/06/03 20:28:36
Great catch! I've addressed it a newer patch.
|
| + // Cancel any pending callbacks. |
| + weak_factory_.InvalidateWeakPtrs(); |
| + ResetStream(); |
| } |
| NextProto BidirectionalStreamQuicImpl::GetProtocol() const { |
| @@ -203,14 +228,16 @@ void BidirectionalStreamQuicImpl::OnHeadersAvailable( |
| negotiated_protocol_ = kProtoQUIC1SPDY3; |
| if (!has_received_headers_) { |
| has_received_headers_ = true; |
| - delegate_->OnHeadersReceived(headers); |
| + if (delegate_) |
| + delegate_->OnHeadersReceived(headers); |
| } else { |
| if (stream_->IsDoneReading()) { |
| // If the write side is closed, OnFinRead() will call |
| // BidirectionalStreamQuicImpl::OnClose(). |
| stream_->OnFinRead(); |
| } |
| - delegate_->OnTrailersReceived(headers); |
| + if (delegate_) |
| + delegate_->OnTrailersReceived(headers); |
| } |
| } |
| @@ -228,17 +255,18 @@ void BidirectionalStreamQuicImpl::OnDataAvailable() { |
| } |
| read_buffer_ = nullptr; |
| read_buffer_len_ = 0; |
| - delegate_->OnDataRead(rv); |
| + if (delegate_) |
| + delegate_->OnDataRead(rv); |
| } |
| void BidirectionalStreamQuicImpl::OnClose(QuicErrorCode error) { |
| DCHECK(stream_); |
| + |
| if (error == QUIC_NO_ERROR && |
| stream_->stream_error() == QUIC_STREAM_NO_ERROR) { |
| ResetStream(); |
| return; |
| } |
| - ResetStream(); |
| NotifyError(was_handshake_confirmed_ ? ERR_QUIC_PROTOCOL_ERROR |
| : ERR_QUIC_HANDSHAKE_FAILED); |
| } |
| @@ -271,7 +299,8 @@ void BidirectionalStreamQuicImpl::OnStreamReady(int rv) { |
| if (send_request_headers_automatically_) { |
| SendRequestHeaders(); |
| } |
| - delegate_->OnStreamReady(has_sent_headers_); |
| + if (delegate_) |
| + delegate_->OnStreamReady(has_sent_headers_); |
| } else { |
| NotifyError(rv); |
| } |
| @@ -280,7 +309,8 @@ void BidirectionalStreamQuicImpl::OnStreamReady(int rv) { |
| void BidirectionalStreamQuicImpl::OnSendDataComplete(int rv) { |
| DCHECK(rv == OK || !stream_); |
| if (rv == OK) { |
| - delegate_->OnDataSent(); |
| + if (delegate_) |
| + delegate_->OnDataSent(); |
| } else { |
| NotifyError(rv); |
| } |
| @@ -290,9 +320,15 @@ void BidirectionalStreamQuicImpl::NotifyError(int error) { |
| DCHECK_NE(OK, error); |
| DCHECK_NE(ERR_IO_PENDING, error); |
| + if (!delegate_) |
| + return; |
| response_status_ = error; |
| ResetStream(); |
|
kapishnikov
2016/06/03 20:10:07
Should we call ResetStream() before "if (!delegate
xunjieli
2016/06/03 20:28:36
Great catch. I've also realized this and addressed
|
| - delegate_->OnFailed(error); |
| + BidirectionalStreamImpl::Delegate* delegate = delegate_; |
| + delegate_ = nullptr; |
| + // Cancel any pending callback. |
| + weak_factory_.InvalidateWeakPtrs(); |
| + delegate->OnFailed(error); |
| } |
| void BidirectionalStreamQuicImpl::ResetStream() { |