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 = false; |
| 759 if (flow_control_state_ >= FLOW_CONTROL_STREAM) { |
| 760 send_stalled_by_stream = (stream->send_window_size() <= 0); |
| 761 UMA_HISTOGRAM_BOOLEAN("Net.SpdyDataFrameSendStalledByStream", |
| 762 send_stalled_by_stream); |
759 } | 763 } |
760 | 764 |
761 // Obey send window size of the stream (and session, if applicable) | 765 if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) { |
762 // if flow control is enabled. | 766 UMA_HISTOGRAM_BOOLEAN("Net.SpdyDataFrameSendStalledBySession", |
| 767 IsSendStalled()); |
| 768 } |
| 769 |
| 770 // Obey send window size of the stream if stream flow control is |
| 771 // enabled. |
763 if (flow_control_state_ >= FLOW_CONTROL_STREAM) { | 772 if (flow_control_state_ >= FLOW_CONTROL_STREAM) { |
764 int32 effective_window_size = stream->send_window_size(); | 773 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); | 774 stream->set_send_stalled_by_flow_control(true); |
773 net_log().AddEvent( | 775 net_log().AddEvent( |
774 NetLog::TYPE_SPDY_SESSION_STREAM_STALLED_ON_STREAM_SEND_WINDOW, | 776 NetLog::TYPE_SPDY_SESSION_STREAM_STALLED_BY_STREAM_SEND_WINDOW, |
775 NetLog::IntegerCallback("stream_id", stream_id)); | 777 NetLog::IntegerCallback("stream_id", stream_id)); |
776 return scoped_ptr<SpdyBuffer>(); | 778 return scoped_ptr<SpdyBuffer>(); |
777 } | 779 } |
778 if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) { | 780 |
779 effective_window_size = | 781 effective_len = std::min(effective_len, stream->send_window_size()); |
780 std::min(effective_window_size, session_send_window_size_); | 782 } |
781 if (effective_window_size <= 0) { | 783 |
782 DCHECK(IsSendStalled()); | 784 // Obey send window size of the session if session flow control is |
783 stream->set_send_stalled_by_flow_control(true); | 785 // enabled. |
784 QueueSendStalledStream(stream); | 786 if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) { |
785 net_log().AddEvent( | 787 if (IsSendStalled()) { |
786 NetLog::TYPE_SPDY_SESSION_STREAM_STALLED_ON_SESSION_SEND_WINDOW, | 788 stream->set_send_stalled_by_flow_control(true); |
787 NetLog::IntegerCallback("stream_id", stream_id)); | 789 QueueSendStalledStream(stream); |
788 return scoped_ptr<SpdyBuffer>(); | 790 net_log().AddEvent( |
789 } | 791 NetLog::TYPE_SPDY_SESSION_STREAM_STALLED_BY_SESSION_SEND_WINDOW, |
| 792 NetLog::IntegerCallback("stream_id", stream_id)); |
| 793 return scoped_ptr<SpdyBuffer>(); |
790 } | 794 } |
791 | 795 |
792 int new_len = std::min(len, effective_window_size); | 796 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 } | 797 } |
798 | 798 |
| 799 DCHECK_GE(effective_len, 0); |
| 800 |
| 801 // Clear FIN flag if only some of the data will be in the data |
| 802 // frame. |
| 803 if (effective_len < len) |
| 804 flags = static_cast<SpdyDataFlags>(flags & ~DATA_FLAG_FIN); |
| 805 |
799 if (net_log().IsLoggingAllEvents()) { | 806 if (net_log().IsLoggingAllEvents()) { |
800 net_log().AddEvent( | 807 net_log().AddEvent( |
801 NetLog::TYPE_SPDY_SESSION_SEND_DATA, | 808 NetLog::TYPE_SPDY_SESSION_SEND_DATA, |
802 base::Bind(&NetLogSpdyDataCallback, stream_id, len, | 809 base::Bind(&NetLogSpdyDataCallback, stream_id, effective_len, |
803 (flags & DATA_FLAG_FIN) != 0)); | 810 (flags & DATA_FLAG_FIN) != 0)); |
804 } | 811 } |
805 | 812 |
806 // Send PrefacePing for DATA_FRAMEs with nonzero payload size. | 813 // Send PrefacePing for DATA_FRAMEs with nonzero payload size. |
807 if (len > 0) | 814 if (effective_len > 0) |
808 SendPrefacePingIfNoneInFlight(); | 815 SendPrefacePingIfNoneInFlight(); |
809 | 816 |
810 // TODO(mbelshe): reduce memory copies here. | 817 // TODO(mbelshe): reduce memory copies here. |
811 DCHECK(buffered_spdy_framer_.get()); | 818 DCHECK(buffered_spdy_framer_.get()); |
812 scoped_ptr<SpdyFrame> frame( | 819 scoped_ptr<SpdyFrame> frame( |
813 buffered_spdy_framer_->CreateDataFrame( | 820 buffered_spdy_framer_->CreateDataFrame( |
814 stream_id, data->data(), static_cast<uint32>(len), flags)); | 821 stream_id, data->data(), |
| 822 static_cast<uint32>(effective_len), flags)); |
815 | 823 |
816 scoped_ptr<SpdyBuffer> data_buffer(new SpdyBuffer(frame.Pass())); | 824 scoped_ptr<SpdyBuffer> data_buffer(new SpdyBuffer(frame.Pass())); |
817 | 825 |
818 if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) { | 826 if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) { |
819 DecreaseSendWindowSize(static_cast<int32>(len)); | 827 DecreaseSendWindowSize(static_cast<int32>(effective_len)); |
820 data_buffer->AddConsumeCallback( | 828 data_buffer->AddConsumeCallback( |
821 base::Bind(&SpdySession::OnWriteBufferConsumed, | 829 base::Bind(&SpdySession::OnWriteBufferConsumed, |
822 weak_factory_.GetWeakPtr(), | 830 weak_factory_.GetWeakPtr(), |
823 static_cast<size_t>(len))); | 831 static_cast<size_t>(effective_len))); |
824 } | 832 } |
825 | 833 |
826 return data_buffer.Pass(); | 834 return data_buffer.Pass(); |
827 } | 835 } |
828 | 836 |
829 void SpdySession::CloseStream(SpdyStreamId stream_id, int status) { | 837 void SpdySession::CloseStream(SpdyStreamId stream_id, int status) { |
830 DCHECK_NE(0u, stream_id); | 838 DCHECK_NE(0u, stream_id); |
831 // TODO(mbelshe): We should send a RST_STREAM control frame here | 839 // TODO(mbelshe): We should send a RST_STREAM control frame here |
832 // so that the server can cancel a large send. | 840 // so that the server can cancel a large send. |
833 | 841 |
(...skipping 1533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2367 if (!queue->empty()) { | 2375 if (!queue->empty()) { |
2368 SpdyStreamId stream_id = queue->front(); | 2376 SpdyStreamId stream_id = queue->front(); |
2369 queue->pop_front(); | 2377 queue->pop_front(); |
2370 return stream_id; | 2378 return stream_id; |
2371 } | 2379 } |
2372 } | 2380 } |
2373 return 0; | 2381 return 0; |
2374 } | 2382 } |
2375 | 2383 |
2376 } // namespace net | 2384 } // namespace net |
OLD | NEW |