| 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 <limits> | 8 #include <limits> |
| 9 #include <map> | 9 #include <map> |
| 10 #include <utility> | 10 #include <utility> |
| 11 | 11 |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
| 14 #include "base/location.h" | 14 #include "base/location.h" |
| 15 #include "base/logging.h" | 15 #include "base/logging.h" |
| 16 #include "base/metrics/field_trial.h" | |
| 17 #include "base/metrics/histogram_macros.h" | 16 #include "base/metrics/histogram_macros.h" |
| 18 #include "base/metrics/sparse_histogram.h" | 17 #include "base/metrics/sparse_histogram.h" |
| 19 #include "base/profiler/scoped_tracker.h" | 18 #include "base/profiler/scoped_tracker.h" |
| 20 #include "base/single_thread_task_runner.h" | 19 #include "base/single_thread_task_runner.h" |
| 21 #include "base/stl_util.h" | 20 #include "base/stl_util.h" |
| 22 #include "base/strings/string_number_conversions.h" | 21 #include "base/strings/string_number_conversions.h" |
| 23 #include "base/strings/string_util.h" | 22 #include "base/strings/string_util.h" |
| 24 #include "base/strings/stringprintf.h" | 23 #include "base/strings/stringprintf.h" |
| 25 #include "base/strings/utf_string_conversions.h" | 24 #include "base/strings/utf_string_conversions.h" |
| 26 #include "base/thread_task_runner_handle.h" | 25 #include "base/thread_task_runner_handle.h" |
| (...skipping 27 matching lines...) Expand all Loading... |
| 54 | 53 |
| 55 namespace { | 54 namespace { |
| 56 | 55 |
| 57 const int kReadBufferSize = 8 * 1024; | 56 const int kReadBufferSize = 8 * 1024; |
| 58 const int kDefaultConnectionAtRiskOfLossSeconds = 10; | 57 const int kDefaultConnectionAtRiskOfLossSeconds = 10; |
| 59 const int kHungIntervalSeconds = 10; | 58 const int kHungIntervalSeconds = 10; |
| 60 | 59 |
| 61 // Minimum seconds that unclaimed pushed streams will be kept in memory. | 60 // Minimum seconds that unclaimed pushed streams will be kept in memory. |
| 62 const int kMinPushedStreamLifetimeSeconds = 300; | 61 const int kMinPushedStreamLifetimeSeconds = 300; |
| 63 | 62 |
| 64 // Field trial constants | |
| 65 const char kSpdyDependenciesFieldTrial[] = "SpdyEnableDependencies"; | |
| 66 const char kSpdyDepencenciesFieldTrialEnable[] = "Enable"; | |
| 67 | |
| 68 // Whether the creation of SPDY dependencies based on priority is | |
| 69 // enabled by default. | |
| 70 static bool priority_dependency_enabled_default = false; | |
| 71 | |
| 72 scoped_ptr<base::ListValue> SpdyHeaderBlockToListValue( | 63 scoped_ptr<base::ListValue> SpdyHeaderBlockToListValue( |
| 73 const SpdyHeaderBlock& headers, | 64 const SpdyHeaderBlock& headers, |
| 74 NetLogCaptureMode capture_mode) { | 65 NetLogCaptureMode capture_mode) { |
| 75 scoped_ptr<base::ListValue> headers_list(new base::ListValue()); | 66 scoped_ptr<base::ListValue> headers_list(new base::ListValue()); |
| 76 for (SpdyHeaderBlock::const_iterator it = headers.begin(); | 67 for (SpdyHeaderBlock::const_iterator it = headers.begin(); |
| 77 it != headers.end(); ++it) { | 68 it != headers.end(); ++it) { |
| 78 headers_list->AppendString( | 69 headers_list->AppendString( |
| 79 it->first.as_string() + ": " + | 70 it->first.as_string() + ": " + |
| 80 ElideHeaderValueForNetLog(capture_mode, it->first.as_string(), | 71 ElideHeaderValueForNetLog(capture_mode, it->first.as_string(), |
| 81 it->second.as_string())); | 72 it->second.as_string())); |
| (...skipping 600 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 682 return true; | 673 return true; |
| 683 } | 674 } |
| 684 | 675 |
| 685 SpdySession::SpdySession( | 676 SpdySession::SpdySession( |
| 686 const SpdySessionKey& spdy_session_key, | 677 const SpdySessionKey& spdy_session_key, |
| 687 const base::WeakPtr<HttpServerProperties>& http_server_properties, | 678 const base::WeakPtr<HttpServerProperties>& http_server_properties, |
| 688 TransportSecurityState* transport_security_state, | 679 TransportSecurityState* transport_security_state, |
| 689 bool verify_domain_authentication, | 680 bool verify_domain_authentication, |
| 690 bool enable_sending_initial_data, | 681 bool enable_sending_initial_data, |
| 691 bool enable_ping_based_connection_checking, | 682 bool enable_ping_based_connection_checking, |
| 683 bool enable_priority_dependencies, |
| 692 NextProto default_protocol, | 684 NextProto default_protocol, |
| 693 size_t session_max_recv_window_size, | 685 size_t session_max_recv_window_size, |
| 694 size_t stream_max_recv_window_size, | 686 size_t stream_max_recv_window_size, |
| 695 TimeFunc time_func, | 687 TimeFunc time_func, |
| 696 ProxyDelegate* proxy_delegate, | 688 ProxyDelegate* proxy_delegate, |
| 697 NetLog* net_log) | 689 NetLog* net_log) |
| 698 : in_io_loop_(false), | 690 : in_io_loop_(false), |
| 699 spdy_session_key_(spdy_session_key), | 691 spdy_session_key_(spdy_session_key), |
| 700 pool_(NULL), | 692 pool_(NULL), |
| 701 http_server_properties_(http_server_properties), | 693 http_server_properties_(http_server_properties), |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 741 verify_domain_authentication_(verify_domain_authentication), | 733 verify_domain_authentication_(verify_domain_authentication), |
| 742 enable_sending_initial_data_(enable_sending_initial_data), | 734 enable_sending_initial_data_(enable_sending_initial_data), |
| 743 enable_ping_based_connection_checking_( | 735 enable_ping_based_connection_checking_( |
| 744 enable_ping_based_connection_checking), | 736 enable_ping_based_connection_checking), |
| 745 protocol_(default_protocol), | 737 protocol_(default_protocol), |
| 746 connection_at_risk_of_loss_time_( | 738 connection_at_risk_of_loss_time_( |
| 747 base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)), | 739 base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)), |
| 748 hung_interval_(base::TimeDelta::FromSeconds(kHungIntervalSeconds)), | 740 hung_interval_(base::TimeDelta::FromSeconds(kHungIntervalSeconds)), |
| 749 proxy_delegate_(proxy_delegate), | 741 proxy_delegate_(proxy_delegate), |
| 750 time_func_(time_func), | 742 time_func_(time_func), |
| 751 send_priority_dependency_(priority_dependency_enabled_default), | 743 priority_dependencies_enabled_(enable_priority_dependencies), |
| 752 weak_factory_(this) { | 744 weak_factory_(this) { |
| 753 DCHECK_GE(protocol_, kProtoSPDYMinimumVersion); | 745 DCHECK_GE(protocol_, kProtoSPDYMinimumVersion); |
| 754 DCHECK_LE(protocol_, kProtoSPDYMaximumVersion); | 746 DCHECK_LE(protocol_, kProtoSPDYMaximumVersion); |
| 755 DCHECK(HttpStreamFactory::spdy_enabled()); | 747 DCHECK(HttpStreamFactory::spdy_enabled()); |
| 756 net_log_.BeginEvent( | 748 net_log_.BeginEvent( |
| 757 NetLog::TYPE_HTTP2_SESSION, | 749 NetLog::TYPE_HTTP2_SESSION, |
| 758 base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair())); | 750 base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair())); |
| 759 next_unclaimed_push_stream_sweep_time_ = time_func_() + | 751 next_unclaimed_push_stream_sweep_time_ = time_func_() + |
| 760 base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds); | 752 base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds); |
| 761 if (base::FieldTrialList::FindFullName(kSpdyDependenciesFieldTrial) == | |
| 762 kSpdyDepencenciesFieldTrialEnable) { | |
| 763 send_priority_dependency_ = true; | |
| 764 } | |
| 765 // TODO(mbelshe): consider randomization of the stream_hi_water_mark. | 753 // TODO(mbelshe): consider randomization of the stream_hi_water_mark. |
| 766 } | 754 } |
| 767 | 755 |
| 768 SpdySession::~SpdySession() { | 756 SpdySession::~SpdySession() { |
| 769 CHECK(!in_io_loop_); | 757 CHECK(!in_io_loop_); |
| 770 DcheckDraining(); | 758 DcheckDraining(); |
| 771 | 759 |
| 772 // TODO(akalin): Check connection->is_initialized() instead. This | 760 // TODO(akalin): Check connection->is_initialized() instead. This |
| 773 // requires re-working CreateFakeSpdySession(), though. | 761 // requires re-working CreateFakeSpdySession(), though. |
| 774 DCHECK(connection_->socket()); | 762 DCHECK(connection_->socket()); |
| (...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1084 bool SpdySession::CloseOneIdleConnection() { | 1072 bool SpdySession::CloseOneIdleConnection() { |
| 1085 CHECK(!in_io_loop_); | 1073 CHECK(!in_io_loop_); |
| 1086 DCHECK(pool_); | 1074 DCHECK(pool_); |
| 1087 if (active_streams_.empty()) { | 1075 if (active_streams_.empty()) { |
| 1088 DoDrainSession(ERR_CONNECTION_CLOSED, "Closing idle connection."); | 1076 DoDrainSession(ERR_CONNECTION_CLOSED, "Closing idle connection."); |
| 1089 } | 1077 } |
| 1090 // Return false as the socket wasn't immediately closed. | 1078 // Return false as the socket wasn't immediately closed. |
| 1091 return false; | 1079 return false; |
| 1092 } | 1080 } |
| 1093 | 1081 |
| 1094 // static | |
| 1095 void SpdySession::SetPriorityDependencyDefaultForTesting(bool enable) { | |
| 1096 priority_dependency_enabled_default = enable; | |
| 1097 } | |
| 1098 | |
| 1099 void SpdySession::EnqueueStreamWrite( | 1082 void SpdySession::EnqueueStreamWrite( |
| 1100 const base::WeakPtr<SpdyStream>& stream, | 1083 const base::WeakPtr<SpdyStream>& stream, |
| 1101 SpdyFrameType frame_type, | 1084 SpdyFrameType frame_type, |
| 1102 scoped_ptr<SpdyBufferProducer> producer) { | 1085 scoped_ptr<SpdyBufferProducer> producer) { |
| 1103 DCHECK(frame_type == HEADERS || | 1086 DCHECK(frame_type == HEADERS || |
| 1104 frame_type == DATA || | 1087 frame_type == DATA || |
| 1105 frame_type == SYN_STREAM); | 1088 frame_type == SYN_STREAM); |
| 1106 EnqueueWrite(stream->priority(), frame_type, std::move(producer), stream); | 1089 EnqueueWrite(stream->priority(), frame_type, std::move(producer), stream); |
| 1107 } | 1090 } |
| 1108 | 1091 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1137 base::Bind(&NetLogSpdySynStreamSentCallback, &block, | 1120 base::Bind(&NetLogSpdySynStreamSentCallback, &block, |
| 1138 (flags & CONTROL_FLAG_FIN) != 0, | 1121 (flags & CONTROL_FLAG_FIN) != 0, |
| 1139 (flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0, | 1122 (flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0, |
| 1140 spdy_priority, stream_id)); | 1123 spdy_priority, stream_id)); |
| 1141 } | 1124 } |
| 1142 } else { | 1125 } else { |
| 1143 SpdyHeadersIR headers(stream_id); | 1126 SpdyHeadersIR headers(stream_id); |
| 1144 headers.set_priority(spdy_priority); | 1127 headers.set_priority(spdy_priority); |
| 1145 headers.set_has_priority(true); | 1128 headers.set_has_priority(true); |
| 1146 | 1129 |
| 1147 if (send_priority_dependency_) { | 1130 if (priority_dependencies_enabled_) { |
| 1148 // Set dependencies to reflect request priority. A newly created | 1131 SpdyStreamId dependent_stream_id = 0; |
| 1149 // stream should be dependent on the most recent previously created | 1132 bool exclusive = false; |
| 1150 // stream of the same priority level. The newly created stream | 1133 priority_dependency_state_.OnStreamSynSent( |
| 1151 // should also have all streams of a lower priority level dependent | 1134 stream_id, spdy_priority, &dependent_stream_id, &exclusive); |
| 1152 // on it, which is guaranteed by setting the exclusive bit. | 1135 headers.set_parent_stream_id(dependent_stream_id); |
| 1153 // | 1136 headers.set_exclusive(exclusive); |
| 1154 // Note that this depends on stream ids being allocated in a monotonically | |
| 1155 // increasing fashion, and on all streams in | |
| 1156 // active_streams_{,by_priority_} having stream ids set. | |
| 1157 for (int i = priority; i >= IDLE; --i) { | |
| 1158 if (active_streams_by_priority_[i].empty()) | |
| 1159 continue; | |
| 1160 | |
| 1161 auto candidate_it = active_streams_by_priority_[i].rbegin(); | |
| 1162 | |
| 1163 // |active_streams_by_priority_| is updated before the | |
| 1164 // SYN stream frame is created, so the current streams | |
| 1165 // id is already on the list. Skip over it, skipping this | |
| 1166 // priority level if it's singular. | |
| 1167 if (candidate_it->second->stream_id() == stream_id) | |
| 1168 ++candidate_it; | |
| 1169 if (candidate_it == active_streams_by_priority_[i].rend()) | |
| 1170 continue; | |
| 1171 | |
| 1172 headers.set_parent_stream_id(candidate_it->second->stream_id()); | |
| 1173 break; | |
| 1174 } | |
| 1175 | |
| 1176 // If there are no streams of priority <= the current stream, the | |
| 1177 // current stream will default to a child of the idle node (0). | |
| 1178 headers.set_exclusive(true); | |
| 1179 } | 1137 } |
| 1180 | 1138 |
| 1181 headers.set_fin((flags & CONTROL_FLAG_FIN) != 0); | 1139 headers.set_fin((flags & CONTROL_FLAG_FIN) != 0); |
| 1182 headers.set_header_block(block); | 1140 headers.set_header_block(block); |
| 1183 syn_frame.reset(buffered_spdy_framer_->SerializeFrame(headers)); | 1141 syn_frame.reset(buffered_spdy_framer_->SerializeFrame(headers)); |
| 1184 | 1142 |
| 1185 if (net_log().IsCapturing()) { | 1143 if (net_log().IsCapturing()) { |
| 1186 net_log().AddEvent( | 1144 net_log().AddEvent( |
| 1187 NetLog::TYPE_HTTP2_SESSION_SEND_HEADERS, | 1145 NetLog::TYPE_HTTP2_SESSION_SEND_HEADERS, |
| 1188 base::Bind(&NetLogSpdyHeadersSentCallback, &block, | 1146 base::Bind(&NetLogSpdyHeadersSentCallback, &block, |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1355 return LOAD_STATE_IDLE; | 1313 return LOAD_STATE_IDLE; |
| 1356 } | 1314 } |
| 1357 | 1315 |
| 1358 void SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it, | 1316 void SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it, |
| 1359 int status) { | 1317 int status) { |
| 1360 // TODO(mbelshe): We should send a RST_STREAM control frame here | 1318 // TODO(mbelshe): We should send a RST_STREAM control frame here |
| 1361 // so that the server can cancel a large send. | 1319 // so that the server can cancel a large send. |
| 1362 | 1320 |
| 1363 scoped_ptr<SpdyStream> owned_stream(it->second.stream); | 1321 scoped_ptr<SpdyStream> owned_stream(it->second.stream); |
| 1364 active_streams_.erase(it); | 1322 active_streams_.erase(it); |
| 1365 active_streams_by_priority_[owned_stream->priority()].erase( | 1323 if (priority_dependencies_enabled_) |
| 1366 owned_stream->stream_id()); | 1324 priority_dependency_state_.OnStreamDestruction(owned_stream->stream_id()); |
| 1367 | 1325 |
| 1368 // TODO(akalin): When SpdyStream was ref-counted (and | 1326 // TODO(akalin): When SpdyStream was ref-counted (and |
| 1369 // |unclaimed_pushed_streams_| held scoped_refptr<SpdyStream>), this | 1327 // |unclaimed_pushed_streams_| held scoped_refptr<SpdyStream>), this |
| 1370 // was only done when status was not OK. This meant that pushed | 1328 // was only done when status was not OK. This meant that pushed |
| 1371 // streams can still be claimed after they're closed. This is | 1329 // streams can still be claimed after they're closed. This is |
| 1372 // probably something that we still want to support, although server | 1330 // probably something that we still want to support, although server |
| 1373 // push is hardly used. Write tests for this and fix this. (See | 1331 // push is hardly used. Write tests for this and fix this. (See |
| 1374 // http://crbug.com/261712 .) | 1332 // http://crbug.com/261712 .) |
| 1375 if (owned_stream->type() == SPDY_PUSH_STREAM) { | 1333 if (owned_stream->type() == SPDY_PUSH_STREAM) { |
| 1376 unclaimed_pushed_streams_.erase(owned_stream->url()); | 1334 unclaimed_pushed_streams_.erase(owned_stream->url()); |
| (...skipping 651 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2028 created_streams_.erase(stream); | 1986 created_streams_.erase(stream); |
| 2029 return owned_stream; | 1987 return owned_stream; |
| 2030 } | 1988 } |
| 2031 | 1989 |
| 2032 void SpdySession::InsertActivatedStream(scoped_ptr<SpdyStream> stream) { | 1990 void SpdySession::InsertActivatedStream(scoped_ptr<SpdyStream> stream) { |
| 2033 SpdyStreamId stream_id = stream->stream_id(); | 1991 SpdyStreamId stream_id = stream->stream_id(); |
| 2034 CHECK_NE(stream_id, 0u); | 1992 CHECK_NE(stream_id, 0u); |
| 2035 std::pair<ActiveStreamMap::iterator, bool> result = | 1993 std::pair<ActiveStreamMap::iterator, bool> result = |
| 2036 active_streams_.insert( | 1994 active_streams_.insert( |
| 2037 std::make_pair(stream_id, ActiveStreamInfo(stream.get()))); | 1995 std::make_pair(stream_id, ActiveStreamInfo(stream.get()))); |
| 2038 active_streams_by_priority_[stream->priority()].insert( | |
| 2039 std::make_pair(stream_id, stream.get())); | |
| 2040 CHECK(result.second); | 1996 CHECK(result.second); |
| 2041 ignore_result(stream.release()); | 1997 ignore_result(stream.release()); |
| 2042 } | 1998 } |
| 2043 | 1999 |
| 2044 void SpdySession::DeleteStream(scoped_ptr<SpdyStream> stream, int status) { | 2000 void SpdySession::DeleteStream(scoped_ptr<SpdyStream> stream, int status) { |
| 2045 if (in_flight_write_stream_.get() == stream.get()) { | 2001 if (in_flight_write_stream_.get() == stream.get()) { |
| 2046 // If we're deleting the stream for the in-flight write, we still | 2002 // If we're deleting the stream for the in-flight write, we still |
| 2047 // need to let the write complete, so we clear | 2003 // need to let the write complete, so we clear |
| 2048 // |in_flight_write_stream_| and let the write finish on its own | 2004 // |in_flight_write_stream_| and let the write finish on its own |
| 2049 // without notifying |in_flight_write_stream_|. | 2005 // without notifying |in_flight_write_stream_|. |
| (...skipping 1304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3354 if (!queue->empty()) { | 3310 if (!queue->empty()) { |
| 3355 SpdyStreamId stream_id = queue->front(); | 3311 SpdyStreamId stream_id = queue->front(); |
| 3356 queue->pop_front(); | 3312 queue->pop_front(); |
| 3357 return stream_id; | 3313 return stream_id; |
| 3358 } | 3314 } |
| 3359 } | 3315 } |
| 3360 return 0; | 3316 return 0; |
| 3361 } | 3317 } |
| 3362 | 3318 |
| 3363 } // namespace net | 3319 } // namespace net |
| OLD | NEW |