Index: net/spdy/spdy_stream.cc |
=================================================================== |
--- net/spdy/spdy_stream.cc (revision 80449) |
+++ net/spdy/spdy_stream.cc (working copy) |
@@ -51,6 +51,9 @@ |
delegate_(NULL), |
request_time_(base::Time::Now()), |
response_(new spdy::SpdyHeaderBlock), |
+ syn_reply_received_(false), |
+ metrics_started_(false), |
+ close_pending_(false), |
io_state_(STATE_NONE), |
response_status_(OK), |
cancelled_(false), |
@@ -230,10 +233,27 @@ |
request_time_ = t; |
} |
+bool SpdyStream::using_sctp() { |
+ return session_->using_sctp(); |
+} |
+ |
+bool SpdyStream::using_sctp_control_stream() { |
+ return session_->using_sctp_control_stream(); |
+} |
+ |
int SpdyStream::OnResponseReceived(const spdy::SpdyHeaderBlock& response) { |
int rv = OK; |
- metrics_.StartStream(); |
+ // We need to avoid starting metrics a second time. If we are using SCTP |
+ // with a single dictionary, and the SYN_REPLY was delayed or lost, we may |
+ // have already started metrics when the first DATA frame arrived. |
+ if ( !(using_sctp() && |
+ using_sctp_control_stream() && |
+ metrics_started()) |
+ ) { |
+ set_metrics_started(); |
+ metrics_.StartStream(); |
+ } |
DCHECK(response_->empty()); |
*response_ = response; // TODO(ukai): avoid copy. |
@@ -286,11 +306,29 @@ |
void SpdyStream::OnDataReceived(const char* data, int length) { |
DCHECK_GE(length, 0); |
+ // TODO(jtl): revisit this |
+ // We need to start metrics here if we are using SCTP without multiple |
+ // dictionaries, the SYN_REPLY has not yet arrived and metrics have not yet |
+ // been started. |
+ if (using_sctp() && |
+ using_sctp_control_stream() && |
+ !syn_reply_received() && |
+ !metrics_started()) { |
+ set_metrics_started(); |
+ metrics_.StartStream(); |
+ } |
// 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_received()) { |
+ // Exception - when using SCTP with a single dictionary, all SPDY CONTROL |
+ // frames are sent on SCTP stream 0, while all SPDY DATA frames are sent on |
+ // SCTP stream n > 0. This means that data can arrive before a SYN_REPLY, |
+ // due to reordering or loss. In this case we can't require response_received |
+ // to be true. |
+ if (!response_received() && |
+ !(using_sctp() && using_sctp_control_stream())) { |
+ printf("SpdyStream::OnDataReceived: closing stream %d\n", stream_id_); |
session_->CloseStream(stream_id_, ERR_SYN_REPLY_NOT_RECEIVED); |
return; |
} |
@@ -314,8 +352,19 @@ |
CHECK(!closed()); |
// A zero-length read means that the stream is being closed. |
- if (!length) { |
+ // Exception - if using SCTP and sending all SPDY control framed on SCTP |
+ // stream 0, we can't close the stream if we haven't received the SYN_REPLY |
+ // yet. |
+ if (!length && using_sctp() && using_sctp_control_stream() && |
+ !syn_reply_received()) { |
+ printf("SpdyStream::OnDataReceived: marking stream %d as ** close_pending " |
+ "*** because !length.\n", stream_id_); |
+ set_close_pending(); // mark stream for closure once SYN_REPLY arrives. |
+ return; |
+ } else if (!length) { |
metrics_.StopStream(); |
+ printf("SpdyStream::OnDataReceived: closing stream %d because !length.\n", |
+ stream_id_); |
session_->CloseStream(stream_id_, net::OK); |
// Note: |this| may be deleted after calling CloseStream. |
return; |