Index: net/spdy/spdy_session.cc |
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc |
index 760e4e330054888836fe3fc06ceef94e462e7c41..343cf9fa84b1ab23d41ee77df332cde93e6878ad 100644 |
--- a/net/spdy/spdy_session.cc |
+++ b/net/spdy/spdy_session.cc |
@@ -753,74 +753,82 @@ scoped_ptr<SpdyBuffer> SpdySession::CreateDataBuffer(SpdyStreamId stream_id, |
return scoped_ptr<SpdyBuffer>(); |
} |
- if (len > kMaxSpdyFrameChunkSize) { |
- len = kMaxSpdyFrameChunkSize; |
- flags = static_cast<SpdyDataFlags>(flags & ~DATA_FLAG_FIN); |
+ int effective_len = std::min(len, kMaxSpdyFrameChunkSize); |
+ |
+ bool send_stalled_by_stream = false; |
+ if (flow_control_state_ >= FLOW_CONTROL_STREAM) { |
+ send_stalled_by_stream = (stream->send_window_size() <= 0); |
+ UMA_HISTOGRAM_BOOLEAN("Net.SpdyDataFrameSendStalledByStream", |
+ send_stalled_by_stream); |
+ } |
+ |
+ if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) { |
+ UMA_HISTOGRAM_BOOLEAN("Net.SpdyDataFrameSendStalledBySession", |
+ IsSendStalled()); |
} |
- // Obey send window size of the stream (and session, if applicable) |
- // if flow control is enabled. |
+ // Obey send window size of the stream if stream flow control is |
+ // enabled. |
if (flow_control_state_ >= FLOW_CONTROL_STREAM) { |
- int32 effective_window_size = stream->send_window_size(); |
- if (effective_window_size <= 0) { |
- // Because we queue frames onto the session, it is possible that |
- // a stream was not flow controlled at the time it attempted the |
- // write, but when we go to fulfill the write, it is now flow |
- // controlled. This is why we need the session to mark the stream |
- // as stalled - because only the session knows for sure when the |
- // stall occurs. |
+ if (send_stalled_by_stream) { |
stream->set_send_stalled_by_flow_control(true); |
net_log().AddEvent( |
- NetLog::TYPE_SPDY_SESSION_STREAM_STALLED_ON_STREAM_SEND_WINDOW, |
+ NetLog::TYPE_SPDY_SESSION_STREAM_STALLED_BY_STREAM_SEND_WINDOW, |
NetLog::IntegerCallback("stream_id", stream_id)); |
return scoped_ptr<SpdyBuffer>(); |
} |
- if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) { |
- effective_window_size = |
- std::min(effective_window_size, session_send_window_size_); |
- if (effective_window_size <= 0) { |
- DCHECK(IsSendStalled()); |
- stream->set_send_stalled_by_flow_control(true); |
- QueueSendStalledStream(stream); |
- net_log().AddEvent( |
- NetLog::TYPE_SPDY_SESSION_STREAM_STALLED_ON_SESSION_SEND_WINDOW, |
- NetLog::IntegerCallback("stream_id", stream_id)); |
- return scoped_ptr<SpdyBuffer>(); |
- } |
- } |
- int new_len = std::min(len, effective_window_size); |
- if (new_len < len) { |
- len = new_len; |
- flags = static_cast<SpdyDataFlags>(flags & ~DATA_FLAG_FIN); |
+ effective_len = std::min(effective_len, stream->send_window_size()); |
+ } |
+ |
+ // Obey send window size of the session if session flow control is |
+ // enabled. |
+ if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) { |
+ if (IsSendStalled()) { |
+ stream->set_send_stalled_by_flow_control(true); |
+ QueueSendStalledStream(stream); |
+ net_log().AddEvent( |
+ NetLog::TYPE_SPDY_SESSION_STREAM_STALLED_BY_SESSION_SEND_WINDOW, |
+ NetLog::IntegerCallback("stream_id", stream_id)); |
+ return scoped_ptr<SpdyBuffer>(); |
} |
+ |
+ effective_len = std::min(effective_len, session_send_window_size_); |
} |
+ DCHECK_GE(effective_len, 0); |
+ |
+ // Clear FIN flag if only some of the data will be in the data |
+ // frame. |
+ if (effective_len < len) |
+ flags = static_cast<SpdyDataFlags>(flags & ~DATA_FLAG_FIN); |
+ |
if (net_log().IsLoggingAllEvents()) { |
net_log().AddEvent( |
NetLog::TYPE_SPDY_SESSION_SEND_DATA, |
- base::Bind(&NetLogSpdyDataCallback, stream_id, len, |
+ base::Bind(&NetLogSpdyDataCallback, stream_id, effective_len, |
(flags & DATA_FLAG_FIN) != 0)); |
} |
// Send PrefacePing for DATA_FRAMEs with nonzero payload size. |
- if (len > 0) |
+ if (effective_len > 0) |
SendPrefacePingIfNoneInFlight(); |
// TODO(mbelshe): reduce memory copies here. |
DCHECK(buffered_spdy_framer_.get()); |
scoped_ptr<SpdyFrame> frame( |
buffered_spdy_framer_->CreateDataFrame( |
- stream_id, data->data(), static_cast<uint32>(len), flags)); |
+ stream_id, data->data(), |
+ static_cast<uint32>(effective_len), flags)); |
scoped_ptr<SpdyBuffer> data_buffer(new SpdyBuffer(frame.Pass())); |
if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) { |
- DecreaseSendWindowSize(static_cast<int32>(len)); |
+ DecreaseSendWindowSize(static_cast<int32>(effective_len)); |
data_buffer->AddConsumeCallback( |
base::Bind(&SpdySession::OnWriteBufferConsumed, |
weak_factory_.GetWeakPtr(), |
- static_cast<size_t>(len))); |
+ static_cast<size_t>(effective_len))); |
} |
return data_buffer.Pass(); |