| 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;
|
|
|