| 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..ad706a56e1bc34b45fc0729cf17df94c09a6339d 100644 | 
| --- a/net/quic/chromium/quic_chromium_client_stream.cc | 
| +++ b/net/quic/chromium/quic_chromium_client_stream.cc | 
| @@ -23,7 +23,7 @@ namespace net { | 
|  | 
| QuicChromiumClientStream::Handle::Handle(QuicChromiumClientStream* stream, | 
| Delegate* delegate) | 
| -    : stream_(stream), delegate_(delegate) { | 
| +    : stream_(stream), delegate_(delegate), read_headers_buffer_(nullptr) { | 
| SaveState(); | 
| } | 
|  | 
| @@ -40,10 +40,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_) | 
| +    return;  // Wait for ReadInitialHeaders to be called. | 
| + | 
| +  int rv = ERR_QUIC_PROTOCOL_ERROR; | 
| +  if (!stream_->DeliverInitialHeaders(read_headers_buffer_, &rv)) | 
| +    rv = ERR_QUIC_PROTOCOL_ERROR; | 
| + | 
| +  ResetAndReturn(&read_headers_callback_).Run(rv); | 
| } | 
|  | 
| void QuicChromiumClientStream::Handle::OnTrailingHeadersAvailable( | 
| @@ -78,6 +83,21 @@ void QuicChromiumClientStream::Handle::OnError(int error) { | 
| } | 
| } | 
|  | 
| +int QuicChromiumClientStream::Handle::ReadInitialHeaders( | 
| +    SpdyHeaderBlock* header_block, | 
| +    const CompletionCallback& callback) { | 
| +  if (!stream_) | 
| +    return ERR_CONNECTION_CLOSED; | 
| + | 
| +  int frame_len = 0; | 
| +  if (stream_->DeliverInitialHeaders(header_block, &frame_len)) | 
| +    return frame_len; | 
| + | 
| +  read_headers_buffer_ = header_block; | 
| +  read_headers_callback_ = callback; | 
| +  return ERR_IO_PENDING; | 
| +} | 
| + | 
| size_t QuicChromiumClientStream::Handle::WriteHeaders( | 
| SpdyHeaderBlock header_block, | 
| bool fin, | 
| @@ -271,16 +291,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 +432,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 +466,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 +509,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( | 
|  |