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

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: 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 622 matching lines...) Expand 10 before | Expand all | Expand 10 after
704 verify_domain_authentication_(verify_domain_authentication), 695 verify_domain_authentication_(verify_domain_authentication),
705 enable_sending_initial_data_(enable_sending_initial_data), 696 enable_sending_initial_data_(enable_sending_initial_data),
706 enable_ping_based_connection_checking_( 697 enable_ping_based_connection_checking_(
707 enable_ping_based_connection_checking), 698 enable_ping_based_connection_checking),
708 protocol_(default_protocol), 699 protocol_(default_protocol),
709 connection_at_risk_of_loss_time_( 700 connection_at_risk_of_loss_time_(
710 base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)), 701 base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)),
711 hung_interval_(base::TimeDelta::FromSeconds(kHungIntervalSeconds)), 702 hung_interval_(base::TimeDelta::FromSeconds(kHungIntervalSeconds)),
712 proxy_delegate_(proxy_delegate), 703 proxy_delegate_(proxy_delegate),
713 time_func_(time_func), 704 time_func_(time_func),
714 send_priority_dependency_(priority_dependency_enabled_default),
715 weak_factory_(this) { 705 weak_factory_(this) {
716 DCHECK_GE(protocol_, kProtoSPDYMinimumVersion); 706 DCHECK_GE(protocol_, kProtoSPDYMinimumVersion);
717 DCHECK_LE(protocol_, kProtoSPDYMaximumVersion); 707 DCHECK_LE(protocol_, kProtoSPDYMaximumVersion);
718 DCHECK(HttpStreamFactory::spdy_enabled()); 708 DCHECK(HttpStreamFactory::spdy_enabled());
719 net_log_.BeginEvent( 709 net_log_.BeginEvent(
720 NetLog::TYPE_HTTP2_SESSION, 710 NetLog::TYPE_HTTP2_SESSION,
721 base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair())); 711 base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair()));
722 next_unclaimed_push_stream_sweep_time_ = time_func_() + 712 next_unclaimed_push_stream_sweep_time_ = time_func_() +
723 base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds); 713 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. 714 // TODO(mbelshe): consider randomization of the stream_hi_water_mark.
729 } 715 }
730 716
731 SpdySession::~SpdySession() { 717 SpdySession::~SpdySession() {
732 CHECK(!in_io_loop_); 718 CHECK(!in_io_loop_);
733 DcheckDraining(); 719 DcheckDraining();
734 720
735 // TODO(akalin): Check connection->is_initialized() instead. This 721 // TODO(akalin): Check connection->is_initialized() instead. This
736 // requires re-working CreateFakeSpdySession(), though. 722 // requires re-working CreateFakeSpdySession(), though.
737 DCHECK(connection_->socket()); 723 DCHECK(connection_->socket());
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after
1047 bool SpdySession::CloseOneIdleConnection() { 1033 bool SpdySession::CloseOneIdleConnection() {
1048 CHECK(!in_io_loop_); 1034 CHECK(!in_io_loop_);
1049 DCHECK(pool_); 1035 DCHECK(pool_);
1050 if (active_streams_.empty()) { 1036 if (active_streams_.empty()) {
1051 DoDrainSession(ERR_CONNECTION_CLOSED, "Closing idle connection."); 1037 DoDrainSession(ERR_CONNECTION_CLOSED, "Closing idle connection.");
1052 } 1038 }
1053 // Return false as the socket wasn't immediately closed. 1039 // Return false as the socket wasn't immediately closed.
1054 return false; 1040 return false;
1055 } 1041 }
1056 1042
1057 // static
1058 void SpdySession::SetPriorityDependencyDefaultForTesting(bool enable) {
1059 priority_dependency_enabled_default = enable;
1060 }
1061
1062 void SpdySession::EnqueueStreamWrite( 1043 void SpdySession::EnqueueStreamWrite(
1063 const base::WeakPtr<SpdyStream>& stream, 1044 const base::WeakPtr<SpdyStream>& stream,
1064 SpdyFrameType frame_type, 1045 SpdyFrameType frame_type,
1065 scoped_ptr<SpdyBufferProducer> producer) { 1046 scoped_ptr<SpdyBufferProducer> producer) {
1066 DCHECK(frame_type == HEADERS || 1047 DCHECK(frame_type == HEADERS ||
1067 frame_type == DATA || 1048 frame_type == DATA ||
1068 frame_type == SYN_STREAM); 1049 frame_type == SYN_STREAM);
1069 EnqueueWrite(stream->priority(), frame_type, std::move(producer), stream); 1050 EnqueueWrite(stream->priority(), frame_type, std::move(producer), stream);
1070 } 1051 }
1071 1052
(...skipping 28 matching lines...) Expand all
1100 base::Bind(&NetLogSpdySynStreamSentCallback, &block, 1081 base::Bind(&NetLogSpdySynStreamSentCallback, &block,
1101 (flags & CONTROL_FLAG_FIN) != 0, 1082 (flags & CONTROL_FLAG_FIN) != 0,
1102 (flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0, 1083 (flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0,
1103 spdy_priority, stream_id)); 1084 spdy_priority, stream_id));
1104 } 1085 }
1105 } else { 1086 } else {
1106 SpdyHeadersIR headers(stream_id); 1087 SpdyHeadersIR headers(stream_id);
1107 headers.set_priority(spdy_priority); 1088 headers.set_priority(spdy_priority);
1108 headers.set_has_priority(true); 1089 headers.set_has_priority(true);
1109 1090
1110 if (send_priority_dependency_) { 1091 SpdyStreamId dependent_stream_id = 0;
1111 // Set dependencies to reflect request priority. A newly created 1092 bool exclusive = false;
1112 // stream should be dependent on the most recent previously created 1093 priority_dependency_state_.OnStreamSynSent(
1113 // stream of the same priority level. The newly created stream 1094 stream_id, priority, &dependent_stream_id, &exclusive);
1114 // should also have all streams of a lower priority level dependent 1095 headers.set_parent_stream_id(dependent_stream_id);
1115 // on it, which is guaranteed by setting the exclusive bit. 1096 headers.set_exclusive(exclusive);
1116 //
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 }
1143 1097
1144 headers.set_fin((flags & CONTROL_FLAG_FIN) != 0); 1098 headers.set_fin((flags & CONTROL_FLAG_FIN) != 0);
1145 headers.set_header_block(block); 1099 headers.set_header_block(block);
1146 syn_frame.reset(buffered_spdy_framer_->SerializeFrame(headers)); 1100 syn_frame.reset(buffered_spdy_framer_->SerializeFrame(headers));
1147 1101
1148 if (net_log().IsCapturing()) { 1102 if (net_log().IsCapturing()) {
1149 net_log().AddEvent( 1103 net_log().AddEvent(
1150 NetLog::TYPE_HTTP2_SESSION_SEND_HEADERS, 1104 NetLog::TYPE_HTTP2_SESSION_SEND_HEADERS,
1151 base::Bind(&NetLogSpdyHeadersSentCallback, &block, 1105 base::Bind(&NetLogSpdyHeadersSentCallback, &block,
1152 (flags & CONTROL_FLAG_FIN) != 0, stream_id, 1106 (flags & CONTROL_FLAG_FIN) != 0, stream_id,
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
1318 return LOAD_STATE_IDLE; 1272 return LOAD_STATE_IDLE;
1319 } 1273 }
1320 1274
1321 void SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it, 1275 void SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it,
1322 int status) { 1276 int status) {
1323 // TODO(mbelshe): We should send a RST_STREAM control frame here 1277 // TODO(mbelshe): We should send a RST_STREAM control frame here
1324 // so that the server can cancel a large send. 1278 // so that the server can cancel a large send.
1325 1279
1326 scoped_ptr<SpdyStream> owned_stream(it->second.stream); 1280 scoped_ptr<SpdyStream> owned_stream(it->second.stream);
1327 active_streams_.erase(it); 1281 active_streams_.erase(it);
1328 active_streams_by_priority_[owned_stream->priority()].erase( 1282 priority_dependency_state_.OnStreamDestruction(owned_stream->stream_id());
1329 owned_stream->stream_id());
1330 1283
1331 // TODO(akalin): When SpdyStream was ref-counted (and 1284 // TODO(akalin): When SpdyStream was ref-counted (and
1332 // |unclaimed_pushed_streams_| held scoped_refptr<SpdyStream>), this 1285 // |unclaimed_pushed_streams_| held scoped_refptr<SpdyStream>), this
1333 // was only done when status was not OK. This meant that pushed 1286 // was only done when status was not OK. This meant that pushed
1334 // streams can still be claimed after they're closed. This is 1287 // streams can still be claimed after they're closed. This is
1335 // probably something that we still want to support, although server 1288 // probably something that we still want to support, although server
1336 // push is hardly used. Write tests for this and fix this. (See 1289 // push is hardly used. Write tests for this and fix this. (See
1337 // http://crbug.com/261712 .) 1290 // http://crbug.com/261712 .)
1338 if (owned_stream->type() == SPDY_PUSH_STREAM) { 1291 if (owned_stream->type() == SPDY_PUSH_STREAM) {
1339 unclaimed_pushed_streams_.erase(owned_stream->url()); 1292 unclaimed_pushed_streams_.erase(owned_stream->url());
(...skipping 642 matching lines...) Expand 10 before | Expand all | Expand 10 after
1982 created_streams_.erase(stream); 1935 created_streams_.erase(stream);
1983 return owned_stream; 1936 return owned_stream;
1984 } 1937 }
1985 1938
1986 void SpdySession::InsertActivatedStream(scoped_ptr<SpdyStream> stream) { 1939 void SpdySession::InsertActivatedStream(scoped_ptr<SpdyStream> stream) {
1987 SpdyStreamId stream_id = stream->stream_id(); 1940 SpdyStreamId stream_id = stream->stream_id();
1988 CHECK_NE(stream_id, 0u); 1941 CHECK_NE(stream_id, 0u);
1989 std::pair<ActiveStreamMap::iterator, bool> result = 1942 std::pair<ActiveStreamMap::iterator, bool> result =
1990 active_streams_.insert( 1943 active_streams_.insert(
1991 std::make_pair(stream_id, ActiveStreamInfo(stream.get()))); 1944 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); 1945 CHECK(result.second);
1995 ignore_result(stream.release()); 1946 ignore_result(stream.release());
1996 } 1947 }
1997 1948
1998 void SpdySession::DeleteStream(scoped_ptr<SpdyStream> stream, int status) { 1949 void SpdySession::DeleteStream(scoped_ptr<SpdyStream> stream, int status) {
1999 if (in_flight_write_stream_.get() == stream.get()) { 1950 if (in_flight_write_stream_.get() == stream.get()) {
2000 // If we're deleting the stream for the in-flight write, we still 1951 // If we're deleting the stream for the in-flight write, we still
2001 // need to let the write complete, so we clear 1952 // need to let the write complete, so we clear
2002 // |in_flight_write_stream_| and let the write finish on its own 1953 // |in_flight_write_stream_| and let the write finish on its own
2003 // without notifying |in_flight_write_stream_|. 1954 // without notifying |in_flight_write_stream_|.
(...skipping 1286 matching lines...) Expand 10 before | Expand all | Expand 10 after
3290 if (!queue->empty()) { 3241 if (!queue->empty()) {
3291 SpdyStreamId stream_id = queue->front(); 3242 SpdyStreamId stream_id = queue->front();
3292 queue->pop_front(); 3243 queue->pop_front();
3293 return stream_id; 3244 return stream_id;
3294 } 3245 }
3295 } 3246 }
3296 return 0; 3247 return 0;
3297 } 3248 }
3298 3249
3299 } // namespace net 3250 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698