diff options
author | rdsmith <rdsmith@chromium.org> | 2016-03-21 12:48:17 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-21 19:50:41 +0000 |
commit | 2e54d1f83e6ae57cb404658f361e469dd9ed2a92 (patch) | |
tree | 3f42235e4ac04c752d2ede436eb167a7cd5148f8 | |
parent | 7f84a3cff30e92540060524cfb58cdd02e330420 (diff) | |
download | chromium_src-2e54d1f83e6ae57cb404658f361e469dd9ed2a92.zip chromium_src-2e54d1f83e6ae57cb404658f361e469dd9ed2a92.tar.gz chromium_src-2e54d1f83e6ae57cb404658f361e469dd9ed2a92.tar.bz2 |
Fix bug in net::RequestPriority -> HTTP/2 dependency conversion.
This CL also defaults this behavior on (subject to finch override), refactors the finch control to be in line with network stack defaults (== based in io_thread.cc), and removes the non-default performance bot configuration.
BUG=590225
R=bnc@chromium.org
R=isherman@chromium.org
Review URL: https://codereview.chromium.org/1779733003
Cr-Commit-Position: refs/heads/master@{#382360}
31 files changed, 363 insertions, 136 deletions
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc index 1e1979b..f8e9b01 100644 --- a/chrome/browser/io_thread.cc +++ b/chrome/browser/io_thread.cc @@ -180,6 +180,11 @@ const char kNpnTrialName[] = "NPN"; const char kNpnTrialEnabledGroupNamePrefix[] = "Enable"; const char kNpnTrialDisabledGroupNamePrefix[] = "Disable"; +// Field trial for priority dependencies. +const char kSpdyDependenciesFieldTrial[] = "SpdyEnableDependencies"; +const char kSpdyDependenciesFieldTrialEnable[] = "Enable"; +const char kSpdyDepencenciesFieldTrialDisable[] = "Disable"; + #if defined(OS_MACOSX) void ObserveKeychainEvents() { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -802,6 +807,7 @@ void IOThread::Init() { switches::kEnableUserAlternateProtocolPorts)) { globals_->enable_user_alternate_protocol_ports = true; } + ConfigurePriorityDependencies(); globals_->enable_brotli.set( base::FeatureList::IsEnabled(features::kBrotliEncoding)); globals_->enable_token_binding = @@ -1102,6 +1108,9 @@ void IOThread::InitializeNetworkSessionParamsFromGlobals( globals.enable_brotli.CopyToIfSet(¶ms->enable_brotli); + globals.enable_priority_dependencies.CopyToIfSet( + ¶ms->enable_priority_dependencies); + globals.enable_quic.CopyToIfSet(¶ms->enable_quic); globals.disable_quic_on_timeout_with_open_streams.CopyToIfSet( ¶ms->disable_quic_on_timeout_with_open_streams); @@ -1208,6 +1217,16 @@ void IOThread::UpdateDnsClientEnabled() { globals()->host_resolver->SetDnsClientEnabled(*dns_client_enabled_); } +void IOThread::ConfigurePriorityDependencies() { + std::string group = + base::FieldTrialList::FindFullName(kSpdyDependenciesFieldTrial); + if (group == kSpdyDependenciesFieldTrialEnable) { + globals_->enable_priority_dependencies.set(true); + } else if (group == kSpdyDepencenciesFieldTrialDisable) { + globals_->enable_priority_dependencies.set(false); + } +} + void IOThread::ConfigureQuic(const base::CommandLine& command_line) { // Always fetch the field trial group to ensure it is reported correctly. // The command line flags will be associated with a group that is reported diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h index d21ce61..6cb2e07 100644 --- a/chrome/browser/io_thread.h +++ b/chrome/browser/io_thread.h @@ -215,6 +215,8 @@ class IOThread : public content::BrowserThreadDelegate { Optional<bool> enable_brotli; + Optional<bool> enable_priority_dependencies; + Optional<bool> enable_quic; Optional<bool> disable_quic_on_timeout_with_open_streams; Optional<bool> enable_quic_for_proxies; @@ -356,6 +358,9 @@ class IOThread : public content::BrowserThreadDelegate { void UpdateNegotiateDisableCnameLookup(); void UpdateNegotiateEnablePort(); + // Configure the use of priority dependencies in SPDY/HTTP2 + void ConfigurePriorityDependencies(); + // Configures QUIC options based on the flags in |command_line| as // well as the QUIC field trial group. void ConfigureQuic(const base::CommandLine& command_line); diff --git a/ios/chrome/browser/ios_chrome_io_thread.h b/ios/chrome/browser/ios_chrome_io_thread.h index 17c7faa..34d4507 100644 --- a/ios/chrome/browser/ios_chrome_io_thread.h +++ b/ios/chrome/browser/ios_chrome_io_thread.h @@ -141,6 +141,8 @@ class IOSChromeIOThread : public web::WebThreadDelegate { Optional<bool> enable_npn; + Optional<bool> enable_priority_dependencies; + Optional<bool> enable_quic; Optional<bool> enable_quic_for_proxies; Optional<bool> quic_always_require_handshake_confirmation; @@ -252,6 +254,10 @@ class IOSChromeIOThread : public web::WebThreadDelegate { void ChangedToOnTheRecordOnIOThread(); + // Configure whether we set HTTP/2 dependencies from the + // net::RequestPriority. + void ConfigurePriorityDependencies(); + // Configures QUIC options based on the QUIC field trial group. void ConfigureQuic(); diff --git a/ios/chrome/browser/ios_chrome_io_thread.mm b/ios/chrome/browser/ios_chrome_io_thread.mm index 4e76c5a..1cd36da 100644 --- a/ios/chrome/browser/ios_chrome_io_thread.mm +++ b/ios/chrome/browser/ios_chrome_io_thread.mm @@ -137,6 +137,11 @@ const char kNpnTrialName[] = "NPN"; const char kNpnTrialEnabledGroupNamePrefix[] = "Enable"; const char kNpnTrialDisabledGroupNamePrefix[] = "Disable"; +// Field trial for priority dependencies. +const char kSpdyDependenciesFieldTrial[] = "SpdyEnableDependencies"; +const char kSpdyDependenciesFieldTrialEnable[] = "Enable"; +const char kSpdyDepencenciesFieldTrialDisable[] = "Disable"; + // Used for the "system" URLRequestContext. class SystemURLRequestContext : public net::URLRequestContext { public: @@ -455,6 +460,7 @@ void IOSChromeIOThread::Init() { ConfigureAltSvcGlobals( base::FieldTrialList::FindFullName(kAltSvcFieldTrialName), globals_); ConfigureQuic(); + ConfigurePriorityDependencies(); InitializeNetworkOptions(); const version_info::Channel channel = ::GetChannel(); @@ -647,6 +653,9 @@ void IOSChromeIOThread::InitializeNetworkSessionParamsFromGlobals( globals.enable_npn.CopyToIfSet(¶ms->enable_npn); + globals.enable_priority_dependencies.CopyToIfSet( + ¶ms->enable_priority_dependencies); + globals.enable_quic.CopyToIfSet(¶ms->enable_quic); globals.enable_quic_for_proxies.CopyToIfSet(¶ms->enable_quic_for_proxies); globals.quic_always_require_handshake_confirmation.CopyToIfSet( @@ -727,6 +736,16 @@ void IOSChromeIOThread::InitSystemRequestContextOnIOThread() { ConstructSystemRequestContext(globals_, net_log_)); } +void IOSChromeIOThread::ConfigurePriorityDependencies() { + std::string group = + base::FieldTrialList::FindFullName(kSpdyDependenciesFieldTrial); + if (group == kSpdyDependenciesFieldTrialEnable) { + globals_->enable_priority_dependencies.set(true); + } else if (group == kSpdyDepencenciesFieldTrialDisable) { + globals_->enable_priority_dependencies.set(false); + } +} + void IOSChromeIOThread::ConfigureQuic() { // Always fetch the field trial group to ensure it is reported correctly. // The command line flags will be associated with a group that is reported diff --git a/net/http/bidirectional_stream_unittest.cc b/net/http/bidirectional_stream_unittest.cc index 6658d82..a3bc810 100644 --- a/net/http/bidirectional_stream_unittest.cc +++ b/net/http/bidirectional_stream_unittest.cc @@ -296,7 +296,7 @@ class MockTimer : public base::MockTimer { class BidirectionalStreamTest : public testing::TestWithParam<bool> { public: BidirectionalStreamTest() - : spdy_util_(kProtoHTTP2, false), + : spdy_util_(kProtoHTTP2, true), session_deps_(kProtoHTTP2), ssl_data_(SSLSocketDataProvider(ASYNC, OK)) { ssl_data_.SetNextProto(kProtoHTTP2); diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc index da649b0..053509a 100644 --- a/net/http/http_network_session.cc +++ b/net/http/http_network_session.cc @@ -99,6 +99,7 @@ HttpNetworkSession::Params::Params() enable_alternative_service_with_different_host(false), enable_npn(true), enable_brotli(false), + enable_priority_dependencies(true), enable_quic(false), disable_quic_on_timeout_with_open_streams(false), enable_quic_for_proxies(false), @@ -193,6 +194,7 @@ HttpNetworkSession::HttpNetworkSession(const Params& params) params.http_server_properties, params.transport_security_state, params.enable_spdy_ping_based_connection_checking, + params.enable_priority_dependencies, params.spdy_default_protocol, params.spdy_session_max_recv_window_size, params.spdy_stream_max_recv_window_size, diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h index 094eea8..a636308 100644 --- a/net/http/http_network_session.h +++ b/net/http/http_network_session.h @@ -106,6 +106,9 @@ class NET_EXPORT HttpNetworkSession // Enables Brotli Content-Encoding support. bool enable_brotli; + // Enable setting of HTTP/2 dependencies based on priority. + bool enable_priority_dependencies; + // Enables QUIC support. bool enable_quic; // Disable QUIC if a connection times out with open streams. diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index b44bf3b..2cf63e4 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc @@ -271,7 +271,6 @@ class HttpNetworkTransactionTest HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_pool_sockets_); ClientSocketPoolManager::set_max_sockets_per_group( HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_group_sockets_); - SpdySession::SetPriorityDependencyDefaultForTesting(false); } protected: @@ -282,8 +281,7 @@ class HttpNetworkTransactionTest HttpNetworkSession::NORMAL_SOCKET_POOL)), old_max_pool_sockets_(ClientSocketPoolManager::max_sockets_per_pool( HttpNetworkSession::NORMAL_SOCKET_POOL)) { - SpdySession::SetPriorityDependencyDefaultForTesting( - GetDependenciesFromPriority()); + session_deps_.enable_priority_dependencies = GetDependenciesFromPriority(); } struct SimpleGetHelperResult { diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc index 29c10d0..7fea5f1 100644 --- a/net/http/http_proxy_client_socket_pool_unittest.cc +++ b/net/http/http_proxy_client_socket_pool_unittest.cc @@ -86,20 +86,18 @@ class HttpProxyClientSocketPoolTest NULL, session_deps_.ssl_config_service.get(), BoundNetLog().net_log()), - session_(CreateNetworkSession()), spdy_util_(GetParam().protocol, GetParam().priority_to_dependency), pool_(kMaxSockets, kMaxSocketsPerGroup, &transport_socket_pool_, &ssl_socket_pool_, NULL) { - SpdySession::SetPriorityDependencyDefaultForTesting( - GetParam().priority_to_dependency); + session_deps_.enable_priority_dependencies = + GetParam().priority_to_dependency; + session_ = CreateNetworkSession(); } - virtual ~HttpProxyClientSocketPoolTest() { - SpdySession::SetPriorityDependencyDefaultForTesting(false); - } + virtual ~HttpProxyClientSocketPoolTest() {} void AddAuthToCache() { const base::string16 kFoo(base::ASCIIToUTF16("foo")); @@ -219,7 +217,7 @@ class HttpProxyClientSocketPoolTest scoped_ptr<CertVerifier> cert_verifier_; SSLClientSocketPool ssl_socket_pool_; - const scoped_ptr<HttpNetworkSession> session_; + scoped_ptr<HttpNetworkSession> session_; protected: SpdyTestUtil spdy_util_; diff --git a/net/net.gypi b/net/net.gypi index b80e2bb..80e59a6 100644 --- a/net/net.gypi +++ b/net/net.gypi @@ -1138,6 +1138,8 @@ 'spdy/hpack/hpack_static_table.cc', 'spdy/hpack/hpack_static_table.h', 'spdy/http2_write_scheduler.h', + 'spdy/http2_priority_dependencies.h', + 'spdy/http2_priority_dependencies.cc', 'spdy/priority_write_scheduler.h', 'spdy/spdy_alt_svc_wire_format.cc', 'spdy/spdy_alt_svc_wire_format.h', @@ -1754,6 +1756,7 @@ 'spdy/hpack/hpack_round_trip_test.cc', 'spdy/hpack/hpack_static_table_test.cc', 'spdy/http2_write_scheduler_test.cc', + 'spdy/http2_priority_dependencies_unittest.cc', 'spdy/mock_spdy_framer_visitor.cc', 'spdy/mock_spdy_framer_visitor.h', 'spdy/priority_write_scheduler_test.cc', diff --git a/net/spdy/http2_priority_dependencies.cc b/net/spdy/http2_priority_dependencies.cc new file mode 100644 index 0000000..a09ef1d --- /dev/null +++ b/net/spdy/http2_priority_dependencies.cc @@ -0,0 +1,51 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/spdy/http2_priority_dependencies.h" + +namespace net { + +Http2PriorityDependencies::Http2PriorityDependencies() {} + +Http2PriorityDependencies::~Http2PriorityDependencies() {} + +void Http2PriorityDependencies::OnStreamSynSent( + SpdyStreamId id, + SpdyPriority priority, + SpdyStreamId* dependent_stream_id, + bool* exclusive) { + DCHECK(entry_by_stream_id_.find(id) == entry_by_stream_id_.end()); + + *dependent_stream_id = 0ul; + *exclusive = true; + + // Find the next highest entry in total order. + for (int i = priority; i >= kV3HighestPriority; --i) { + if (!id_priority_lists_[i].empty()) { + *dependent_stream_id = id_priority_lists_[i].back().first; + break; + } + } + + id_priority_lists_[priority].push_back(std::make_pair(id, priority)); + IdList::iterator it = id_priority_lists_[priority].end(); + --it; + entry_by_stream_id_[id] = it; +} + +void Http2PriorityDependencies::OnStreamDestruction(SpdyStreamId id) { + EntryMap::iterator emit = entry_by_stream_id_.find(id); + + // This routine may be called without a matching call to + // OnStreamSynSent above, in the case of server push. In that case, + // it's a no-op. + if (emit == entry_by_stream_id_.end()) + return; + + IdList::iterator it = emit->second; + id_priority_lists_[it->second].erase(it); + entry_by_stream_id_.erase(emit); +} + +} // namespace net diff --git a/net/spdy/http2_priority_dependencies.h b/net/spdy/http2_priority_dependencies.h new file mode 100644 index 0000000..8f4ced0 --- /dev/null +++ b/net/spdy/http2_priority_dependencies.h @@ -0,0 +1,60 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_HTTP2_PRIORITY_DEPENDENCIES_H_ +#define NET_HTTP2_PRIORITY_DEPENDENCIES_H_ + +#include <list> +#include <map> + +#include "net/spdy/spdy_protocol.h" + +namespace net { + +// A helper class encapsulating the state and logic to set dependencies of +// HTTP2 streams based on their SpdyPriority and the ordering +// of creation and deletion of the streams. +class NET_EXPORT_PRIVATE Http2PriorityDependencies { + public: + Http2PriorityDependencies(); + ~Http2PriorityDependencies(); + + // Called when a stream SYN is sent to the server. Note that in the + // case of server push, a stream may be created without this routine + // being called. In such cases, the client ignores the stream's priority + // (as the server is effectively overriding the client's notions of + // priority anyway). + // On return, |*dependent_stream_id| is set to the stream id that + // this stream should be made dependent on, and |*exclusive| set to + // whether that dependency should be exclusive. + void OnStreamSynSent(SpdyStreamId id, + SpdyPriority priority, + SpdyStreamId* dependent_stream_id, + bool* exclusive); + + void OnStreamDestruction(SpdyStreamId id); + + private: + // The requirements for the internal data structure for this class are: + // a) Constant time insertion of entries at the end of the list, + // b) Fast removal of any entry based on its id. + // c) Constant time lookup of the entry at the end of the list. + // std::list would satisfy (a) & (c), but some form of map is + // needed for (b). The priority must be included in the map + // entries so that deletion can determine which list in id_priority_lists_ + // to erase from. + using IdList = std::list<std::pair<SpdyStreamId, SpdyPriority>>; + using EntryMap = std::map<SpdyStreamId, IdList::iterator>; + + IdList id_priority_lists_[kV3LowestPriority + 1]; + + // Tracks the location of an id anywhere in the above vector of lists. + // Iterators to list elements remain valid until those particular elements + // are erased. + EntryMap entry_by_stream_id_; +}; + +} // namespace net + +#endif // NET_HTTP2_PRIORITY_DEPENDENCIES_H_ diff --git a/net/spdy/http2_priority_dependencies_unittest.cc b/net/spdy/http2_priority_dependencies_unittest.cc new file mode 100644 index 0000000..05c482b --- /dev/null +++ b/net/spdy/http2_priority_dependencies_unittest.cc @@ -0,0 +1,144 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/spdy/http2_priority_dependencies.h" + +#include "testing/platform_test.h" + +namespace net { + +class HttpPriorityDependencyTest : public PlatformTest { + public: + HttpPriorityDependencyTest() : next_id_(0u) {} + + // Fixed priority values to use for testing. + enum { HIGHEST = 0, MEDIUM = 2, LOW = 4, LOWEST = 5 }; + + SpdyStreamId GetId() { return ++next_id_; } + + void TestStreamCreation(SpdyStreamId new_id, + SpdyPriority priority, + SpdyStreamId expected_dependent_id) { + SpdyStreamId dependent_id = 999u; + bool exclusive = false; + dependency_state.OnStreamSynSent(new_id, priority, &dependent_id, + &exclusive); + EXPECT_EQ(expected_dependent_id, dependent_id); + EXPECT_TRUE(exclusive); + } + + void OnStreamDestruction(SpdyStreamId id) { + dependency_state.OnStreamDestruction(id); + } + + private: + SpdyStreamId next_id_; + Http2PriorityDependencies dependency_state; +}; + +// Confirm dependencies correct for entries at the same priority. +TEST_F(HttpPriorityDependencyTest, SamePriority) { + Http2PriorityDependencies dependency_state; + + const SpdyStreamId first_id = GetId(); + const SpdyStreamId second_id = GetId(); + const SpdyStreamId third_id = GetId(); + + TestStreamCreation(first_id, MEDIUM, 0u); + TestStreamCreation(second_id, MEDIUM, first_id); + TestStreamCreation(third_id, MEDIUM, second_id); +} + +// Confirm dependencies correct for entries at different priorities, increasing. +TEST_F(HttpPriorityDependencyTest, DifferentPriorityIncreasing) { + Http2PriorityDependencies dependency_state; + + const SpdyStreamId first_id = GetId(); + const SpdyStreamId second_id = GetId(); + const SpdyStreamId third_id = GetId(); + + TestStreamCreation(first_id, LOWEST, 0u); + TestStreamCreation(second_id, MEDIUM, 0u); + TestStreamCreation(third_id, HIGHEST, 0u); +} + +// Confirm dependencies correct for entries at different priorities, increasing. +TEST_F(HttpPriorityDependencyTest, DifferentPriorityDecreasing) { + Http2PriorityDependencies dependency_state; + + const SpdyStreamId first_id = GetId(); + const SpdyStreamId second_id = GetId(); + const SpdyStreamId third_id = GetId(); + + TestStreamCreation(first_id, HIGHEST, 0u); + TestStreamCreation(second_id, MEDIUM, first_id); + TestStreamCreation(third_id, LOWEST, second_id); +} + +// Confirm dependencies correct if requests are completed between before +// next creation. +TEST_F(HttpPriorityDependencyTest, CompletionBeforeIssue) { + Http2PriorityDependencies dependency_state; + + const SpdyStreamId first_id = GetId(); + const SpdyStreamId second_id = GetId(); + const SpdyStreamId third_id = GetId(); + + TestStreamCreation(first_id, HIGHEST, 0u); + OnStreamDestruction(first_id); + TestStreamCreation(second_id, MEDIUM, 0u); + OnStreamDestruction(second_id); + TestStreamCreation(third_id, LOWEST, 0u); +} + +// Confirm dependencies correct if some requests are completed between before +// next creation. +TEST_F(HttpPriorityDependencyTest, SomeCompletions) { + Http2PriorityDependencies dependency_state; + + const SpdyStreamId first_id = GetId(); + const SpdyStreamId second_id = GetId(); + const SpdyStreamId third_id = GetId(); + + TestStreamCreation(first_id, HIGHEST, 0u); + TestStreamCreation(second_id, MEDIUM, first_id); + OnStreamDestruction(second_id); + TestStreamCreation(third_id, LOWEST, first_id); +} + +// A more complex example parallel to a simple web page. +TEST_F(HttpPriorityDependencyTest, Complex) { + Http2PriorityDependencies dependency_state; + + const SpdyStreamId first_id = GetId(); + const SpdyStreamId second_id = GetId(); + const SpdyStreamId third_id = GetId(); + const SpdyStreamId fourth_id = GetId(); + const SpdyStreamId fifth_id = GetId(); + const SpdyStreamId sixth_id = GetId(); + const SpdyStreamId seventh_id = GetId(); + const SpdyStreamId eighth_id = GetId(); + const SpdyStreamId nineth_id = GetId(); + const SpdyStreamId tenth_id = GetId(); + + TestStreamCreation(first_id, HIGHEST, 0u); + TestStreamCreation(second_id, MEDIUM, first_id); + TestStreamCreation(third_id, MEDIUM, second_id); + OnStreamDestruction(first_id); + TestStreamCreation(fourth_id, MEDIUM, third_id); + TestStreamCreation(fifth_id, LOWEST, fourth_id); + TestStreamCreation(sixth_id, MEDIUM, fourth_id); + OnStreamDestruction(third_id); + TestStreamCreation(seventh_id, MEDIUM, sixth_id); + TestStreamCreation(eighth_id, LOW, seventh_id); + OnStreamDestruction(second_id); + OnStreamDestruction(fourth_id); + OnStreamDestruction(fifth_id); + OnStreamDestruction(sixth_id); + OnStreamDestruction(seventh_id); + TestStreamCreation(nineth_id, MEDIUM, 0u); + TestStreamCreation(tenth_id, HIGHEST, 0u); +} + +} // namespace net diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc index 69ef370..9bd5a70 100644 --- a/net/spdy/spdy_http_stream_unittest.cc +++ b/net/spdy/spdy_http_stream_unittest.cc @@ -82,14 +82,11 @@ class SpdyHttpStreamTest : public testing::Test, SpdyHttpStreamTest() : spdy_util_(GetProtocol(), GetDependenciesFromPriority()), session_deps_(GetProtocol()) { - SpdySession::SetPriorityDependencyDefaultForTesting( - GetDependenciesFromPriority()); + session_deps_.enable_priority_dependencies = GetDependenciesFromPriority(); session_deps_.net_log = &net_log_; } - ~SpdyHttpStreamTest() { - SpdySession::SetPriorityDependencyDefaultForTesting(false); - } + ~SpdyHttpStreamTest() {} protected: NextProto GetProtocol() const { diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc index 88b34eb..cecfe7c 100644 --- a/net/spdy/spdy_network_transaction_unittest.cc +++ b/net/spdy/spdy_network_transaction_unittest.cc @@ -114,6 +114,8 @@ void UpdateSpdySessionDependencies(SpdyNetworkTransactionTestParams test_params, "www.example.org", 443), expiration); } + session_deps->enable_priority_dependencies = + test_params.priority_to_dependency; } scoped_ptr<SpdySessionDependencies> CreateSpdySessionDependencies( @@ -140,8 +142,6 @@ class SpdyNetworkTransactionTest protected: SpdyNetworkTransactionTest() : spdy_util_(GetParam().protocol, GetParam().priority_to_dependency) { - SpdySession::SetPriorityDependencyDefaultForTesting( - GetParam().priority_to_dependency); spdy_util_.set_default_url(GURL(GetDefaultUrl())); } @@ -150,7 +150,6 @@ class SpdyNetworkTransactionTest // destruction. upload_data_stream_.reset(); base::RunLoop().RunUntilIdle(); - SpdySession::SetPriorityDependencyDefaultForTesting(false); } void SetUp() override { diff --git a/net/spdy/spdy_proxy_client_socket_unittest.cc b/net/spdy/spdy_proxy_client_socket_unittest.cc index 20ba5a5..cda99f0 100644 --- a/net/spdy/spdy_proxy_client_socket_unittest.cc +++ b/net/spdy/spdy_proxy_client_socket_unittest.cc @@ -179,14 +179,12 @@ SpdyProxyClientSocketTest::SpdyProxyClientSocketTest() proxy_, PRIVACY_MODE_DISABLED) { session_deps_.net_log = net_log_.bound().net_log(); - SpdySession::SetPriorityDependencyDefaultForTesting( - GetDependenciesFromPriority()); + session_deps_.enable_priority_dependencies = GetDependenciesFromPriority(); } SpdyProxyClientSocketTest::~SpdyProxyClientSocketTest() { EXPECT_TRUE(data_->AllWriteDataConsumed()); EXPECT_TRUE(data_->AllReadDataConsumed()); - SpdySession::SetPriorityDependencyDefaultForTesting(false); } void SpdyProxyClientSocketTest::TearDown() { diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc index da9589a..3ab0112 100644 --- a/net/spdy/spdy_session.cc +++ b/net/spdy/spdy_session.cc @@ -13,7 +13,6 @@ #include "base/compiler_specific.h" #include "base/location.h" #include "base/logging.h" -#include "base/metrics/field_trial.h" #include "base/metrics/histogram_macros.h" #include "base/metrics/sparse_histogram.h" #include "base/profiler/scoped_tracker.h" @@ -61,14 +60,6 @@ const int kHungIntervalSeconds = 10; // Minimum seconds that unclaimed pushed streams will be kept in memory. const int kMinPushedStreamLifetimeSeconds = 300; -// Field trial constants -const char kSpdyDependenciesFieldTrial[] = "SpdyEnableDependencies"; -const char kSpdyDepencenciesFieldTrialEnable[] = "Enable"; - -// Whether the creation of SPDY dependencies based on priority is -// enabled by default. -static bool priority_dependency_enabled_default = false; - scoped_ptr<base::ListValue> SpdyHeaderBlockToListValue( const SpdyHeaderBlock& headers, NetLogCaptureMode capture_mode) { @@ -689,6 +680,7 @@ SpdySession::SpdySession( bool verify_domain_authentication, bool enable_sending_initial_data, bool enable_ping_based_connection_checking, + bool enable_priority_dependencies, NextProto default_protocol, size_t session_max_recv_window_size, size_t stream_max_recv_window_size, @@ -748,7 +740,7 @@ SpdySession::SpdySession( hung_interval_(base::TimeDelta::FromSeconds(kHungIntervalSeconds)), proxy_delegate_(proxy_delegate), time_func_(time_func), - send_priority_dependency_(priority_dependency_enabled_default), + priority_dependencies_enabled_(enable_priority_dependencies), weak_factory_(this) { DCHECK_GE(protocol_, kProtoSPDYMinimumVersion); DCHECK_LE(protocol_, kProtoSPDYMaximumVersion); @@ -758,10 +750,6 @@ SpdySession::SpdySession( base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair())); next_unclaimed_push_stream_sweep_time_ = time_func_() + base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds); - if (base::FieldTrialList::FindFullName(kSpdyDependenciesFieldTrial) == - kSpdyDepencenciesFieldTrialEnable) { - send_priority_dependency_ = true; - } // TODO(mbelshe): consider randomization of the stream_hi_water_mark. } @@ -1091,11 +1079,6 @@ bool SpdySession::CloseOneIdleConnection() { return false; } -// static -void SpdySession::SetPriorityDependencyDefaultForTesting(bool enable) { - priority_dependency_enabled_default = enable; -} - void SpdySession::EnqueueStreamWrite( const base::WeakPtr<SpdyStream>& stream, SpdyFrameType frame_type, @@ -1144,38 +1127,13 @@ scoped_ptr<SpdyFrame> SpdySession::CreateSynStream( headers.set_priority(spdy_priority); headers.set_has_priority(true); - if (send_priority_dependency_) { - // Set dependencies to reflect request priority. A newly created - // stream should be dependent on the most recent previously created - // stream of the same priority level. The newly created stream - // should also have all streams of a lower priority level dependent - // on it, which is guaranteed by setting the exclusive bit. - // - // Note that this depends on stream ids being allocated in a monotonically - // increasing fashion, and on all streams in - // active_streams_{,by_priority_} having stream ids set. - for (int i = priority; i >= IDLE; --i) { - if (active_streams_by_priority_[i].empty()) - continue; - - auto candidate_it = active_streams_by_priority_[i].rbegin(); - - // |active_streams_by_priority_| is updated before the - // SYN stream frame is created, so the current streams - // id is already on the list. Skip over it, skipping this - // priority level if it's singular. - if (candidate_it->second->stream_id() == stream_id) - ++candidate_it; - if (candidate_it == active_streams_by_priority_[i].rend()) - continue; - - headers.set_parent_stream_id(candidate_it->second->stream_id()); - break; - } - - // If there are no streams of priority <= the current stream, the - // current stream will default to a child of the idle node (0). - headers.set_exclusive(true); + if (priority_dependencies_enabled_) { + SpdyStreamId dependent_stream_id = 0; + bool exclusive = false; + priority_dependency_state_.OnStreamSynSent( + stream_id, spdy_priority, &dependent_stream_id, &exclusive); + headers.set_parent_stream_id(dependent_stream_id); + headers.set_exclusive(exclusive); } headers.set_fin((flags & CONTROL_FLAG_FIN) != 0); @@ -1362,8 +1320,8 @@ void SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it, scoped_ptr<SpdyStream> owned_stream(it->second.stream); active_streams_.erase(it); - active_streams_by_priority_[owned_stream->priority()].erase( - owned_stream->stream_id()); + if (priority_dependencies_enabled_) + priority_dependency_state_.OnStreamDestruction(owned_stream->stream_id()); // TODO(akalin): When SpdyStream was ref-counted (and // |unclaimed_pushed_streams_| held scoped_refptr<SpdyStream>), this @@ -2035,8 +1993,6 @@ void SpdySession::InsertActivatedStream(scoped_ptr<SpdyStream> stream) { std::pair<ActiveStreamMap::iterator, bool> result = active_streams_.insert( std::make_pair(stream_id, ActiveStreamInfo(stream.get()))); - active_streams_by_priority_[stream->priority()].insert( - std::make_pair(stream_id, stream.get())); CHECK(result.second); ignore_result(stream.release()); } diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h index 343aa2d..5ce8fec 100644 --- a/net/spdy/spdy_session.h +++ b/net/spdy/spdy_session.h @@ -32,6 +32,7 @@ #include "net/socket/ssl_client_socket.h" #include "net/socket/stream_socket.h" #include "net/spdy/buffered_spdy_framer.h" +#include "net/spdy/http2_priority_dependencies.h" #include "net/spdy/spdy_buffer.h" #include "net/spdy/spdy_framer.h" #include "net/spdy/spdy_header_block.h" @@ -290,6 +291,7 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface, bool verify_domain_authentication, bool enable_sending_initial_data, bool enable_ping_based_connection_checking, + bool enable_priority_dependencies, NextProto default_protocol, size_t session_max_recv_window_size, size_t stream_max_recv_window_size, @@ -1001,10 +1003,6 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface, bool check_ping_status_pending() const { return check_ping_status_pending_; } - // Set whether priority->dependency conversion is enabled - // by default for all future SpdySessions. - static void SetPriorityDependencyDefaultForTesting(bool enable); - // Whether Do{Read,Write}Loop() is in the call stack. Useful for // making sure we don't destroy ourselves prematurely in that case. bool in_io_loop_; @@ -1050,14 +1048,6 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface, // them? ActiveStreamMap active_streams_; - // Per-priority map from stream id to all active streams. This map will - // contain the same set of streams as |active_streams_|. It is used for - // setting dependencies to match incoming requests RequestPriority. - // - // |active_streams_by_priority_| does *not* own its SpdyStream objects. - std::map<SpdyStreamId, SpdyStream*> - active_streams_by_priority_[NUM_PRIORITIES]; - UnclaimedPushedStreamContainer unclaimed_pushed_streams_; // Set of all created streams but that have not yet sent any frames. @@ -1230,9 +1220,8 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface, TimeFunc time_func_; - // Should priority-based dependency information be sent in stream header - // frames. - bool send_priority_dependency_; + const bool priority_dependencies_enabled_; + Http2PriorityDependencies priority_dependency_state_; // Used for posting asynchronous IO tasks. We use this even though // SpdySession is refcounted because we don't need to keep the SpdySession diff --git a/net/spdy/spdy_session_pool.cc b/net/spdy/spdy_session_pool.cc index afc285c..b84c8bb 100644 --- a/net/spdy/spdy_session_pool.cc +++ b/net/spdy/spdy_session_pool.cc @@ -36,6 +36,7 @@ SpdySessionPool::SpdySessionPool( const base::WeakPtr<HttpServerProperties>& http_server_properties, TransportSecurityState* transport_security_state, bool enable_ping_based_connection_checking, + bool enable_priority_dependencies, NextProto default_protocol, size_t session_max_recv_window_size, size_t stream_max_recv_window_size, @@ -49,6 +50,7 @@ SpdySessionPool::SpdySessionPool( enable_sending_initial_data_(true), enable_ping_based_connection_checking_( enable_ping_based_connection_checking), + enable_priority_dependencies_(enable_priority_dependencies), // TODO(akalin): Force callers to have a valid value of // |default_protocol_|. default_protocol_((default_protocol == kProtoUnknown) ? kProtoSPDY31 @@ -95,9 +97,10 @@ base::WeakPtr<SpdySession> SpdySessionPool::CreateAvailableSessionFromSocket( scoped_ptr<SpdySession> new_session(new SpdySession( key, http_server_properties_, transport_security_state_, verify_domain_authentication_, enable_sending_initial_data_, - enable_ping_based_connection_checking_, default_protocol_, - session_max_recv_window_size_, stream_max_recv_window_size_, time_func_, - proxy_delegate_, net_log.net_log())); + enable_ping_based_connection_checking_, enable_priority_dependencies_, + default_protocol_, session_max_recv_window_size_, + stream_max_recv_window_size_, time_func_, proxy_delegate_, + net_log.net_log())); new_session->InitializeWithSocket(std::move(connection), this, is_secure, certificate_error_code); diff --git a/net/spdy/spdy_session_pool.h b/net/spdy/spdy_session_pool.h index d02ecb2..eeae314 100644 --- a/net/spdy/spdy_session_pool.h +++ b/net/spdy/spdy_session_pool.h @@ -55,6 +55,7 @@ class NET_EXPORT SpdySessionPool const base::WeakPtr<HttpServerProperties>& http_server_properties, TransportSecurityState* transport_security_state, bool enable_ping_based_connection_checking, + bool enable_priority_dependencies, NextProto default_protocol, size_t session_max_recv_window_size, size_t stream_max_recv_window_size, @@ -227,6 +228,7 @@ class NET_EXPORT SpdySessionPool bool verify_domain_authentication_; bool enable_sending_initial_data_; bool enable_ping_based_connection_checking_; + const bool enable_priority_dependencies_; const NextProto default_protocol_; size_t session_max_recv_window_size_; size_t stream_max_recv_window_size_; diff --git a/net/spdy/spdy_session_pool_unittest.cc b/net/spdy/spdy_session_pool_unittest.cc index cb849d3..cbd41c2 100644 --- a/net/spdy/spdy_session_pool_unittest.cc +++ b/net/spdy/spdy_session_pool_unittest.cc @@ -520,8 +520,8 @@ TEST_P(SpdySessionPoolTest, IPAddressChanged) { // can ignore issues of how dependencies are set. We default to // setting them (when doing the appropriate protocol) since that's // where we're eventually headed for all HTTP/2 connections. - SpdyTestUtil spdy_util(GetParam(), true); - SpdySession::SetPriorityDependencyDefaultForTesting(true); + session_deps_.enable_priority_dependencies = true; + SpdyTestUtil spdy_util(GetParam(), /*enable_priority_dependencies*/ true); MockRead reads[] = { MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. @@ -630,7 +630,6 @@ TEST_P(SpdySessionPoolTest, IPAddressChanged) { EXPECT_TRUE(delegateB.StreamIsClosed()); EXPECT_EQ(ERR_NETWORK_CHANGED, delegateB.WaitForClose()); #endif // defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS) - SpdySession::SetPriorityDependencyDefaultForTesting(false); } TEST_P(SpdySessionPoolTest, FindAvailableSession) { diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc index 6e5797f..91547b4 100644 --- a/net/spdy/spdy_session_unittest.cc +++ b/net/spdy/spdy_session_unittest.cc @@ -139,8 +139,7 @@ class SpdySessionTest : public PlatformTest, key_(test_host_port_pair_, ProxyServer::Direct(), PRIVACY_MODE_DISABLED) { - SpdySession::SetPriorityDependencyDefaultForTesting( - GetDependenciesFromPriority()); + session_deps_.enable_priority_dependencies = GetDependenciesFromPriority(); } virtual ~SpdySessionTest() { @@ -150,7 +149,6 @@ class SpdySessionTest : public PlatformTest, HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_pool_sockets_); ClientSocketPoolManager::set_max_sockets_per_group( HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_group_sockets_); - SpdySession::SetPriorityDependencyDefaultForTesting(false); } void SetUp() override { diff --git a/net/spdy/spdy_stream_unittest.cc b/net/spdy/spdy_stream_unittest.cc index eea3352..70bbc49 100644 --- a/net/spdy/spdy_stream_unittest.cc +++ b/net/spdy/spdy_stream_unittest.cc @@ -69,14 +69,12 @@ class SpdyStreamTest : public ::testing::Test, SpdyStreamTest() : spdy_util_(GetProtocol(), GetDependenciesFromPriority()), session_deps_(GetProtocol()), - session_(SpdySessionDependencies::SpdyCreateSession(&session_deps_)), offset_(0) { - SpdySession::SetPriorityDependencyDefaultForTesting( - GetDependenciesFromPriority()); + session_deps_.enable_priority_dependencies = GetDependenciesFromPriority(); + session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_); } ~SpdyStreamTest() { - SpdySession::SetPriorityDependencyDefaultForTesting(false); } base::WeakPtr<SpdySession> CreateDefaultSpdySession() { diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc index 627eeee..2a37dab 100644 --- a/net/spdy/spdy_test_util_common.cc +++ b/net/spdy/spdy_test_util_common.cc @@ -341,6 +341,7 @@ SpdySessionDependencies::SpdySessionDependencies(NextProto protocol) enable_ping(false), enable_user_alternate_protocol_ports(false), enable_npn(true), + enable_priority_dependencies(true), protocol(protocol), session_max_recv_window_size( SpdySession::GetDefaultInitialWindowSize(protocol)), @@ -377,6 +378,7 @@ SpdySessionDependencies::SpdySessionDependencies( enable_ping(false), enable_user_alternate_protocol_ports(false), enable_npn(true), + enable_priority_dependencies(true), protocol(protocol), session_max_recv_window_size( SpdySession::GetDefaultInitialWindowSize(protocol)), @@ -424,6 +426,8 @@ HttpNetworkSession::Params SpdySessionDependencies::CreateSessionParams( params.enable_user_alternate_protocol_ports = session_deps->enable_user_alternate_protocol_ports; params.enable_npn = session_deps->enable_npn; + params.enable_priority_dependencies = + session_deps->enable_priority_dependencies; params.spdy_default_protocol = session_deps->protocol; params.spdy_session_max_recv_window_size = session_deps->session_max_recv_window_size; @@ -1042,8 +1046,13 @@ SpdyFrame* SpdyTestUtil::ConstructSpdySyn(int stream_id, // Get the stream id of the next highest priority request // (most recent request of the same priority, or last request of // an earlier priority). + // Note that this is a duplicate of the logic in Http2PriorityDependencies + // (slightly transformed as this is based on RequestPriority and that logic + // on SpdyPriority, but only slightly transformed) and hence tests using + // this function do not effectively test that logic. + // That logic is tested by the Http2PriorityDependencies unit tests. int parent_stream_id = 0; - for (int q = priority; q >= IDLE; --q) { + for (int q = priority; q <= HIGHEST; ++q) { if (!priority_to_stream_id_list_[q].empty()) { parent_stream_id = priority_to_stream_id_list_[q].back(); break; diff --git a/net/spdy/spdy_test_util_common.h b/net/spdy/spdy_test_util_common.h index e4ad8ec..64992a6 100644 --- a/net/spdy/spdy_test_util_common.h +++ b/net/spdy/spdy_test_util_common.h @@ -197,6 +197,7 @@ struct SpdySessionDependencies { bool enable_ping; bool enable_user_alternate_protocol_ports; bool enable_npn; + bool enable_priority_dependencies; NextProto protocol; size_t session_max_recv_window_size; size_t stream_max_recv_window_size; diff --git a/testing/variations/fieldtrial_testing_config_android.json b/testing/variations/fieldtrial_testing_config_android.json index dc85f56..e2b80af 100644 --- a/testing/variations/fieldtrial_testing_config_android.json +++ b/testing/variations/fieldtrial_testing_config_android.json @@ -333,11 +333,6 @@ "group_name": "Enabled" } ], - "SpdyEnableDependencies": [ - { - "group_name": "Enable" - } - ], "SpeculativeResourcePrefetching": [ { "group_name": "v=1a:Prefetching=Enabled:Predictor=Url" diff --git a/testing/variations/fieldtrial_testing_config_chromeos.json b/testing/variations/fieldtrial_testing_config_chromeos.json index 2312ee9..9a03f0b 100644 --- a/testing/variations/fieldtrial_testing_config_chromeos.json +++ b/testing/variations/fieldtrial_testing_config_chromeos.json @@ -145,11 +145,6 @@ "group_name": "ExperimentYes" } ], - "SpdyEnableDependencies": [ - { - "group_name": "Enable" - } - ], "StrictSecureCookies": [ { "group_name": "Enabled" diff --git a/testing/variations/fieldtrial_testing_config_ios.json b/testing/variations/fieldtrial_testing_config_ios.json index 67899aa..a2e409b 100644 --- a/testing/variations/fieldtrial_testing_config_ios.json +++ b/testing/variations/fieldtrial_testing_config_ios.json @@ -56,11 +56,6 @@ "group_name": "Enabled" } ], - "SpdyEnableDependencies": [ - { - "group_name": "Enable" - } - ], "SyncHttpContentCompression": [ { "group_name": "Enabled" diff --git a/testing/variations/fieldtrial_testing_config_linux.json b/testing/variations/fieldtrial_testing_config_linux.json index ec15528..cee9d02 100644 --- a/testing/variations/fieldtrial_testing_config_linux.json +++ b/testing/variations/fieldtrial_testing_config_linux.json @@ -192,11 +192,6 @@ "group_name": "ExperimentYes" } ], - "SpdyEnableDependencies": [ - { - "group_name": "Enable" - } - ], "StrictSecureCookies": [ { "group_name": "Enabled" diff --git a/testing/variations/fieldtrial_testing_config_mac.json b/testing/variations/fieldtrial_testing_config_mac.json index 5ad2471..b3cbf6f 100644 --- a/testing/variations/fieldtrial_testing_config_mac.json +++ b/testing/variations/fieldtrial_testing_config_mac.json @@ -208,11 +208,6 @@ "group_name": "ExperimentYes" } ], - "SpdyEnableDependencies": [ - { - "group_name": "Enable" - } - ], "StrictSecureCookies": [ { "group_name": "Enabled" diff --git a/testing/variations/fieldtrial_testing_config_win.json b/testing/variations/fieldtrial_testing_config_win.json index 79e43ec..45b55af 100644 --- a/testing/variations/fieldtrial_testing_config_win.json +++ b/testing/variations/fieldtrial_testing_config_win.json @@ -285,11 +285,6 @@ "group_name": "ExperimentYes" } ], - "SpdyEnableDependencies": [ - { - "group_name": "Enable" - } - ], "StrictSecureCookies": [ { "group_name": "Enabled" |