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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
52 | 52 |
53 namespace { | 53 namespace { |
54 | 54 |
55 const int kReadBufferSize = 8 * 1024; | 55 const int kReadBufferSize = 8 * 1024; |
56 const int kDefaultConnectionAtRiskOfLossSeconds = 10; | 56 const int kDefaultConnectionAtRiskOfLossSeconds = 10; |
57 const int kHungIntervalSeconds = 10; | 57 const int kHungIntervalSeconds = 10; |
58 | 58 |
59 // Minimum seconds that unclaimed pushed streams will be kept in memory. | 59 // Minimum seconds that unclaimed pushed streams will be kept in memory. |
60 const int kMinPushedStreamLifetimeSeconds = 300; | 60 const int kMinPushedStreamLifetimeSeconds = 300; |
61 | 61 |
| 62 // Field trial constants |
| 63 const char kSpdyDependenciesFieldTrial[] = "SpdyEnableDependencies"; |
| 64 const char kSpdyDepencenciesFieldTrialEnable[] = "Enable"; |
| 65 |
| 66 // Whether the creation of SPDY dependencies based on priority is |
| 67 // enabled by default. |
| 68 static bool priority_dependency_enabled_default = false; |
| 69 |
62 scoped_ptr<base::ListValue> SpdyHeaderBlockToListValue( | 70 scoped_ptr<base::ListValue> SpdyHeaderBlockToListValue( |
63 const SpdyHeaderBlock& headers, | 71 const SpdyHeaderBlock& headers, |
64 NetLogCaptureMode capture_mode) { | 72 NetLogCaptureMode capture_mode) { |
65 scoped_ptr<base::ListValue> headers_list(new base::ListValue()); | 73 scoped_ptr<base::ListValue> headers_list(new base::ListValue()); |
66 for (SpdyHeaderBlock::const_iterator it = headers.begin(); | 74 for (SpdyHeaderBlock::const_iterator it = headers.begin(); |
67 it != headers.end(); ++it) { | 75 it != headers.end(); ++it) { |
68 headers_list->AppendString( | 76 headers_list->AppendString( |
69 it->first.as_string() + ": " + | 77 it->first.as_string() + ": " + |
70 ElideHeaderValueForNetLog(capture_mode, it->first.as_string(), | 78 ElideHeaderValueForNetLog(capture_mode, it->first.as_string(), |
71 it->second.as_string())); | 79 it->second.as_string())); |
(...skipping 612 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
684 enable_sending_initial_data_(enable_sending_initial_data), | 692 enable_sending_initial_data_(enable_sending_initial_data), |
685 enable_compression_(enable_compression), | 693 enable_compression_(enable_compression), |
686 enable_ping_based_connection_checking_( | 694 enable_ping_based_connection_checking_( |
687 enable_ping_based_connection_checking), | 695 enable_ping_based_connection_checking), |
688 protocol_(default_protocol), | 696 protocol_(default_protocol), |
689 connection_at_risk_of_loss_time_( | 697 connection_at_risk_of_loss_time_( |
690 base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)), | 698 base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)), |
691 hung_interval_(base::TimeDelta::FromSeconds(kHungIntervalSeconds)), | 699 hung_interval_(base::TimeDelta::FromSeconds(kHungIntervalSeconds)), |
692 trusted_spdy_proxy_(trusted_spdy_proxy), | 700 trusted_spdy_proxy_(trusted_spdy_proxy), |
693 time_func_(time_func), | 701 time_func_(time_func), |
| 702 send_priority_dependency_(priority_dependency_enabled_default), |
694 weak_factory_(this) { | 703 weak_factory_(this) { |
695 DCHECK_GE(protocol_, kProtoSPDYMinimumVersion); | 704 DCHECK_GE(protocol_, kProtoSPDYMinimumVersion); |
696 DCHECK_LE(protocol_, kProtoSPDYMaximumVersion); | 705 DCHECK_LE(protocol_, kProtoSPDYMaximumVersion); |
697 DCHECK(HttpStreamFactory::spdy_enabled()); | 706 DCHECK(HttpStreamFactory::spdy_enabled()); |
698 net_log_.BeginEvent( | 707 net_log_.BeginEvent( |
699 NetLog::TYPE_HTTP2_SESSION, | 708 NetLog::TYPE_HTTP2_SESSION, |
700 base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair())); | 709 base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair())); |
701 next_unclaimed_push_stream_sweep_time_ = time_func_() + | 710 next_unclaimed_push_stream_sweep_time_ = time_func_() + |
702 base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds); | 711 base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds); |
| 712 if (base::FieldTrialList::FindFullName(kSpdyDependenciesFieldTrial) == |
| 713 kSpdyDepencenciesFieldTrialEnable) { |
| 714 send_priority_dependency_ = true; |
| 715 } |
703 // TODO(mbelshe): consider randomization of the stream_hi_water_mark. | 716 // TODO(mbelshe): consider randomization of the stream_hi_water_mark. |
704 } | 717 } |
705 | 718 |
706 SpdySession::~SpdySession() { | 719 SpdySession::~SpdySession() { |
707 CHECK(!in_io_loop_); | 720 CHECK(!in_io_loop_); |
708 DcheckDraining(); | 721 DcheckDraining(); |
709 | 722 |
710 // TODO(akalin): Check connection->is_initialized() instead. This | 723 // TODO(akalin): Check connection->is_initialized() instead. This |
711 // requires re-working CreateFakeSpdySession(), though. | 724 // requires re-working CreateFakeSpdySession(), though. |
712 DCHECK(connection_->socket()); | 725 DCHECK(connection_->socket()); |
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1038 bool SpdySession::CloseOneIdleConnection() { | 1051 bool SpdySession::CloseOneIdleConnection() { |
1039 CHECK(!in_io_loop_); | 1052 CHECK(!in_io_loop_); |
1040 DCHECK(pool_); | 1053 DCHECK(pool_); |
1041 if (active_streams_.empty()) { | 1054 if (active_streams_.empty()) { |
1042 DoDrainSession(ERR_CONNECTION_CLOSED, "Closing idle connection."); | 1055 DoDrainSession(ERR_CONNECTION_CLOSED, "Closing idle connection."); |
1043 } | 1056 } |
1044 // Return false as the socket wasn't immediately closed. | 1057 // Return false as the socket wasn't immediately closed. |
1045 return false; | 1058 return false; |
1046 } | 1059 } |
1047 | 1060 |
| 1061 // static |
| 1062 void SpdySession::SetPriorityDependencyDefaultForTesting(bool enable) { |
| 1063 priority_dependency_enabled_default = enable; |
| 1064 } |
| 1065 |
1048 void SpdySession::EnqueueStreamWrite( | 1066 void SpdySession::EnqueueStreamWrite( |
1049 const base::WeakPtr<SpdyStream>& stream, | 1067 const base::WeakPtr<SpdyStream>& stream, |
1050 SpdyFrameType frame_type, | 1068 SpdyFrameType frame_type, |
1051 scoped_ptr<SpdyBufferProducer> producer) { | 1069 scoped_ptr<SpdyBufferProducer> producer) { |
1052 DCHECK(frame_type == HEADERS || | 1070 DCHECK(frame_type == HEADERS || |
1053 frame_type == DATA || | 1071 frame_type == DATA || |
1054 frame_type == CREDENTIAL || | 1072 frame_type == CREDENTIAL || |
1055 frame_type == SYN_STREAM); | 1073 frame_type == SYN_STREAM); |
1056 EnqueueWrite(stream->priority(), frame_type, producer.Pass(), stream); | 1074 EnqueueWrite(stream->priority(), frame_type, producer.Pass(), stream); |
1057 } | 1075 } |
(...skipping 20 matching lines...) Expand all Loading... |
1078 syn_stream.set_associated_to_stream_id(0); | 1096 syn_stream.set_associated_to_stream_id(0); |
1079 syn_stream.set_priority(spdy_priority); | 1097 syn_stream.set_priority(spdy_priority); |
1080 syn_stream.set_fin((flags & CONTROL_FLAG_FIN) != 0); | 1098 syn_stream.set_fin((flags & CONTROL_FLAG_FIN) != 0); |
1081 syn_stream.set_unidirectional((flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0); | 1099 syn_stream.set_unidirectional((flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0); |
1082 syn_stream.set_header_block(block); | 1100 syn_stream.set_header_block(block); |
1083 syn_frame.reset(buffered_spdy_framer_->SerializeFrame(syn_stream)); | 1101 syn_frame.reset(buffered_spdy_framer_->SerializeFrame(syn_stream)); |
1084 } else { | 1102 } else { |
1085 SpdyHeadersIR headers(stream_id); | 1103 SpdyHeadersIR headers(stream_id); |
1086 headers.set_priority(spdy_priority); | 1104 headers.set_priority(spdy_priority); |
1087 headers.set_has_priority(true); | 1105 headers.set_has_priority(true); |
| 1106 |
| 1107 if (send_priority_dependency_) { |
| 1108 // Set dependencies to reflect request priority. A newly created |
| 1109 // stream should be dependent on the most recent previously created |
| 1110 // stream of the same priority level. The newly created stream |
| 1111 // should also have all streams of a lower priority level dependent |
| 1112 // on it, which is guaranteed by setting the exclusive bit. |
| 1113 // |
| 1114 // Note that this depends on stream ids being allocated in a monotonically |
| 1115 // increasing fashion, and on all streams in |
| 1116 // active_streams_{,by_priority_} having stream ids set. |
| 1117 for (int i = priority; i >= IDLE; --i) { |
| 1118 if (active_streams_by_priority_[i].empty()) |
| 1119 continue; |
| 1120 |
| 1121 auto candidate_it = active_streams_by_priority_[i].rbegin(); |
| 1122 |
| 1123 // |active_streams_by_priority_| is updated before the |
| 1124 // SYN stream frame is created, so the current streams |
| 1125 // id is already on the list. Skip over it, skipping this |
| 1126 // priority level if it's singular. |
| 1127 if (candidate_it->second->stream_id() == stream_id) |
| 1128 ++candidate_it; |
| 1129 if (candidate_it == active_streams_by_priority_[i].rend()) |
| 1130 continue; |
| 1131 |
| 1132 headers.set_parent_stream_id(candidate_it->second->stream_id()); |
| 1133 break; |
| 1134 } |
| 1135 |
| 1136 // If there are no streams of priority <= the current stream, the |
| 1137 // current stream will default to a child of the idle node (0). |
| 1138 headers.set_exclusive(true); |
| 1139 } |
| 1140 |
1088 headers.set_fin((flags & CONTROL_FLAG_FIN) != 0); | 1141 headers.set_fin((flags & CONTROL_FLAG_FIN) != 0); |
1089 headers.set_header_block(block); | 1142 headers.set_header_block(block); |
1090 syn_frame.reset(buffered_spdy_framer_->SerializeFrame(headers)); | 1143 syn_frame.reset(buffered_spdy_framer_->SerializeFrame(headers)); |
1091 } | 1144 } |
1092 | 1145 |
1093 streams_initiated_count_++; | 1146 streams_initiated_count_++; |
1094 | 1147 |
1095 if (net_log().IsCapturing()) { | 1148 if (net_log().IsCapturing()) { |
1096 const NetLog::EventType type = | 1149 const NetLog::EventType type = |
1097 (GetProtocolVersion() <= SPDY3) | 1150 (GetProtocolVersion() <= SPDY3) |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1284 return LOAD_STATE_IDLE; | 1337 return LOAD_STATE_IDLE; |
1285 } | 1338 } |
1286 | 1339 |
1287 void SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it, | 1340 void SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it, |
1288 int status) { | 1341 int status) { |
1289 // TODO(mbelshe): We should send a RST_STREAM control frame here | 1342 // TODO(mbelshe): We should send a RST_STREAM control frame here |
1290 // so that the server can cancel a large send. | 1343 // so that the server can cancel a large send. |
1291 | 1344 |
1292 scoped_ptr<SpdyStream> owned_stream(it->second.stream); | 1345 scoped_ptr<SpdyStream> owned_stream(it->second.stream); |
1293 active_streams_.erase(it); | 1346 active_streams_.erase(it); |
| 1347 active_streams_by_priority_[owned_stream->priority()].erase( |
| 1348 owned_stream->stream_id()); |
1294 | 1349 |
1295 // TODO(akalin): When SpdyStream was ref-counted (and | 1350 // TODO(akalin): When SpdyStream was ref-counted (and |
1296 // |unclaimed_pushed_streams_| held scoped_refptr<SpdyStream>), this | 1351 // |unclaimed_pushed_streams_| held scoped_refptr<SpdyStream>), this |
1297 // was only done when status was not OK. This meant that pushed | 1352 // was only done when status was not OK. This meant that pushed |
1298 // streams can still be claimed after they're closed. This is | 1353 // streams can still be claimed after they're closed. This is |
1299 // probably something that we still want to support, although server | 1354 // probably something that we still want to support, although server |
1300 // push is hardly used. Write tests for this and fix this. (See | 1355 // push is hardly used. Write tests for this and fix this. (See |
1301 // http://crbug.com/261712 .) | 1356 // http://crbug.com/261712 .) |
1302 if (owned_stream->type() == SPDY_PUSH_STREAM) { | 1357 if (owned_stream->type() == SPDY_PUSH_STREAM) { |
1303 unclaimed_pushed_streams_.erase(owned_stream->url()); | 1358 unclaimed_pushed_streams_.erase(owned_stream->url()); |
(...skipping 641 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1945 created_streams_.erase(stream); | 2000 created_streams_.erase(stream); |
1946 return owned_stream.Pass(); | 2001 return owned_stream.Pass(); |
1947 } | 2002 } |
1948 | 2003 |
1949 void SpdySession::InsertActivatedStream(scoped_ptr<SpdyStream> stream) { | 2004 void SpdySession::InsertActivatedStream(scoped_ptr<SpdyStream> stream) { |
1950 SpdyStreamId stream_id = stream->stream_id(); | 2005 SpdyStreamId stream_id = stream->stream_id(); |
1951 CHECK_NE(stream_id, 0u); | 2006 CHECK_NE(stream_id, 0u); |
1952 std::pair<ActiveStreamMap::iterator, bool> result = | 2007 std::pair<ActiveStreamMap::iterator, bool> result = |
1953 active_streams_.insert( | 2008 active_streams_.insert( |
1954 std::make_pair(stream_id, ActiveStreamInfo(stream.get()))); | 2009 std::make_pair(stream_id, ActiveStreamInfo(stream.get()))); |
| 2010 active_streams_by_priority_[stream->priority()].insert( |
| 2011 std::make_pair(stream_id, stream.get())); |
1955 CHECK(result.second); | 2012 CHECK(result.second); |
1956 ignore_result(stream.release()); | 2013 ignore_result(stream.release()); |
1957 } | 2014 } |
1958 | 2015 |
1959 void SpdySession::DeleteStream(scoped_ptr<SpdyStream> stream, int status) { | 2016 void SpdySession::DeleteStream(scoped_ptr<SpdyStream> stream, int status) { |
1960 if (in_flight_write_stream_.get() == stream.get()) { | 2017 if (in_flight_write_stream_.get() == stream.get()) { |
1961 // If we're deleting the stream for the in-flight write, we still | 2018 // If we're deleting the stream for the in-flight write, we still |
1962 // need to let the write complete, so we clear | 2019 // need to let the write complete, so we clear |
1963 // |in_flight_write_stream_| and let the write finish on its own | 2020 // |in_flight_write_stream_| and let the write finish on its own |
1964 // without notifying |in_flight_write_stream_|. | 2021 // without notifying |in_flight_write_stream_|. |
(...skipping 1312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3277 if (!queue->empty()) { | 3334 if (!queue->empty()) { |
3278 SpdyStreamId stream_id = queue->front(); | 3335 SpdyStreamId stream_id = queue->front(); |
3279 queue->pop_front(); | 3336 queue->pop_front(); |
3280 return stream_id; | 3337 return stream_id; |
3281 } | 3338 } |
3282 } | 3339 } |
3283 return 0; | 3340 return 0; |
3284 } | 3341 } |
3285 | 3342 |
3286 } // namespace net | 3343 } // namespace net |
OLD | NEW |