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

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: Incorporate Bence's detailed comments. 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
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 564 matching lines...) Expand 10 before | Expand all | Expand 10 after
646 return true; 637 return true;
647 } 638 }
648 639
649 SpdySession::SpdySession( 640 SpdySession::SpdySession(
650 const SpdySessionKey& spdy_session_key, 641 const SpdySessionKey& spdy_session_key,
651 const base::WeakPtr<HttpServerProperties>& http_server_properties, 642 const base::WeakPtr<HttpServerProperties>& http_server_properties,
652 TransportSecurityState* transport_security_state, 643 TransportSecurityState* transport_security_state,
653 bool verify_domain_authentication, 644 bool verify_domain_authentication,
654 bool enable_sending_initial_data, 645 bool enable_sending_initial_data,
655 bool enable_ping_based_connection_checking, 646 bool enable_ping_based_connection_checking,
647 bool enable_priority_dependencies,
656 NextProto default_protocol, 648 NextProto default_protocol,
657 size_t session_max_recv_window_size, 649 size_t session_max_recv_window_size,
658 size_t stream_max_recv_window_size, 650 size_t stream_max_recv_window_size,
659 TimeFunc time_func, 651 TimeFunc time_func,
660 ProxyDelegate* proxy_delegate, 652 ProxyDelegate* proxy_delegate,
661 NetLog* net_log) 653 NetLog* net_log)
662 : in_io_loop_(false), 654 : in_io_loop_(false),
663 spdy_session_key_(spdy_session_key), 655 spdy_session_key_(spdy_session_key),
664 pool_(NULL), 656 pool_(NULL),
665 http_server_properties_(http_server_properties), 657 http_server_properties_(http_server_properties),
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
704 verify_domain_authentication_(verify_domain_authentication), 696 verify_domain_authentication_(verify_domain_authentication),
705 enable_sending_initial_data_(enable_sending_initial_data), 697 enable_sending_initial_data_(enable_sending_initial_data),
706 enable_ping_based_connection_checking_( 698 enable_ping_based_connection_checking_(
707 enable_ping_based_connection_checking), 699 enable_ping_based_connection_checking),
708 protocol_(default_protocol), 700 protocol_(default_protocol),
709 connection_at_risk_of_loss_time_( 701 connection_at_risk_of_loss_time_(
710 base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)), 702 base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)),
711 hung_interval_(base::TimeDelta::FromSeconds(kHungIntervalSeconds)), 703 hung_interval_(base::TimeDelta::FromSeconds(kHungIntervalSeconds)),
712 proxy_delegate_(proxy_delegate), 704 proxy_delegate_(proxy_delegate),
713 time_func_(time_func), 705 time_func_(time_func),
714 send_priority_dependency_(priority_dependency_enabled_default), 706 priority_dependencies_enabled_(enable_priority_dependencies),
715 weak_factory_(this) { 707 weak_factory_(this) {
716 DCHECK_GE(protocol_, kProtoSPDYMinimumVersion); 708 DCHECK_GE(protocol_, kProtoSPDYMinimumVersion);
717 DCHECK_LE(protocol_, kProtoSPDYMaximumVersion); 709 DCHECK_LE(protocol_, kProtoSPDYMaximumVersion);
718 DCHECK(HttpStreamFactory::spdy_enabled()); 710 DCHECK(HttpStreamFactory::spdy_enabled());
719 net_log_.BeginEvent( 711 net_log_.BeginEvent(
720 NetLog::TYPE_HTTP2_SESSION, 712 NetLog::TYPE_HTTP2_SESSION,
721 base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair())); 713 base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair()));
722 next_unclaimed_push_stream_sweep_time_ = time_func_() + 714 next_unclaimed_push_stream_sweep_time_ = time_func_() +
723 base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds); 715 base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds);
724 if (base::FieldTrialList::FindFullName(kSpdyDependenciesFieldTrial) ==
725 kSpdyDepencenciesFieldTrialEnable) {
726 send_priority_dependency_ = true;
727 }
728 // TODO(mbelshe): consider randomization of the stream_hi_water_mark. 716 // TODO(mbelshe): consider randomization of the stream_hi_water_mark.
729 } 717 }
730 718
731 SpdySession::~SpdySession() { 719 SpdySession::~SpdySession() {
732 CHECK(!in_io_loop_); 720 CHECK(!in_io_loop_);
733 DcheckDraining(); 721 DcheckDraining();
734 722
735 // TODO(akalin): Check connection->is_initialized() instead. This 723 // TODO(akalin): Check connection->is_initialized() instead. This
736 // requires re-working CreateFakeSpdySession(), though. 724 // requires re-working CreateFakeSpdySession(), though.
737 DCHECK(connection_->socket()); 725 DCHECK(connection_->socket());
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after
1047 bool SpdySession::CloseOneIdleConnection() { 1035 bool SpdySession::CloseOneIdleConnection() {
1048 CHECK(!in_io_loop_); 1036 CHECK(!in_io_loop_);
1049 DCHECK(pool_); 1037 DCHECK(pool_);
1050 if (active_streams_.empty()) { 1038 if (active_streams_.empty()) {
1051 DoDrainSession(ERR_CONNECTION_CLOSED, "Closing idle connection."); 1039 DoDrainSession(ERR_CONNECTION_CLOSED, "Closing idle connection.");
1052 } 1040 }
1053 // Return false as the socket wasn't immediately closed. 1041 // Return false as the socket wasn't immediately closed.
1054 return false; 1042 return false;
1055 } 1043 }
1056 1044
1057 // static
1058 void SpdySession::SetPriorityDependencyDefaultForTesting(bool enable) {
1059 priority_dependency_enabled_default = enable;
1060 }
1061
1062 void SpdySession::EnqueueStreamWrite( 1045 void SpdySession::EnqueueStreamWrite(
1063 const base::WeakPtr<SpdyStream>& stream, 1046 const base::WeakPtr<SpdyStream>& stream,
1064 SpdyFrameType frame_type, 1047 SpdyFrameType frame_type,
1065 scoped_ptr<SpdyBufferProducer> producer) { 1048 scoped_ptr<SpdyBufferProducer> producer) {
1066 DCHECK(frame_type == HEADERS || 1049 DCHECK(frame_type == HEADERS ||
1067 frame_type == DATA || 1050 frame_type == DATA ||
1068 frame_type == SYN_STREAM); 1051 frame_type == SYN_STREAM);
1069 EnqueueWrite(stream->priority(), frame_type, std::move(producer), stream); 1052 EnqueueWrite(stream->priority(), frame_type, std::move(producer), stream);
1070 } 1053 }
1071 1054
(...skipping 28 matching lines...) Expand all
1100 base::Bind(&NetLogSpdySynStreamSentCallback, &block, 1083 base::Bind(&NetLogSpdySynStreamSentCallback, &block,
1101 (flags & CONTROL_FLAG_FIN) != 0, 1084 (flags & CONTROL_FLAG_FIN) != 0,
1102 (flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0, 1085 (flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0,
1103 spdy_priority, stream_id)); 1086 spdy_priority, stream_id));
1104 } 1087 }
1105 } else { 1088 } else {
1106 SpdyHeadersIR headers(stream_id); 1089 SpdyHeadersIR headers(stream_id);
1107 headers.set_priority(spdy_priority); 1090 headers.set_priority(spdy_priority);
1108 headers.set_has_priority(true); 1091 headers.set_has_priority(true);
1109 1092
1110 if (send_priority_dependency_) { 1093 if (priority_dependencies_enabled_) {
1111 // Set dependencies to reflect request priority. A newly created 1094 SpdyStreamId dependent_stream_id = 0;
1112 // stream should be dependent on the most recent previously created 1095 bool exclusive = false;
1113 // stream of the same priority level. The newly created stream 1096 priority_dependency_state_.OnStreamSynSent(
1114 // should also have all streams of a lower priority level dependent 1097 stream_id, spdy_priority, &dependent_stream_id, &exclusive);
1115 // on it, which is guaranteed by setting the exclusive bit. 1098 headers.set_parent_stream_id(dependent_stream_id);
1116 // 1099 headers.set_exclusive(exclusive);
1117 // Note that this depends on stream ids being allocated in a monotonically
1118 // increasing fashion, and on all streams in
1119 // active_streams_{,by_priority_} having stream ids set.
1120 for (int i = priority; i >= IDLE; --i) {
1121 if (active_streams_by_priority_[i].empty())
1122 continue;
1123
1124 auto candidate_it = active_streams_by_priority_[i].rbegin();
1125
1126 // |active_streams_by_priority_| is updated before the
1127 // SYN stream frame is created, so the current streams
1128 // id is already on the list. Skip over it, skipping this
1129 // priority level if it's singular.
1130 if (candidate_it->second->stream_id() == stream_id)
1131 ++candidate_it;
1132 if (candidate_it == active_streams_by_priority_[i].rend())
1133 continue;
1134
1135 headers.set_parent_stream_id(candidate_it->second->stream_id());
1136 break;
1137 }
1138
1139 // If there are no streams of priority <= the current stream, the
1140 // current stream will default to a child of the idle node (0).
1141 headers.set_exclusive(true);
1142 } 1100 }
1143 1101
1144 headers.set_fin((flags & CONTROL_FLAG_FIN) != 0); 1102 headers.set_fin((flags & CONTROL_FLAG_FIN) != 0);
1145 headers.set_header_block(block); 1103 headers.set_header_block(block);
1146 syn_frame.reset(buffered_spdy_framer_->SerializeFrame(headers)); 1104 syn_frame.reset(buffered_spdy_framer_->SerializeFrame(headers));
1147 1105
1148 if (net_log().IsCapturing()) { 1106 if (net_log().IsCapturing()) {
1149 net_log().AddEvent( 1107 net_log().AddEvent(
1150 NetLog::TYPE_HTTP2_SESSION_SEND_HEADERS, 1108 NetLog::TYPE_HTTP2_SESSION_SEND_HEADERS,
1151 base::Bind(&NetLogSpdyHeadersSentCallback, &block, 1109 base::Bind(&NetLogSpdyHeadersSentCallback, &block,
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
1318 return LOAD_STATE_IDLE; 1276 return LOAD_STATE_IDLE;
1319 } 1277 }
1320 1278
1321 void SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it, 1279 void SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it,
1322 int status) { 1280 int status) {
1323 // TODO(mbelshe): We should send a RST_STREAM control frame here 1281 // TODO(mbelshe): We should send a RST_STREAM control frame here
1324 // so that the server can cancel a large send. 1282 // so that the server can cancel a large send.
1325 1283
1326 scoped_ptr<SpdyStream> owned_stream(it->second.stream); 1284 scoped_ptr<SpdyStream> owned_stream(it->second.stream);
1327 active_streams_.erase(it); 1285 active_streams_.erase(it);
1328 active_streams_by_priority_[owned_stream->priority()].erase( 1286 if (priority_dependencies_enabled_)
1329 owned_stream->stream_id()); 1287 priority_dependency_state_.OnStreamDestruction(owned_stream->stream_id());
1330 1288
1331 // TODO(akalin): When SpdyStream was ref-counted (and 1289 // TODO(akalin): When SpdyStream was ref-counted (and
1332 // |unclaimed_pushed_streams_| held scoped_refptr<SpdyStream>), this 1290 // |unclaimed_pushed_streams_| held scoped_refptr<SpdyStream>), this
1333 // was only done when status was not OK. This meant that pushed 1291 // was only done when status was not OK. This meant that pushed
1334 // streams can still be claimed after they're closed. This is 1292 // streams can still be claimed after they're closed. This is
1335 // probably something that we still want to support, although server 1293 // probably something that we still want to support, although server
1336 // push is hardly used. Write tests for this and fix this. (See 1294 // push is hardly used. Write tests for this and fix this. (See
1337 // http://crbug.com/261712 .) 1295 // http://crbug.com/261712 .)
1338 if (owned_stream->type() == SPDY_PUSH_STREAM) { 1296 if (owned_stream->type() == SPDY_PUSH_STREAM) {
1339 unclaimed_pushed_streams_.erase(owned_stream->url()); 1297 unclaimed_pushed_streams_.erase(owned_stream->url());
(...skipping 642 matching lines...) Expand 10 before | Expand all | Expand 10 after
1982 created_streams_.erase(stream); 1940 created_streams_.erase(stream);
1983 return owned_stream; 1941 return owned_stream;
1984 } 1942 }
1985 1943
1986 void SpdySession::InsertActivatedStream(scoped_ptr<SpdyStream> stream) { 1944 void SpdySession::InsertActivatedStream(scoped_ptr<SpdyStream> stream) {
1987 SpdyStreamId stream_id = stream->stream_id(); 1945 SpdyStreamId stream_id = stream->stream_id();
1988 CHECK_NE(stream_id, 0u); 1946 CHECK_NE(stream_id, 0u);
1989 std::pair<ActiveStreamMap::iterator, bool> result = 1947 std::pair<ActiveStreamMap::iterator, bool> result =
1990 active_streams_.insert( 1948 active_streams_.insert(
1991 std::make_pair(stream_id, ActiveStreamInfo(stream.get()))); 1949 std::make_pair(stream_id, ActiveStreamInfo(stream.get())));
1992 active_streams_by_priority_[stream->priority()].insert(
1993 std::make_pair(stream_id, stream.get()));
1994 CHECK(result.second); 1950 CHECK(result.second);
1995 ignore_result(stream.release()); 1951 ignore_result(stream.release());
1996 } 1952 }
1997 1953
1998 void SpdySession::DeleteStream(scoped_ptr<SpdyStream> stream, int status) { 1954 void SpdySession::DeleteStream(scoped_ptr<SpdyStream> stream, int status) {
1999 if (in_flight_write_stream_.get() == stream.get()) { 1955 if (in_flight_write_stream_.get() == stream.get()) {
2000 // If we're deleting the stream for the in-flight write, we still 1956 // If we're deleting the stream for the in-flight write, we still
2001 // need to let the write complete, so we clear 1957 // need to let the write complete, so we clear
2002 // |in_flight_write_stream_| and let the write finish on its own 1958 // |in_flight_write_stream_| and let the write finish on its own
2003 // without notifying |in_flight_write_stream_|. 1959 // without notifying |in_flight_write_stream_|.
(...skipping 1286 matching lines...) Expand 10 before | Expand all | Expand 10 after
3290 if (!queue->empty()) { 3246 if (!queue->empty()) {
3291 SpdyStreamId stream_id = queue->front(); 3247 SpdyStreamId stream_id = queue->front();
3292 queue->pop_front(); 3248 queue->pop_front();
3293 return stream_id; 3249 return stream_id;
3294 } 3250 }
3295 } 3251 }
3296 return 0; 3252 return 0;
3297 } 3253 }
3298 3254
3299 } // namespace net 3255 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698