Commit 02b906a3 authored by Bence Béky's avatar Bence Béky Committed by Commit Bot

Reject HTTP/2 pushed streams when push is disabled.

Bug: 862805
Change-Id: I327807a7ca854cf97986008ccd9482cd8ccaa1b2
Reviewed-on: https://chromium-review.googlesource.com/1141282
Commit-Queue: Ryan Hamilton <rch@chromium.org>
Reviewed-by: default avatarRyan Hamilton <rch@chromium.org>
Cr-Commit-Position: refs/heads/master@{#576203}
parent 224ba0fb
...@@ -2743,6 +2743,55 @@ TEST_F(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) { ...@@ -2743,6 +2743,55 @@ TEST_F(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) {
EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine()); EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
} }
// When server push is disabled by
// HttpNetworkSession::initial_settings[SETTINGS_ENABLE_PUSH] = 0, verify that
// such a setting is sent out in the initial SETTINGS frame, and if the server
// creates a pushed stream despite of this, it is immediately reset.
TEST_F(SpdyNetworkTransactionTest, ServerPushDisabled) {
spdy::SpdySerializedFrame preface(
const_cast<char*>(spdy::kHttp2ConnectionHeaderPrefix),
spdy::kHttp2ConnectionHeaderPrefixSize,
/* owns_buffer = */ false);
spdy::SettingsMap initial_settings;
initial_settings[spdy::SETTINGS_HEADER_TABLE_SIZE] = kSpdyMaxHeaderTableSize;
initial_settings[spdy::SETTINGS_ENABLE_PUSH] = 0;
initial_settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] =
kSpdyMaxConcurrentPushedStreams;
spdy::SpdySerializedFrame initial_settings_frame(
spdy_util_.ConstructSpdySettings(initial_settings));
spdy::SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
spdy::SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
MockWrite writes[] = {CreateMockWrite(preface, 0),
CreateMockWrite(initial_settings_frame, 1),
CreateMockWrite(req, 2), CreateMockWrite(rst, 5)};
spdy::SpdySerializedFrame reply(
spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
spdy::SpdySerializedFrame push(
spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {CreateMockRead(reply, 3), CreateMockRead(push, 4),
CreateMockRead(body, 6), MockRead(ASYNC, OK, 7)};
SequencedSocketData data(reads, writes);
auto session_deps = std::make_unique<SpdySessionDependencies>();
session_deps->http2_settings[spdy::SETTINGS_ENABLE_PUSH] = 0;
NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
std::move(session_deps));
SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
SpdySessionPoolPeer pool_peer(spdy_session_pool);
pool_peer.SetEnableSendingInitialData(true);
helper.RunToCompletion(&data);
}
TEST_F(SpdyNetworkTransactionTest, ServerPushHeadMethod) { TEST_F(SpdyNetworkTransactionTest, ServerPushHeadMethod) {
spdy::SpdySerializedFrame req( spdy::SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST)); spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
......
...@@ -177,6 +177,16 @@ bool IsSpdySettingAtDefaultInitialValue(spdy::SpdySettingsId setting_id, ...@@ -177,6 +177,16 @@ bool IsSpdySettingAtDefaultInitialValue(spdy::SpdySettingsId setting_id,
} }
} }
bool IsPushEnabled(const spdy::SettingsMap& initial_settings) {
const auto it = initial_settings.find(spdy::SETTINGS_ENABLE_PUSH);
// Push is enabled by default.
if (it == initial_settings.end())
return true;
return it->second == 1;
}
std::unique_ptr<base::Value> NetLogSpdyHeadersSentCallback( std::unique_ptr<base::Value> NetLogSpdyHeadersSentCallback(
const spdy::SpdyHeaderBlock* headers, const spdy::SpdyHeaderBlock* headers,
bool fin, bool fin,
...@@ -820,6 +830,7 @@ SpdySession::SpdySession( ...@@ -820,6 +830,7 @@ SpdySession::SpdySession(
enable_ping_based_connection_checking), enable_ping_based_connection_checking),
support_ietf_format_quic_altsvc_(support_ietf_format_quic_altsvc), support_ietf_format_quic_altsvc_(support_ietf_format_quic_altsvc),
is_trusted_proxy_(is_trusted_proxy), is_trusted_proxy_(is_trusted_proxy),
enable_push_(IsPushEnabled(initial_settings)),
support_websocket_(false), support_websocket_(false),
connection_at_risk_of_loss_time_( connection_at_risk_of_loss_time_(
base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)), base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)),
...@@ -1637,6 +1648,19 @@ void SpdySession::ProcessPendingStreamRequests() { ...@@ -1637,6 +1648,19 @@ void SpdySession::ProcessPendingStreamRequests() {
void SpdySession::TryCreatePushStream(spdy::SpdyStreamId stream_id, void SpdySession::TryCreatePushStream(spdy::SpdyStreamId stream_id,
spdy::SpdyStreamId associated_stream_id, spdy::SpdyStreamId associated_stream_id,
spdy::SpdyHeaderBlock headers) { spdy::SpdyHeaderBlock headers) {
// Pushed streams are speculative, so they start at an IDLE priority.
// TODO(bnc): Send pushed stream cancellation with higher priority to avoid
// wasting bandwidth.
const RequestPriority request_priority = IDLE;
if (!enable_push_) {
// TODO(bnc): Call RecordSpdyPushedStreamFateHistogram().
EnqueueResetStreamFrame(stream_id, request_priority,
spdy::ERROR_CODE_REFUSED_STREAM,
"Push is disabled.");
return;
}
if ((stream_id & 0x1) != 0) { if ((stream_id & 0x1) != 0) {
std::string description = base::StringPrintf( std::string description = base::StringPrintf(
"Received invalid pushed stream id %d (must be even) on stream id %d.", "Received invalid pushed stream id %d (must be even) on stream id %d.",
...@@ -1676,9 +1700,6 @@ void SpdySession::TryCreatePushStream(spdy::SpdyStreamId stream_id, ...@@ -1676,9 +1700,6 @@ void SpdySession::TryCreatePushStream(spdy::SpdyStreamId stream_id,
last_accepted_push_stream_id_ = stream_id; last_accepted_push_stream_id_ = stream_id;
// Pushed streams are speculative, so they start at an IDLE priority.
const RequestPriority request_priority = IDLE;
if (availability_state_ == STATE_GOING_AWAY) { if (availability_state_ == STATE_GOING_AWAY) {
RecordSpdyPushedStreamFateHistogram(SpdyPushedStreamFate::kGoingAway); RecordSpdyPushedStreamFateHistogram(SpdyPushedStreamFate::kGoingAway);
EnqueueResetStreamFrame(stream_id, request_priority, EnqueueResetStreamFrame(stream_id, request_priority,
......
...@@ -1099,16 +1099,20 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface, ...@@ -1099,16 +1099,20 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
const quic::QuicTransportVersionVector quic_supported_versions_; const quic::QuicTransportVersionVector quic_supported_versions_;
// Outside of tests, these should always be true. // Outside of tests, these should always be true.
bool enable_sending_initial_data_; const bool enable_sending_initial_data_;
bool enable_ping_based_connection_checking_; const bool enable_ping_based_connection_checking_;
// If true, alt-svc headers advertising QUIC in IETF format will be supported. // If true, alt-svc headers advertising QUIC in IETF format will be supported.
bool support_ietf_format_quic_altsvc_; const bool support_ietf_format_quic_altsvc_;
// If true, this session is being made to a trusted SPDY/HTTP2 proxy that is // If true, this session is being made to a trusted SPDY/HTTP2 proxy that is
// allowed to push cross-origin resources. // allowed to push cross-origin resources.
const bool is_trusted_proxy_; const bool is_trusted_proxy_;
// If true, accept pushed streams from server.
// If false, reset pushed streams immediately.
const bool enable_push_;
// True if the server has advertised WebSocket support via // True if the server has advertised WebSocket support via
// spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL, see // spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL, see
// https://tools.ietf.org/html/draft-ietf-httpbis-h2-websockets-00. // https://tools.ietf.org/html/draft-ietf-httpbis-h2-websockets-00.
......
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