Chromium Code Reviews| Index: net/quic/chromium/quic_chromium_client_stream.cc |
| diff --git a/net/quic/chromium/quic_chromium_client_stream.cc b/net/quic/chromium/quic_chromium_client_stream.cc |
| index 5eb505a382db4011e8ab0e6ed3bd9f794c365855..5f806595a430bfd589e1863e418b9dd5904525d2 100644 |
| --- a/net/quic/chromium/quic_chromium_client_stream.cc |
| +++ b/net/quic/chromium/quic_chromium_client_stream.cc |
| @@ -21,9 +21,31 @@ |
| namespace net { |
| +namespace { |
| + |
| +// Sets a boolean to a value, and restores it to the previous value once |
| +// the saver goes out of scope. |
| +class ScopedBoolSaver { |
| + public: |
| + ScopedBoolSaver(bool* var, bool new_val) : var_(var), old_val_(*var) { |
| + *var_ = new_val; |
| + } |
| + |
| + ~ScopedBoolSaver() { *var_ = old_val_; } |
| + |
| + private: |
| + bool* var_; |
| + bool old_val_; |
| +}; |
| + |
| +} // namespace |
| + |
| QuicChromiumClientStream::Handle::Handle(QuicChromiumClientStream* stream, |
| Delegate* delegate) |
| - : stream_(stream), delegate_(delegate) { |
| + : stream_(stream), |
| + delegate_(delegate), |
| + can_invoke_callbacks_(true), |
| + read_headers_buffer_(nullptr) { |
| SaveState(); |
| } |
| @@ -40,10 +62,15 @@ void QuicChromiumClientStream::Handle::ClearDelegate() { |
| delegate_ = nullptr; |
| } |
| -void QuicChromiumClientStream::Handle::OnInitialHeadersAvailable( |
| - const SpdyHeaderBlock& headers, |
| - size_t frame_len) { |
| - delegate_->OnInitialHeadersAvailable(headers, frame_len); |
| +void QuicChromiumClientStream::Handle::OnInitialHeadersAvailable() { |
| + if (!read_headers_callback_ || !can_invoke_callbacks_) |
| + return; // Wait for ReadInitialHeaders to be called. |
| + |
| + int rv; |
|
xunjieli
2017/05/10 17:54:27
Looks like DeliverInitialiHeaders() can fail to in
Ryan Hamilton
2017/05/10 18:26:40
I think that should only happen when Deliver retur
|
| + if (!stream_->DeliverInitialHeaders(read_headers_buffer_, &rv)) |
|
xunjieli
2017/05/10 17:54:27
If BidiStream or QuicHttpStream is gone but Handle
Ryan Hamilton
2017/05/10 18:26:40
The Handle is by definition owned by "the caller"
xunjieli
2017/05/10 18:58:08
Acknowledged. The ownership model takes a while to
Ryan Hamilton
2017/05/10 19:33:46
*fingers crossed*!
|
| + rv = ERR_QUIC_PROTOCOL_ERROR; |
| + |
| + ResetAndReturn(&read_headers_callback_).Run(rv); |
| } |
| void QuicChromiumClientStream::Handle::OnTrailingHeadersAvailable( |
| @@ -78,6 +105,22 @@ void QuicChromiumClientStream::Handle::OnError(int error) { |
| } |
| } |
| +int QuicChromiumClientStream::Handle::ReadInitialHeaders( |
| + SpdyHeaderBlock* header_block, |
| + const CompletionCallback& callback) { |
| + ScopedBoolSaver saver(&can_invoke_callbacks_, false); |
|
xunjieli
2017/05/10 17:54:27
Why do we need to have this bool? I don't see any
Ryan Hamilton
2017/05/10 18:26:40
AH! Sorry, I meant to mention this in the CL descr
xunjieli
2017/05/10 18:58:08
I see. That makes sense. Let's omit this in this C
Ryan Hamilton
2017/05/10 19:33:46
SGTM. Done.
|
| + if (!stream_) |
| + return ERR_CONNECTION_CLOSED; |
| + |
| + int frame_len; |
|
xunjieli
2017/05/10 17:54:27
same here. |frame_len| might not be initialized.
Ryan Hamilton
2017/05/10 18:26:40
Done.
|
| + if (stream_->DeliverInitialHeaders(header_block, &frame_len)) |
| + return frame_len; |
| + |
| + read_headers_buffer_ = header_block; |
| + SetCallback(callback, &read_headers_callback_); |
| + return ERR_IO_PENDING; |
| +} |
| + |
| size_t QuicChromiumClientStream::Handle::WriteHeaders( |
| SpdyHeaderBlock header_block, |
| bool fin, |
| @@ -234,6 +277,13 @@ void QuicChromiumClientStream::Handle::SaveState() { |
| priority_ = stream_->priority(); |
| } |
| +void QuicChromiumClientStream::Handle::SetCallback( |
| + CompletionCallback new_callback, |
| + CompletionCallback* callback) { |
| + DCHECK(!can_invoke_callbacks_); |
| + *callback = new_callback; |
| +} |
| + |
| QuicChromiumClientStream::QuicChromiumClientStream( |
| QuicStreamId id, |
| QuicClientSessionBase* session, |
| @@ -271,16 +321,14 @@ void QuicChromiumClientStream::OnInitialHeadersComplete( |
| ConsumeHeaderList(); |
| session_->OnInitialHeadersComplete(id(), header_block); |
| - if (handle_) { |
| - // The handle will receive the headers via a posted task. |
| - NotifyHandleOfInitialHeadersAvailableLater(std::move(header_block), |
| - frame_len); |
| - return; |
| - } |
| - |
| // Buffer the headers and deliver them when the handle arrives. |
| initial_headers_ = std::move(header_block); |
| initial_headers_frame_len_ = frame_len; |
| + |
| + if (handle_) { |
| + // The handle will be notified of the headers via a posted task. |
| + NotifyHandleOfInitialHeadersAvailableLater(); |
| + } |
| } |
| void QuicChromiumClientStream::OnTrailingHeadersComplete( |
| @@ -414,10 +462,8 @@ QuicChromiumClientStream::CreateHandle( |
| handle_ = handle.get(); |
| // Should this perhaps be via PostTask to make reasoning simpler? |
| - if (!initial_headers_.empty()) { |
| - handle_->OnInitialHeadersAvailable(std::move(initial_headers_), |
| - initial_headers_frame_len_); |
| - } |
| + if (!initial_headers_.empty()) |
| + handle_->OnInitialHeadersAvailable(); |
| return handle; |
| } |
| @@ -450,31 +496,21 @@ int QuicChromiumClientStream::Read(IOBuffer* buf, int buf_len) { |
| return bytes_read; |
| } |
| -void QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailableLater( |
| - SpdyHeaderBlock headers, |
| - size_t frame_len) { |
| +void QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailableLater() { |
| DCHECK(handle_); |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, |
| base::Bind( |
| &QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailable, |
| - weak_factory_.GetWeakPtr(), base::Passed(std::move(headers)), |
| - frame_len)); |
| + weak_factory_.GetWeakPtr())); |
| } |
| -void QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailable( |
| - SpdyHeaderBlock headers, |
| - size_t frame_len) { |
| +void QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailable() { |
| if (!handle_) |
| return; |
| - DCHECK(!headers_delivered_); |
| - headers_delivered_ = true; |
| - net_log_.AddEvent( |
| - NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_HEADERS, |
| - base::Bind(&SpdyHeaderBlockNetLogCallback, &headers)); |
| - |
| - handle_->OnInitialHeadersAvailable(headers, frame_len); |
| + if (!headers_delivered_) |
| + handle_->OnInitialHeadersAvailable(); |
| } |
| void QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailableLater( |
| @@ -503,10 +539,24 @@ void QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailable( |
| net_log_.AddEvent( |
| NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_TRAILERS, |
| base::Bind(&SpdyHeaderBlockNetLogCallback, &headers)); |
| - |
| handle_->OnTrailingHeadersAvailable(headers, frame_len); |
| } |
| +bool QuicChromiumClientStream::DeliverInitialHeaders(SpdyHeaderBlock* headers, |
| + int* frame_len) { |
| + if (initial_headers_.empty()) |
| + return false; |
| + |
| + headers_delivered_ = true; |
| + net_log_.AddEvent( |
| + NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_HEADERS, |
| + base::Bind(&SpdyHeaderBlockNetLogCallback, &initial_headers_)); |
| + |
| + *headers = std::move(initial_headers_); |
| + *frame_len = initial_headers_frame_len_; |
| + return true; |
| +} |
| + |
| void QuicChromiumClientStream::NotifyHandleOfDataAvailableLater() { |
| DCHECK(handle_); |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |