| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/spdy/spdy_session.h" | 5 #include "net/spdy/spdy_session.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <map> | 8 #include <map> |
| 9 | 9 |
| 10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
| (...skipping 735 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 746 // Find our stream. | 746 // Find our stream. |
| 747 CHECK(IsStreamActive(stream_id)); | 747 CHECK(IsStreamActive(stream_id)); |
| 748 scoped_refptr<SpdyStream> stream = active_streams_[stream_id]; | 748 scoped_refptr<SpdyStream> stream = active_streams_[stream_id]; |
| 749 CHECK_EQ(stream->stream_id(), stream_id); | 749 CHECK_EQ(stream->stream_id(), stream_id); |
| 750 | 750 |
| 751 if (len < 0) { | 751 if (len < 0) { |
| 752 NOTREACHED(); | 752 NOTREACHED(); |
| 753 return scoped_ptr<SpdyBuffer>(); | 753 return scoped_ptr<SpdyBuffer>(); |
| 754 } | 754 } |
| 755 | 755 |
| 756 if (len > kMaxSpdyFrameChunkSize) { | 756 int effective_len = std::min(len, kMaxSpdyFrameChunkSize); |
| 757 len = kMaxSpdyFrameChunkSize; | 757 |
| 758 flags = static_cast<SpdyDataFlags>(flags & ~DATA_FLAG_FIN); | 758 bool send_stalled_by_stream = |
| 759 (flow_control_state_ >= FLOW_CONTROL_STREAM) && |
| 760 (stream->send_window_size() <= 0); |
| 761 bool send_stalled_by_session = IsSendStalled(); |
| 762 |
| 763 // NOTE: There's an enum of the same name in histograms.xml. |
| 764 enum SpdyFrameFlowControlState { |
| 765 SEND_NOT_STALLED, |
| 766 SEND_STALLED_BY_STREAM, |
| 767 SEND_STALLED_BY_SESSION, |
| 768 SEND_STALLED_BY_STREAM_AND_SESSION, |
| 769 }; |
| 770 |
| 771 SpdyFrameFlowControlState frame_flow_control_state = SEND_NOT_STALLED; |
| 772 if (send_stalled_by_stream) { |
| 773 if (send_stalled_by_session) { |
| 774 frame_flow_control_state = SEND_STALLED_BY_STREAM_AND_SESSION; |
| 775 } else { |
| 776 frame_flow_control_state = SEND_STALLED_BY_STREAM; |
| 777 } |
| 778 } else if (send_stalled_by_session) { |
| 779 frame_flow_control_state = SEND_STALLED_BY_SESSION; |
| 759 } | 780 } |
| 760 | 781 |
| 761 // Obey send window size of the stream (and session, if applicable) | 782 if (flow_control_state_ == FLOW_CONTROL_STREAM) { |
| 762 // if flow control is enabled. | 783 UMA_HISTOGRAM_ENUMERATION( |
| 784 "Net.SpdyFrameStreamFlowControlState", |
| 785 frame_flow_control_state, |
| 786 SEND_STALLED_BY_STREAM + 1); |
| 787 } else if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) { |
| 788 UMA_HISTOGRAM_ENUMERATION( |
| 789 "Net.SpdyFrameStreamAndSessionFlowControlState", |
| 790 frame_flow_control_state, |
| 791 SEND_STALLED_BY_STREAM_AND_SESSION + 1); |
| 792 } |
| 793 |
| 794 // Obey send window size of the stream if stream flow control is |
| 795 // enabled. |
| 763 if (flow_control_state_ >= FLOW_CONTROL_STREAM) { | 796 if (flow_control_state_ >= FLOW_CONTROL_STREAM) { |
| 764 int32 effective_window_size = stream->send_window_size(); | 797 if (send_stalled_by_stream) { |
| 765 if (effective_window_size <= 0) { | |
| 766 // Because we queue frames onto the session, it is possible that | |
| 767 // a stream was not flow controlled at the time it attempted the | |
| 768 // write, but when we go to fulfill the write, it is now flow | |
| 769 // controlled. This is why we need the session to mark the stream | |
| 770 // as stalled - because only the session knows for sure when the | |
| 771 // stall occurs. | |
| 772 stream->set_send_stalled_by_flow_control(true); | 798 stream->set_send_stalled_by_flow_control(true); |
| 773 net_log().AddEvent( | 799 net_log().AddEvent( |
| 774 NetLog::TYPE_SPDY_SESSION_STREAM_STALLED_ON_STREAM_SEND_WINDOW, | 800 NetLog::TYPE_SPDY_SESSION_STREAM_STALLED_BY_STREAM_SEND_WINDOW, |
| 775 NetLog::IntegerCallback("stream_id", stream_id)); | 801 NetLog::IntegerCallback("stream_id", stream_id)); |
| 776 return scoped_ptr<SpdyBuffer>(); | 802 return scoped_ptr<SpdyBuffer>(); |
| 777 } | 803 } |
| 778 if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) { | 804 |
| 779 effective_window_size = | 805 effective_len = std::min(effective_len, stream->send_window_size()); |
| 780 std::min(effective_window_size, session_send_window_size_); | 806 } |
| 781 if (effective_window_size <= 0) { | 807 |
| 782 DCHECK(IsSendStalled()); | 808 // Obey send window size of the session if session flow control is |
| 783 stream->set_send_stalled_by_flow_control(true); | 809 // enabled. |
| 784 QueueSendStalledStream(stream); | 810 if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) { |
| 785 net_log().AddEvent( | 811 if (send_stalled_by_session) { |
| 786 NetLog::TYPE_SPDY_SESSION_STREAM_STALLED_ON_SESSION_SEND_WINDOW, | 812 stream->set_send_stalled_by_flow_control(true); |
| 787 NetLog::IntegerCallback("stream_id", stream_id)); | 813 QueueSendStalledStream(stream); |
| 788 return scoped_ptr<SpdyBuffer>(); | 814 net_log().AddEvent( |
| 789 } | 815 NetLog::TYPE_SPDY_SESSION_STREAM_STALLED_BY_SESSION_SEND_WINDOW, |
| 816 NetLog::IntegerCallback("stream_id", stream_id)); |
| 817 return scoped_ptr<SpdyBuffer>(); |
| 790 } | 818 } |
| 791 | 819 |
| 792 int new_len = std::min(len, effective_window_size); | 820 effective_len = std::min(effective_len, session_send_window_size_); |
| 793 if (new_len < len) { | |
| 794 len = new_len; | |
| 795 flags = static_cast<SpdyDataFlags>(flags & ~DATA_FLAG_FIN); | |
| 796 } | |
| 797 } | 821 } |
| 798 | 822 |
| 823 DCHECK_GE(effective_len, 0); |
| 824 |
| 825 // Clear FIN flag if only some of the data will be in the data |
| 826 // frame. |
| 827 if (effective_len < len) |
| 828 flags = static_cast<SpdyDataFlags>(flags & ~DATA_FLAG_FIN); |
| 829 |
| 799 if (net_log().IsLoggingAllEvents()) { | 830 if (net_log().IsLoggingAllEvents()) { |
| 800 net_log().AddEvent( | 831 net_log().AddEvent( |
| 801 NetLog::TYPE_SPDY_SESSION_SEND_DATA, | 832 NetLog::TYPE_SPDY_SESSION_SEND_DATA, |
| 802 base::Bind(&NetLogSpdyDataCallback, stream_id, len, | 833 base::Bind(&NetLogSpdyDataCallback, stream_id, effective_len, |
| 803 (flags & DATA_FLAG_FIN) != 0)); | 834 (flags & DATA_FLAG_FIN) != 0)); |
| 804 } | 835 } |
| 805 | 836 |
| 806 // Send PrefacePing for DATA_FRAMEs with nonzero payload size. | 837 // Send PrefacePing for DATA_FRAMEs with nonzero payload size. |
| 807 if (len > 0) | 838 if (effective_len > 0) |
| 808 SendPrefacePingIfNoneInFlight(); | 839 SendPrefacePingIfNoneInFlight(); |
| 809 | 840 |
| 810 // TODO(mbelshe): reduce memory copies here. | 841 // TODO(mbelshe): reduce memory copies here. |
| 811 DCHECK(buffered_spdy_framer_.get()); | 842 DCHECK(buffered_spdy_framer_.get()); |
| 812 scoped_ptr<SpdyFrame> frame( | 843 scoped_ptr<SpdyFrame> frame( |
| 813 buffered_spdy_framer_->CreateDataFrame( | 844 buffered_spdy_framer_->CreateDataFrame( |
| 814 stream_id, data->data(), static_cast<uint32>(len), flags)); | 845 stream_id, data->data(), |
| 846 static_cast<uint32>(effective_len), flags)); |
| 815 | 847 |
| 816 scoped_ptr<SpdyBuffer> data_buffer(new SpdyBuffer(frame.Pass())); | 848 scoped_ptr<SpdyBuffer> data_buffer(new SpdyBuffer(frame.Pass())); |
| 817 | 849 |
| 818 if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) { | 850 if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) { |
| 819 DecreaseSendWindowSize(static_cast<int32>(len)); | 851 DecreaseSendWindowSize(static_cast<int32>(effective_len)); |
| 820 data_buffer->AddConsumeCallback( | 852 data_buffer->AddConsumeCallback( |
| 821 base::Bind(&SpdySession::OnWriteBufferConsumed, | 853 base::Bind(&SpdySession::OnWriteBufferConsumed, |
| 822 weak_factory_.GetWeakPtr(), | 854 weak_factory_.GetWeakPtr(), |
| 823 static_cast<size_t>(len))); | 855 static_cast<size_t>(effective_len))); |
| 824 } | 856 } |
| 825 | 857 |
| 826 return data_buffer.Pass(); | 858 return data_buffer.Pass(); |
| 827 } | 859 } |
| 828 | 860 |
| 829 void SpdySession::CloseStream(SpdyStreamId stream_id, int status) { | 861 void SpdySession::CloseStream(SpdyStreamId stream_id, int status) { |
| 830 DCHECK_NE(0u, stream_id); | 862 DCHECK_NE(0u, stream_id); |
| 831 // TODO(mbelshe): We should send a RST_STREAM control frame here | 863 // TODO(mbelshe): We should send a RST_STREAM control frame here |
| 832 // so that the server can cancel a large send. | 864 // so that the server can cancel a large send. |
| 833 | 865 |
| (...skipping 1533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2367 if (!queue->empty()) { | 2399 if (!queue->empty()) { |
| 2368 SpdyStreamId stream_id = queue->front(); | 2400 SpdyStreamId stream_id = queue->front(); |
| 2369 queue->pop_front(); | 2401 queue->pop_front(); |
| 2370 return stream_id; | 2402 return stream_id; |
| 2371 } | 2403 } |
| 2372 } | 2404 } |
| 2373 return 0; | 2405 return 0; |
| 2374 } | 2406 } |
| 2375 | 2407 |
| 2376 } // namespace net | 2408 } // namespace net |
| OLD | NEW |