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 |