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..da6733a2b56ea0fe3b6c50c9a4197ce27d2d2647 100644 |
--- a/net/quic/bidirectional_stream_quic_impl.cc |
+++ b/net/quic/bidirectional_stream_quic_impl.cc |
@@ -75,7 +75,14 @@ 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,8 +126,14 @@ 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_) { |
@@ -149,9 +162,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."; |
mef
2016/06/03 20:03:19
I think logging is fine, but I'm not sure that pos
xunjieli
2016/06/03 20:20:53
If stream is destroyed gracefully because of a net
|
+ 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 +193,14 @@ void BidirectionalStreamQuicImpl::SendvData( |
} |
void BidirectionalStreamQuicImpl::Cancel() { |
- if (stream_) { |
- stream_->SetDelegate(nullptr); |
- stream_->Reset(QUIC_STREAM_CANCELLED); |
- ResetStream(); |
- } |
+ if (!stream_) |
+ return; |
+ stream_->SetDelegate(nullptr); |
+ stream_->Reset(QUIC_STREAM_CANCELLED); |
+ delegate_ = nullptr; |
+ // Cancel any pending callbacks. |
+ weak_factory_.InvalidateWeakPtrs(); |
mef
2016/06/03 20:03:19
should this be part of ResetStream()?
xunjieli
2016/06/03 20:20:53
Great question! If OnClose(OK) is invoked, we do R
|
+ ResetStream(); |
} |
NextProto BidirectionalStreamQuicImpl::GetProtocol() const { |
@@ -203,14 +226,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 +253,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 +297,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 +307,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 +318,15 @@ void BidirectionalStreamQuicImpl::NotifyError(int error) { |
DCHECK_NE(OK, error); |
DCHECK_NE(ERR_IO_PENDING, error); |
+ if (!delegate_) |
+ return; |
response_status_ = error; |
ResetStream(); |
- delegate_->OnFailed(error); |
+ BidirectionalStreamImpl::Delegate* delegate = delegate_; |
+ delegate_ = nullptr; |
+ // Cancel any pending callback. |
+ weak_factory_.InvalidateWeakPtrs(); |
mef
2016/06/03 20:03:19
If we invalidate any pending callbacks here, why d
xunjieli
2016/06/03 20:20:53
Great question! InvalidateWeakPtrs() only invalida
|
+ delegate->OnFailed(error); |
} |
void BidirectionalStreamQuicImpl::ResetStream() { |