| Index: net/spdy/spdy_stream.cc
|
| diff --git a/net/spdy/spdy_stream.cc b/net/spdy/spdy_stream.cc
|
| index b79cb9936abeb5633cdcaca88c883f2b972ed6e6..5fd5f14690cec30e28c6b91b0ec00562110047f1 100644
|
| --- a/net/spdy/spdy_stream.cc
|
| +++ b/net/spdy/spdy_stream.cc
|
| @@ -13,7 +13,8 @@ namespace net {
|
|
|
| SpdyStream::SpdyStream(
|
| SpdySession* session, spdy::SpdyStreamId stream_id, bool pushed)
|
| - : stream_id_(stream_id),
|
| + : continue_buffering_data_(true),
|
| + stream_id_(stream_id),
|
| priority_(0),
|
| send_window_size_(spdy::kInitialWindowSize),
|
| pushed_(pushed),
|
| @@ -39,16 +40,32 @@ void SpdyStream::SetDelegate(Delegate* delegate) {
|
| CHECK(delegate);
|
| delegate_ = delegate;
|
|
|
| - if (!response_->empty()) {
|
| - // The stream already got response.
|
| - delegate_->OnResponseReceived(*response_, response_time_, OK);
|
| + if (pushed_) {
|
| + CHECK(!response_->empty());
|
| + MessageLoop::current()->PostTask(
|
| + FROM_HERE, NewRunnableMethod(this,
|
| + &SpdyStream::PushedStreamReplayData));
|
| + } else {
|
| + continue_buffering_data_ = false;
|
| }
|
| +}
|
|
|
| +void SpdyStream::PushedStreamReplayData() {
|
| + if (cancelled_ || delegate_ == NULL)
|
| + return;
|
| +
|
| + delegate_->OnResponseReceived(*response_, response_time_, OK);
|
| +
|
| + continue_buffering_data_ = false;
|
| std::vector<scoped_refptr<IOBufferWithSize> > buffers;
|
| buffers.swap(pending_buffers_);
|
| for (size_t i = 0; i < buffers.size(); ++i) {
|
| - if (delegate_)
|
| - delegate_->OnDataReceived(buffers[i]->data(), buffers[i]->size());
|
| + if (delegate_){
|
| + if (buffers[i])
|
| + delegate_->OnDataReceived(buffers[i]->data(), buffers[i]->size());
|
| + else
|
| + delegate_->OnDataReceived(NULL, 0);
|
| + }
|
| }
|
| }
|
|
|
| @@ -131,13 +148,7 @@ int SpdyStream::OnResponseReceived(const spdy::SpdyHeaderBlock& response) {
|
| CHECK(pushed_);
|
| io_state_ = STATE_READ_HEADERS;
|
| } else if (io_state_ == STATE_READ_HEADERS_COMPLETE) {
|
| - // This SpdyStream could be in this state in both true and false pushed_
|
| - // conditions.
|
| - // The false pushed_ condition (client request) will always go through
|
| - // this state.
|
| - // The true pushed_condition (server push) can be in this state when the
|
| - // client requests an X-Associated-Content piece of content prior
|
| - // to when the server push happens.
|
| + CHECK(!pushed_);
|
| } else {
|
| // We're not expecting a response while in this state. Error!
|
| rv = ERR_SPDY_PROTOCOL_ERROR;
|
| @@ -146,8 +157,8 @@ int SpdyStream::OnResponseReceived(const spdy::SpdyHeaderBlock& response) {
|
| rv = DoLoop(rv);
|
| if (delegate_)
|
| rv = delegate_->OnResponseReceived(*response_, response_time_, rv);
|
| - // if delegate_ is not yet attached, we'll return response when delegate
|
| - // gets attached to the stream.
|
| + // If delegate_ is not yet attached, we'll call OnResponseReceived after the
|
| + // delegate gets attached to the stream.
|
|
|
| return rv;
|
| }
|
| @@ -157,7 +168,20 @@ void SpdyStream::OnDataReceived(const char* data, int length) {
|
| LOG(INFO) << "SpdyStream: Data (" << length << " bytes) received for "
|
| << stream_id_;
|
|
|
| - CHECK(!response_complete_);
|
| + if (!delegate_ || continue_buffering_data_) {
|
| + // It should be valid for this to happen in the server push case.
|
| + // We'll return received data when delegate gets attached to the stream.
|
| + if (length > 0) {
|
| + IOBufferWithSize* buf = new IOBufferWithSize(length);
|
| + memcpy(buf->data(), data, length);
|
| + pending_buffers_.push_back(buf);
|
| + }
|
| + else
|
| + pending_buffers_.push_back(NULL);
|
| + return;
|
| + }
|
| +
|
| + CHECK(!response_complete_);
|
|
|
| // If we don't have a response, then the SYN_REPLY did not come through.
|
| // We cannot pass data up to the caller unless the reply headers have been
|
| @@ -248,16 +272,11 @@ int SpdyStream::DoSendRequest(bool has_upload_data) {
|
| DCHECK_EQ(io_state_, STATE_NONE);
|
| io_state_ = STATE_SEND_HEADERS;
|
| } else {
|
| + // Pushed stream should not have upload data.
|
| DCHECK(!has_upload_data);
|
| - if (!response_->empty()) {
|
| - // We already have response headers, so we don't need to read the header.
|
| - // Pushed stream should not have upload data.
|
| - // We don't need to call DoLoop() in this state.
|
| - DCHECK_EQ(io_state_, STATE_OPEN);
|
| - return OK;
|
| - } else {
|
| - io_state_ = STATE_READ_HEADERS;
|
| - }
|
| + DCHECK(!response_->empty());
|
| + DCHECK_EQ(io_state_, STATE_OPEN);
|
| + return ERR_IO_PENDING;
|
| }
|
| return DoLoop(result);
|
| }
|
|
|