| 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 |