Commit e84179dd authored by Bence Béky's avatar Bence Béky Committed by Chromium LUCI CQ

Parse SETTINGS_DEPRECATE_HTTP2_PRIORITIES.

Implement logic for
https://httpwg.org/http-extensions/draft-ietf-httpbis-priority.html#name-disabling-http-2-priorities
in SpdySession, adding accessors for HTTP/2 priorities and
PRIORITY_UPDATE frame.  Add |enable_priority_update| knob to

SpdySessionDependencies via SpdySessionPool to SpdySession.  Default to
current behavior both in tests and production.

HttpNetworkSession: :Params and plumb it through from
Change-Id: Iada98d7d692b3ce10e37cd9681ba16a99d564237
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2616834Reviewed-by: default avatarRenjie Tang <renjietang@chromium.org>
Commit-Queue: Bence Béky <bnc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#843004}
parent db1d912f
......@@ -95,7 +95,8 @@ HttpNetworkSession::Params::Params()
enable_quic(true),
enable_quic_proxies_for_https_urls(false),
disable_idle_sockets_close_on_memory_pressure(false),
key_auth_cache_server_entries_by_network_isolation_key(false) {
key_auth_cache_server_entries_by_network_isolation_key(false),
enable_priority_update(false) {
enable_early_data =
base::FeatureList::IsEnabled(features::kEnableTLS13EarlyData);
}
......@@ -183,6 +184,7 @@ HttpNetworkSession::HttpNetworkSession(const Params& params,
AddDefaultHttp2Settings(params.http2_settings),
params.greased_http2_frame,
params.http2_end_stream_with_data_frame,
params.enable_priority_update,
params.time_func,
context.network_quality_estimator),
http_stream_factory_(std::make_unique<HttpStreamFactory>(this)),
......
......@@ -151,6 +151,13 @@ class NET_EXPORT HttpNetworkSession {
bool disable_idle_sockets_close_on_memory_pressure;
bool key_auth_cache_server_entries_by_network_isolation_key;
// If true, enable sending PRIORITY_UPDATE frames until SETTINGS frame
// arrives. After SETTINGS frame arrives, do not send PRIORITY_UPDATE
// frames any longer if SETTINGS_DEPRECATE_HTTP2_PRIORITIES is missing or
// has zero 0, but continue and also stop sending HTTP/2-style priority
// information in HEADERS frames and PRIORITY frames if it has value 1.
bool enable_priority_update;
};
// Structure with pointers to the dependencies of the HttpNetworkSession.
......
......@@ -926,6 +926,7 @@ SpdySession::SpdySession(
const base::Optional<SpdySessionPool::GreasedHttp2Frame>&
greased_http2_frame,
bool http2_end_stream_with_data_frame,
bool enable_priority_update,
TimeFunc time_func,
ServerPushDelegate* push_delegate,
NetworkQualityEstimator* network_quality_estimator,
......@@ -953,6 +954,9 @@ SpdySession::SpdySession(
initial_settings_(initial_settings),
greased_http2_frame_(greased_http2_frame),
http2_end_stream_with_data_frame_(http2_end_stream_with_data_frame),
enable_priority_update_(enable_priority_update),
deprecate_http2_priorities_(false),
settings_frame_received_(false),
in_confirm_handshake_(false),
max_concurrent_streams_(kInitialMaxConcurrentStreams),
max_concurrent_pushed_streams_(
......@@ -1158,6 +1162,18 @@ void SpdySession::EnqueueGreasedFrame(const base::WeakPtr<SpdyStream>& stream) {
stream, stream->traffic_annotation());
}
bool SpdySession::ShouldSendHttp2Priority() const {
return !enable_priority_update_ || !deprecate_http2_priorities_;
}
bool SpdySession::ShouldSendPriorityUpdate() const {
if (!enable_priority_update_) {
return false;
}
return settings_frame_received_ ? deprecate_http2_priorities_ : true;
}
int SpdySession::ConfirmHandshake(CompletionOnceCallback callback) {
int rv = ERR_IO_PENDING;
if (!in_confirm_handshake_) {
......@@ -2663,6 +2679,26 @@ void SpdySession::HandleSetting(uint32_t id, uint32_t value) {
support_websocket_ = true;
}
break;
case spdy::SETTINGS_DEPRECATE_HTTP2_PRIORITIES:
if (value != 0 && value != 1) {
DoDrainSession(
ERR_HTTP2_PROTOCOL_ERROR,
"Invalid value for spdy::SETTINGS_DEPRECATE_HTTP2_PRIORITIES.");
return;
}
if (settings_frame_received_) {
if (value != (deprecate_http2_priorities_ ? 1 : 0)) {
DoDrainSession(ERR_HTTP2_PROTOCOL_ERROR,
"spdy::SETTINGS_DEPRECATE_HTTP2_PRIORITIES value "
"changed after first SETTINGS frame.");
return;
}
} else {
if (value == 1) {
deprecate_http2_priorities_ = true;
}
}
break;
}
}
......@@ -3309,6 +3345,10 @@ void SpdySession::OnSetting(spdy::SpdySettingsId id, uint32_t value) {
[&] { return NetLogSpdyRecvSettingParams(id, value); });
}
void SpdySession::OnSettingsEnd() {
settings_frame_received_ = true;
}
void SpdySession::OnWindowUpdate(spdy::SpdyStreamId stream_id,
int delta_window_size) {
CHECK(in_io_loop_);
......
......@@ -353,6 +353,7 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
const base::Optional<SpdySessionPool::GreasedHttp2Frame>&
greased_http2_frame,
bool http2_end_stream_with_data_frame,
bool enable_priority_update,
TimeFunc time_func,
ServerPushDelegate* push_delegate,
NetworkQualityEstimator* network_quality_estimator,
......@@ -442,6 +443,21 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
// Send greased frame, that is, a frame of reserved type.
void EnqueueGreasedFrame(const base::WeakPtr<SpdyStream>& stream);
// Returns whether HTTP/2 style priority information (stream dependency and
// weight fields in HEADERS frames, and PRIORITY frames) should be sent. True
// unless |enable_priority_update_| is true and
// SETTINGS_DEPRECATE_HTTP2_PRIORITIES with value 1 has been received from
// server. In particular, if it returns false, it will always return false
// afterwards.
bool ShouldSendHttp2Priority() const;
// Returns whether PRIORITY_UPDATE frames should be sent. False if
// |enable_priority_update_| is false. Otherwise, true before SETTINGS frame
// is received from server, and true after SETTINGS frame is received if it
// contained SETTINGS_DEPRECATE_HTTP2_PRIORITIES with value 1. In particular,
// if it returns false, it will always return false afterwards.
bool ShouldSendPriorityUpdate() const;
// Runs the handshake to completion to confirm the handshake with the server.
// If ERR_IO_PENDING is returned, then when the handshake is confirmed,
// |callback| will be called.
......@@ -904,7 +920,7 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
void OnSettings() override;
void OnSettingsAck() override;
void OnSetting(spdy::SpdySettingsId id, uint32_t value) override;
void OnSettingsEnd() override {}
void OnSettingsEnd() override;
void OnWindowUpdate(spdy::SpdyStreamId stream_id,
int delta_window_size) override;
void OnPushPromise(spdy::SpdyStreamId stream_id,
......@@ -1130,7 +1146,21 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
// If unset, the HEADERS frame will have the END_STREAM flag set on.
// This is useful in conjuction with |greased_http2_frame_| so that a frame
// of reserved type can be sent out even on requests without a body.
bool http2_end_stream_with_data_frame_;
const bool http2_end_stream_with_data_frame_;
// If true, enable sending PRIORITY_UPDATE frames until SETTINGS frame
// arrives. After SETTINGS frame arrives, do not send PRIORITY_UPDATE frames
// any longer if SETTINGS_DEPRECATE_HTTP2_PRIORITIES is missing or has zero 0,
// but continue and also stop sending HTTP/2-style priority information in
// HEADERS frames and PRIORITY frames if it has value 1.
const bool enable_priority_update_;
// The value of the last received SETTINGS_DEPRECATE_HTTP2_PRIORITIES, with 0
// mapping to false and 1 to true. Initial value is false.
bool deprecate_http2_priorities_;
// True if at least one SETTINGS frame has been received.
bool settings_frame_received_;
// The callbacks to notify a request that the handshake has been confirmed.
std::vector<CompletionOnceCallback> waiting_for_confirmation_callbacks_;
......
......@@ -90,6 +90,7 @@ SpdySessionPool::SpdySessionPool(
const spdy::SettingsMap& initial_settings,
const base::Optional<GreasedHttp2Frame>& greased_http2_frame,
bool http2_end_stream_with_data_frame,
bool enable_priority_update,
SpdySessionPool::TimeFunc time_func,
NetworkQualityEstimator* network_quality_estimator)
: http_server_properties_(http_server_properties),
......@@ -107,6 +108,7 @@ SpdySessionPool::SpdySessionPool(
initial_settings_(initial_settings),
greased_http2_frame_(greased_http2_frame),
http2_end_stream_with_data_frame_(http2_end_stream_with_data_frame),
enable_priority_update_(enable_priority_update),
time_func_(time_func),
push_delegate_(nullptr),
network_quality_estimator_(network_quality_estimator) {
......@@ -667,8 +669,9 @@ std::unique_ptr<SpdySession> SpdySessionPool::CreateSession(
enable_ping_based_connection_checking_, is_http2_enabled_,
is_quic_enabled_, is_trusted_proxy, session_max_recv_window_size_,
session_max_queued_capped_frames_, initial_settings_,
greased_http2_frame_, http2_end_stream_with_data_frame_, time_func_,
push_delegate_, network_quality_estimator_, net_log);
greased_http2_frame_, http2_end_stream_with_data_frame_,
enable_priority_update_, time_func_, push_delegate_,
network_quality_estimator_, net_log);
}
base::WeakPtr<SpdySession> SpdySessionPool::InsertSession(
......
......@@ -145,6 +145,7 @@ class NET_EXPORT SpdySessionPool
const spdy::SettingsMap& initial_settings,
const base::Optional<GreasedHttp2Frame>& greased_http2_frame,
bool http2_end_stream_with_data_frame,
bool enable_priority_update,
SpdySessionPool::TimeFunc time_func,
NetworkQualityEstimator* network_quality_estimator);
~SpdySessionPool() override;
......@@ -450,7 +451,14 @@ class NET_EXPORT SpdySessionPool
// If unset, the HEADERS frame will have the END_STREAM flag set on.
// This is useful in conjuction with |greased_http2_frame_| so that a frame
// of reserved type can be sent out even on requests without a body.
bool http2_end_stream_with_data_frame_;
const bool http2_end_stream_with_data_frame_;
// If true, enable sending PRIORITY_UPDATE frames until SETTINGS frame
// arrives. After SETTINGS frame arrives, do not send PRIORITY_UPDATE frames
// any longer if SETTINGS_DEPRECATE_HTTP2_PRIORITIES is missing or has zero 0,
// but continue and also stop sending HTTP/2-style priority information in
// HEADERS frames and PRIORITY frames if it has value 1.
const bool enable_priority_update_;
SpdySessionRequestMap spdy_session_request_map_;
......
......@@ -7247,4 +7247,155 @@ TEST_F(SpdySessionTest, UpdateHeaderTableSize) {
EXPECT_TRUE(data.AllReadDataConsumed());
}
TEST_F(SpdySessionTest, PriorityUpdateDisabled) {
session_deps_.enable_priority_update = false;
spdy::SettingsMap settings;
settings[spdy::SETTINGS_DEPRECATE_HTTP2_PRIORITIES] = 1;
auto settings_frame = spdy_util_.ConstructSpdySettings(settings);
auto settings_ack = spdy_util_.ConstructSpdySettingsAck();
MockRead reads[] = {CreateMockRead(settings_frame, 0),
MockRead(ASYNC, ERR_IO_PENDING, 2),
MockRead(ASYNC, 0, 3)};
MockWrite writes[] = {CreateMockWrite(settings_ack, 1)};
SequencedSocketData data(reads, writes);
session_deps_.socket_factory->AddSocketDataProvider(&data);
AddSSLSocketData();
CreateNetworkSession();
CreateSpdySession();
// HTTP/2 priorities enabled by default.
// PRIORITY_UPDATE is disabled by |enable_priority_update| = false.
EXPECT_TRUE(session_->ShouldSendHttp2Priority());
EXPECT_FALSE(session_->ShouldSendPriorityUpdate());
// Receive SETTINGS frame.
base::RunLoop().RunUntilIdle();
// Since |enable_priority_update| = false,
// SETTINGS_DEPRECATE_HTTP2_PRIORITIES has no effect.
EXPECT_TRUE(session_->ShouldSendHttp2Priority());
EXPECT_FALSE(session_->ShouldSendPriorityUpdate());
data.Resume();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(data.AllWriteDataConsumed());
EXPECT_TRUE(data.AllReadDataConsumed());
}
TEST_F(SpdySessionTest, PriorityUpdateEnabledHttp2PrioritiesDeprecated) {
session_deps_.enable_priority_update = true;
spdy::SettingsMap settings;
settings[spdy::SETTINGS_DEPRECATE_HTTP2_PRIORITIES] = 1;
auto settings_frame = spdy_util_.ConstructSpdySettings(settings);
auto settings_ack = spdy_util_.ConstructSpdySettingsAck();
MockRead reads[] = {CreateMockRead(settings_frame, 0),
MockRead(ASYNC, ERR_IO_PENDING, 2),
MockRead(ASYNC, 0, 3)};
MockWrite writes[] = {CreateMockWrite(settings_ack, 1)};
SequencedSocketData data(reads, writes);
session_deps_.socket_factory->AddSocketDataProvider(&data);
AddSSLSocketData();
CreateNetworkSession();
CreateSpdySession();
// Both priority schemes are enabled until SETTINGS frame is received.
EXPECT_TRUE(session_->ShouldSendHttp2Priority());
EXPECT_TRUE(session_->ShouldSendPriorityUpdate());
// Receive SETTINGS frame.
base::RunLoop().RunUntilIdle();
// SETTINGS_DEPRECATE_HTTP2_PRIORITIES = 1 disables HTTP/2 priorities.
EXPECT_FALSE(session_->ShouldSendHttp2Priority());
EXPECT_TRUE(session_->ShouldSendPriorityUpdate());
data.Resume();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(data.AllWriteDataConsumed());
EXPECT_TRUE(data.AllReadDataConsumed());
}
TEST_F(SpdySessionTest, PriorityUpdateEnabledHttp2PrioritiesNotDeprecated) {
session_deps_.enable_priority_update = true;
spdy::SettingsMap settings;
settings[spdy::SETTINGS_DEPRECATE_HTTP2_PRIORITIES] = 0;
auto settings_frame = spdy_util_.ConstructSpdySettings(settings);
auto settings_ack = spdy_util_.ConstructSpdySettingsAck();
MockRead reads[] = {CreateMockRead(settings_frame, 0),
MockRead(ASYNC, ERR_IO_PENDING, 2),
MockRead(ASYNC, 0, 3)};
MockWrite writes[] = {CreateMockWrite(settings_ack, 1)};
SequencedSocketData data(reads, writes);
session_deps_.socket_factory->AddSocketDataProvider(&data);
AddSSLSocketData();
CreateNetworkSession();
CreateSpdySession();
// Both priority schemes are enabled until SETTINGS frame is received.
EXPECT_TRUE(session_->ShouldSendHttp2Priority());
EXPECT_TRUE(session_->ShouldSendPriorityUpdate());
// Receive SETTINGS frame.
base::RunLoop().RunUntilIdle();
// SETTINGS_DEPRECATE_HTTP2_PRIORITIES = 0 disables PRIORITY_UPDATE.
EXPECT_TRUE(session_->ShouldSendHttp2Priority());
EXPECT_FALSE(session_->ShouldSendPriorityUpdate());
data.Resume();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(data.AllWriteDataConsumed());
EXPECT_TRUE(data.AllReadDataConsumed());
}
TEST_F(SpdySessionTest, SettingsDeprecateHttp2PrioritiesValueMustNotChange) {
spdy::SettingsMap settings0;
settings0[spdy::SETTINGS_DEPRECATE_HTTP2_PRIORITIES] = 0;
auto settings_frame0 = spdy_util_.ConstructSpdySettings(settings0);
spdy::SettingsMap settings1;
settings1[spdy::SETTINGS_DEPRECATE_HTTP2_PRIORITIES] = 1;
auto settings_frame1 = spdy_util_.ConstructSpdySettings(settings1);
MockRead reads[] = {
CreateMockRead(settings_frame1, 0), MockRead(ASYNC, ERR_IO_PENDING, 2),
CreateMockRead(settings_frame1, 3), MockRead(ASYNC, ERR_IO_PENDING, 5),
CreateMockRead(settings_frame0, 6)};
auto settings_ack = spdy_util_.ConstructSpdySettingsAck();
auto goaway = spdy_util_.ConstructSpdyGoAway(
0, spdy::ERROR_CODE_PROTOCOL_ERROR,
"spdy::SETTINGS_DEPRECATE_HTTP2_PRIORITIES value changed after first "
"SETTINGS frame.");
MockWrite writes[] = {
CreateMockWrite(settings_ack, 1), CreateMockWrite(settings_ack, 4),
CreateMockWrite(settings_ack, 7), CreateMockWrite(goaway, 8)};
SequencedSocketData data(reads, writes);
session_deps_.socket_factory->AddSocketDataProvider(&data);
AddSSLSocketData();
CreateNetworkSession();
CreateSpdySession();
base::RunLoop().RunUntilIdle();
data.Resume();
base::RunLoop().RunUntilIdle();
data.Resume();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(data.AllWriteDataConsumed());
EXPECT_TRUE(data.AllReadDataConsumed());
}
} // namespace net
......@@ -348,7 +348,8 @@ SpdySessionDependencies::SpdySessionDependencies(
net_log(nullptr),
disable_idle_sockets_close_on_memory_pressure(false),
enable_early_data(false),
key_auth_cache_server_entries_by_network_isolation_key(false) {
key_auth_cache_server_entries_by_network_isolation_key(false),
enable_priority_update(false) {
http2_settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] =
kDefaultInitialWindowSize;
}
......@@ -406,6 +407,7 @@ HttpNetworkSession::Params SpdySessionDependencies::CreateSessionParams(
params.enable_early_data = session_deps->enable_early_data;
params.key_auth_cache_server_entries_by_network_isolation_key =
session_deps->key_auth_cache_server_entries_by_network_isolation_key;
params.enable_priority_update = session_deps->enable_priority_update;
return params;
}
......
......@@ -238,6 +238,7 @@ struct SpdySessionDependencies {
bool disable_idle_sockets_close_on_memory_pressure;
bool enable_early_data;
bool key_auth_cache_server_entries_by_network_isolation_key;
bool enable_priority_update;
};
class SpdyURLRequestContext : public URLRequestContext {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment