Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(700)

Side by Side Diff: net/spdy/spdy_session.cc

Issue 1779733003: Fix bug in net::RequestPriority -> HTTP/2 dependency conversion. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Make bi-directional stream unittests enable priority->dependency setting. Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/spdy/spdy_session.h ('k') | net/spdy/spdy_session_pool.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « net/spdy/spdy_session.h ('k') | net/spdy/spdy_session_pool.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698