summaryrefslogtreecommitdiffstats
path: root/net/spdy/spdy_stream.cc
diff options
context:
space:
mode:
Diffstat (limited to 'net/spdy/spdy_stream.cc')
-rw-r--r--net/spdy/spdy_stream.cc162
1 files changed, 55 insertions, 107 deletions
diff --git a/net/spdy/spdy_stream.cc b/net/spdy/spdy_stream.cc
index fb5692a4..0204db6 100644
--- a/net/spdy/spdy_stream.cc
+++ b/net/spdy/spdy_stream.cc
@@ -20,12 +20,11 @@ SpdyStream::SpdyStream(
send_window_size_(spdy::kInitialWindowSize),
pushed_(pushed),
metrics_(Singleton<BandwidthMetrics>::get()),
- syn_reply_received_(false),
+ response_received_(false),
session_(session),
delegate_(NULL),
request_time_(base::Time::Now()),
response_(new spdy::SpdyHeaderBlock),
- response_complete_(false),
io_state_(STATE_NONE),
response_status_(OK),
cancelled_(false),
@@ -42,7 +41,7 @@ void SpdyStream::SetDelegate(Delegate* delegate) {
delegate_ = delegate;
if (pushed_) {
- CHECK(!response_->empty());
+ CHECK(response_received());
MessageLoop::current()->PostTask(
FROM_HERE, NewRunnableMethod(this,
&SpdyStream::PushedStreamReplayData));
@@ -72,7 +71,7 @@ void SpdyStream::PushedStreamReplayData() {
void SpdyStream::DetachDelegate() {
delegate_ = NULL;
- if (!response_complete_)
+ if (!closed())
Cancel();
}
@@ -115,7 +114,7 @@ void SpdyStream::IncreaseSendWindowSize(int delta_window_size) {
// If the stream was stalled due to consumed window size, restart the
// I/O loop.
- if (!response_complete_ && !delegate_->IsFinishedSendingBody()) {
+ if (!closed() && !delegate_->IsFinishedSendingBody()) {
// Don't start the I/O loop for every WINDOW_UPDATE frame received,
// since we may receive many of them before the "write" due to first
// received WINDOW_UPDATE is completed.
@@ -154,8 +153,7 @@ void SpdyStream::SetRequestTime(base::Time t) {
int SpdyStream::OnResponseReceived(const spdy::SpdyHeaderBlock& response) {
int rv = OK;
- LOG(INFO) << "OnResponseReceived";
- DCHECK_NE(io_state_, STATE_OPEN);
+ LOG(INFO) << "Received response for stream " << stream_id_;
metrics_.StartStream();
@@ -165,17 +163,14 @@ int SpdyStream::OnResponseReceived(const spdy::SpdyHeaderBlock& response) {
recv_first_byte_time_ = base::TimeTicks::Now();
response_time_ = base::Time::Now();
- if (io_state_ == STATE_NONE) {
- CHECK(pushed_);
- io_state_ = STATE_READ_HEADERS;
- } else if (io_state_ == STATE_READ_HEADERS_COMPLETE) {
- CHECK(!pushed_);
- } else {
- // We're not expecting a response while in this state. Error!
- rv = ERR_SPDY_PROTOCOL_ERROR;
- }
+ // If we receive a response before we are in STATE_WAITING_FOR_RESPONSE, then
+ // the server has sent the SYN_REPLY too early.
+ if (!pushed_ && io_state_ != STATE_WAITING_FOR_RESPONSE)
+ return ERR_SPDY_PROTOCOL_ERROR;
+ if (pushed_)
+ CHECK(io_state_ == STATE_NONE);
+ io_state_ = STATE_OPEN;
- rv = DoLoop(rv);
if (delegate_)
rv = delegate_->OnResponseReceived(*response_, response_time_, rv);
// If delegate_ is not yet attached, we'll call OnResponseReceived after the
@@ -202,12 +197,12 @@ void SpdyStream::OnDataReceived(const char* data, int length) {
return;
}
- CHECK(!response_complete_);
+ CHECK(!closed());
// 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
// received.
- if (response_->empty()) {
+ if (!response_received()) {
session_->CloseStream(stream_id_, ERR_SYN_REPLY_NOT_RECEIVED);
return;
}
@@ -238,26 +233,18 @@ void SpdyStream::OnDataReceived(const char* data, int length) {
delegate_->OnDataReceived(data, length);
}
-void SpdyStream::OnWriteComplete(int status) {
- // TODO(mbelshe): Check for cancellation here. If we're cancelled, we
- // should discontinue the DoLoop.
-
- // Clear it just in case this write lead to a 0 size send window, so that
- // incoming window updates will cause a write to be scheduled again.
+// This function is only called when an entire frame is written.
+void SpdyStream::OnWriteComplete(int bytes) {
window_update_write_pending_ = false;
-
- // It is possible that this stream was closed while we had a write pending.
- if (response_complete_)
+ DCHECK_LE(0, bytes);
+ send_bytes_ += bytes;
+ if (cancelled() || closed())
return;
-
- if (status > 0)
- send_bytes_ += status;
-
- DoLoop(status);
+ DoLoop(bytes);
}
void SpdyStream::OnClose(int status) {
- response_complete_ = true;
+ io_state_ = STATE_DONE;
response_status_ = status;
Delegate* delegate = delegate_;
delegate_ = NULL;
@@ -274,53 +261,20 @@ void SpdyStream::Cancel() {
session_->ResetStream(stream_id_, spdy::CANCEL);
}
-int SpdyStream::DoSendRequest(bool has_upload_data) {
- CHECK(!cancelled_);
-
- if (!pushed_) {
- spdy::SpdyControlFlags flags = spdy::CONTROL_FLAG_NONE;
- if (!has_upload_data)
- flags = spdy::CONTROL_FLAG_FIN;
-
- CHECK(request_.get());
- int result = session_->WriteSynStream(
- stream_id_, static_cast<RequestPriority>(priority_), flags,
- request_);
- if (result != ERR_IO_PENDING)
- return result;
- }
-
- send_time_ = base::TimeTicks::Now();
-
- int result = OK;
- if (!pushed_) {
- DCHECK_EQ(io_state_, STATE_NONE);
- io_state_ = STATE_SEND_HEADERS;
- } else {
- // Pushed stream should not have upload data.
- DCHECK(!has_upload_data);
- DCHECK(!response_->empty());
- DCHECK_EQ(io_state_, STATE_OPEN);
+int SpdyStream::SendRequest(bool has_upload_data) {
+ // Pushed streams do not send any data, and should always be in STATE_OPEN or
+ // STATE_DONE. However, we still want to return IO_PENDING to mimic non-push
+ // behavior.
+ has_upload_data_ = has_upload_data;
+ if (pushed_) {
+ send_time_ = base::TimeTicks::Now();
+ DCHECK(!has_upload_data_);
+ DCHECK(response_received());
return ERR_IO_PENDING;
}
- return DoLoop(result);
-}
-
-int SpdyStream::DoReadResponseHeaders() {
- CHECK(!cancelled_);
-
- // The SYN_REPLY has already been received.
- if (!response_->empty()) {
- CHECK_EQ(STATE_OPEN, io_state_);
- return OK;
- } else {
- CHECK_EQ(STATE_NONE, io_state_);
- }
-
-
- io_state_ = STATE_READ_HEADERS;
- // Q: do we need to run DoLoop here?
- return ERR_IO_PENDING;
+ CHECK_EQ(STATE_NONE, io_state_);
+ io_state_ = STATE_SEND_HEADERS;
+ return DoLoop(OK);
}
int SpdyStream::WriteStreamData(IOBuffer* data, int length,
@@ -337,7 +291,7 @@ int SpdyStream::DoLoop(int result) {
State state = io_state_;
io_state_ = STATE_NONE;
switch (state) {
- // State machine 1: Send headers and wait for response headers.
+ // State machine 1: Send headers and body.
case STATE_SEND_HEADERS:
CHECK_EQ(OK, result);
net_log_.BeginEvent(NetLog::TYPE_SPDY_STREAM_SEND_HEADERS, NULL);
@@ -356,16 +310,12 @@ int SpdyStream::DoLoop(int result) {
net_log_.EndEvent(NetLog::TYPE_SPDY_STREAM_SEND_BODY, NULL);
result = DoSendBodyComplete(result);
break;
- case STATE_READ_HEADERS:
- CHECK_EQ(OK, result);
- net_log_.BeginEvent(NetLog::TYPE_SPDY_STREAM_READ_HEADERS, NULL);
- result = DoReadHeaders();
- break;
- case STATE_READ_HEADERS_COMPLETE:
- net_log_.EndEvent(NetLog::TYPE_SPDY_STREAM_READ_HEADERS, NULL);
- result = DoReadHeadersComplete(result);
+ // This is an intermediary waiting state. This state is reached when all
+ // data has been sent, but no data has been received.
+ case STATE_WAITING_FOR_RESPONSE:
+ io_state_ = STATE_WAITING_FOR_RESPONSE;
+ result = ERR_IO_PENDING;
break;
-
// State machine 2: connection is established.
// In STATE_OPEN, OnResponseReceived has already been called.
// OnDataReceived, OnClose and OnWriteCompelte can be called.
@@ -398,12 +348,20 @@ int SpdyStream::DoLoop(int result) {
}
int SpdyStream::DoSendHeaders() {
- // The SpdySession will always call us back when the send is complete.
- // TODO(willchan): This code makes the assumption that for the non-push stream
- // case, the client code calls SendRequest() after creating the stream and
- // before yielding back to the MessageLoop. This is true in the current code,
- // but is not obvious from the headers. We should make the code handle
- // SendRequest() being called after the SYN_REPLY has been received.
+ CHECK(!cancelled_);
+
+ spdy::SpdyControlFlags flags = spdy::CONTROL_FLAG_NONE;
+ if (!has_upload_data_)
+ flags = spdy::CONTROL_FLAG_FIN;
+
+ CHECK(request_.get());
+ int result = session_->WriteSynStream(
+ stream_id_, static_cast<RequestPriority>(priority_), flags,
+ request_);
+ if (result != ERR_IO_PENDING)
+ return result;
+
+ send_time_ = base::TimeTicks::Now();
io_state_ = STATE_SEND_HEADERS_COMPLETE;
return ERR_IO_PENDING;
}
@@ -419,7 +377,7 @@ int SpdyStream::DoSendHeadersComplete(int result) {
// There is no body, skip that state.
if (delegate_->OnSendHeadersComplete(result)) {
- io_state_ = STATE_READ_HEADERS;
+ io_state_ = STATE_WAITING_FOR_RESPONSE;
return OK;
}
@@ -454,21 +412,11 @@ int SpdyStream::DoSendBodyComplete(int result) {
if (!delegate_->IsFinishedSendingBody())
io_state_ = STATE_SEND_BODY;
else
- io_state_ = STATE_READ_HEADERS;
+ io_state_ = STATE_WAITING_FOR_RESPONSE;
return OK;
}
-int SpdyStream::DoReadHeaders() {
- io_state_ = STATE_READ_HEADERS_COMPLETE;
- return !response_->empty() ? OK : ERR_IO_PENDING;
-}
-
-int SpdyStream::DoReadHeadersComplete(int result) {
- io_state_ = STATE_OPEN;
- return result;
-}
-
int SpdyStream::DoOpen(int result) {
if (delegate_)
delegate_->OnDataSent(result);