Commit 6a070bcd authored by Bence Béky's avatar Bence Béky Committed by Commit Bot

Implement GREASE for HTTP/2.

Send one extra setting with a random reserved identifier and random
value in the initial SETTINGS frame.  Send a short frame of a random
reserved type, with random flags and payload, after every SETTINGS and
HEADERS frame sent, on the same stream.

The two behaviors are gated by separate field trials.

Send the same greased settings identifier and value on every connection.
Send the same greased frame type, flags, and payload on every
connection.  This is to prevent the retry logic from hiding bogus
servers.

Reserved settings identifiers and frame types are described at
https://tools.ietf.org/html/draft-bishop-httpbis-grease-00.

Bug: 841264
Change-Id: Ie1bd1e4f106bf64020f45171e350d37a10815bc8
Reviewed-on: https://chromium-review.googlesource.com/1207750
Commit-Queue: Bence Béky <bnc@chromium.org>
Reviewed-by: default avatarRyan Hamilton <rch@chromium.org>
Cr-Commit-Position: refs/heads/master@{#589168}
parent 9b85bf74
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "components/network_session_configurator/browser/network_session_configurator.h" #include "components/network_session_configurator/browser/network_session_configurator.h"
#include <limits>
#include <map> #include <map>
#include <unordered_set> #include <unordered_set>
#include <utility> #include <utility>
...@@ -13,6 +14,7 @@ ...@@ -13,6 +14,7 @@
#include "base/feature_list.h" #include "base/feature_list.h"
#include "base/metrics/field_trial.h" #include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "base/strings/string_split.h" #include "base/strings/string_split.h"
...@@ -24,6 +26,7 @@ ...@@ -24,6 +26,7 @@
#include "net/base/host_mapping_rules.h" #include "net/base/host_mapping_rules.h"
#include "net/http/http_stream_factory.h" #include "net/http/http_stream_factory.h"
#include "net/quic/quic_utils_chromium.h" #include "net/quic/quic_utils_chromium.h"
#include "net/spdy/spdy_session_pool.h"
#include "net/third_party/quic/core/quic_packets.h" #include "net/third_party/quic/core/quic_packets.h"
#include "net/third_party/spdy/core/spdy_protocol.h" #include "net/third_party/spdy/core/spdy_protocol.h"
...@@ -123,7 +126,36 @@ void ConfigureHttp2Params(const base::CommandLine& command_line, ...@@ -123,7 +126,36 @@ void ConfigureHttp2Params(const base::CommandLine& command_line,
params->enable_http2 = false; params->enable_http2 = false;
return; return;
} }
// After parsing initial settings, optionally add a setting with reserved
// identifier to "grease" settings, see
// https://tools.ietf.org/html/draft-bishop-httpbis-grease-00.
params->http2_settings = GetHttp2Settings(http2_trial_params); params->http2_settings = GetHttp2Settings(http2_trial_params);
if (GetVariationParam(http2_trial_params, "http2_grease_settings") ==
"true") {
spdy::SpdySettingsId id = 0x0a0a + 0x1000 * base::RandGenerator(0xf + 1) +
0x0010 * base::RandGenerator(0xf + 1);
uint32_t value = base::RandGenerator(
static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()) + 1);
params->http2_settings.insert(std::make_pair(id, value));
}
// Optionally define a frame of reserved type to "grease" frame types, see
// https://tools.ietf.org/html/draft-bishop-httpbis-grease-00.
if (GetVariationParam(http2_trial_params, "http2_grease_frame_type") ==
"true") {
const uint8_t type = 0x0b + 0x1f * base::RandGenerator(8);
const uint8_t flags =
base::RandGenerator(std::numeric_limits<uint8_t>::max() + 1);
const size_t length = base::RandGenerator(7);
// RandBytesAsString() does not support zero length.
const std::string payload =
(length > 0) ? base::RandBytesAsString(length) : std::string();
params->greased_http2_frame =
base::Optional<net::SpdySessionPool::GreasedHttp2Frame>(
{type, flags, payload});
}
params->enable_websocket_over_http2 = params->enable_websocket_over_http2 =
ConfigureWebsocketOverHttp2(command_line, http2_trial_params); ConfigureWebsocketOverHttp2(command_line, http2_trial_params);
} }
......
...@@ -64,6 +64,7 @@ TEST_F(NetworkSessionConfiguratorTest, Defaults) { ...@@ -64,6 +64,7 @@ TEST_F(NetworkSessionConfiguratorTest, Defaults) {
EXPECT_TRUE(params_.enable_http2); EXPECT_TRUE(params_.enable_http2);
EXPECT_TRUE(params_.http2_settings.empty()); EXPECT_TRUE(params_.http2_settings.empty());
EXPECT_FALSE(params_.greased_http2_frame);
EXPECT_FALSE(params_.enable_websocket_over_http2); EXPECT_FALSE(params_.enable_websocket_over_http2);
EXPECT_FALSE(params_.enable_quic); EXPECT_FALSE(params_.enable_quic);
...@@ -796,6 +797,37 @@ TEST_F(NetworkSessionConfiguratorTest, QuicHeadersIncludeH2StreamDependency) { ...@@ -796,6 +797,37 @@ TEST_F(NetworkSessionConfiguratorTest, QuicHeadersIncludeH2StreamDependency) {
EXPECT_TRUE(params_.quic_headers_include_h2_stream_dependency); EXPECT_TRUE(params_.quic_headers_include_h2_stream_dependency);
} }
TEST_F(NetworkSessionConfiguratorTest, Http2GreaseSettings) {
std::map<std::string, std::string> field_trial_params;
field_trial_params["http2_grease_settings"] = "true";
variations::AssociateVariationParams("HTTP2", "Enabled", field_trial_params);
base::FieldTrialList::CreateFieldTrial("HTTP2", "Enabled");
ParseFieldTrials();
bool greased_setting_found = false;
for (const auto& setting : params_.http2_settings) {
if ((setting.first & 0x0f0f) == 0x0a0a) {
greased_setting_found = true;
break;
}
}
EXPECT_TRUE(greased_setting_found);
}
TEST_F(NetworkSessionConfiguratorTest, Http2GreaseFrameType) {
std::map<std::string, std::string> field_trial_params;
field_trial_params["http2_grease_frame_type"] = "true";
variations::AssociateVariationParams("HTTP2", "Enabled", field_trial_params);
base::FieldTrialList::CreateFieldTrial("HTTP2", "Enabled");
ParseFieldTrials();
ASSERT_TRUE(params_.greased_http2_frame);
const uint8_t frame_type = params_.greased_http2_frame.value().type;
EXPECT_EQ(0x0b, frame_type % 0x1f);
}
TEST_F(NetworkSessionConfiguratorTest, TEST_F(NetworkSessionConfiguratorTest,
WebsocketOverHttp2EnabledFromCommandLine) { WebsocketOverHttp2EnabledFromCommandLine) {
base::CommandLine command_line(base::CommandLine::NO_PROGRAM); base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
......
...@@ -244,6 +244,7 @@ HttpNetworkSession::HttpNetworkSession(const Params& params, ...@@ -244,6 +244,7 @@ HttpNetworkSession::HttpNetworkSession(const Params& params,
params.support_ietf_format_quic_altsvc, params.support_ietf_format_quic_altsvc,
params.spdy_session_max_recv_window_size, params.spdy_session_max_recv_window_size,
AddDefaultHttp2Settings(params.http2_settings), AddDefaultHttp2Settings(params.http2_settings),
params.greased_http2_frame,
params.time_func), params.time_func),
http_stream_factory_(std::make_unique<HttpStreamFactory>(this)), http_stream_factory_(std::make_unique<HttpStreamFactory>(this)),
params_(params), params_(params),
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "base/memory/memory_pressure_monitor.h" #include "base/memory/memory_pressure_monitor.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/threading/thread_checker.h" #include "base/threading/thread_checker.h"
#include "net/base/host_mapping_rules.h" #include "net/base/host_mapping_rules.h"
#include "net/base/host_port_pair.h" #include "net/base/host_port_pair.h"
...@@ -113,7 +114,18 @@ class NET_EXPORT HttpNetworkSession : public base::MemoryCoordinatorClient { ...@@ -113,7 +114,18 @@ class NET_EXPORT HttpNetworkSession : public base::MemoryCoordinatorClient {
size_t spdy_session_max_recv_window_size; size_t spdy_session_max_recv_window_size;
// HTTP/2 connection settings. // HTTP/2 connection settings.
// Unknown settings will still be sent to the server. // Unknown settings will still be sent to the server.
// Might contain unknown setting identifiers from a predefined set that
// servers are supposed to ignore, see
// https://tools.ietf.org/html/draft-bishop-httpbis-grease-00.
// The same setting will be sent on every connection to prevent the retry
// logic from hiding broken servers.
spdy::SettingsMap http2_settings; spdy::SettingsMap http2_settings;
// If set, an HTTP/2 frame with a reserved frame type will be sent after
// every HEADERS and SETTINGS frame. See
// https://tools.ietf.org/html/draft-bishop-httpbis-grease-00.
// The same frame will be sent out on all connections to prevent the retry
// logic from hiding broken servers.
base::Optional<SpdySessionPool::GreasedHttp2Frame> greased_http2_frame;
// Source of time for SPDY connections. // Source of time for SPDY connections.
SpdySessionPool::TimeFunc time_func; SpdySessionPool::TimeFunc time_func;
// Whether to enable HTTP/2 Alt-Svc entries. // Whether to enable HTTP/2 Alt-Svc entries.
......
...@@ -152,6 +152,42 @@ enum PushedStreamVaryResponseHeaderValues ParseVaryInPushedResponse( ...@@ -152,6 +152,42 @@ enum PushedStreamVaryResponseHeaderValues ParseVaryInPushedResponse(
return kVaryHasNoAcceptEncoding; return kVaryHasNoAcceptEncoding;
} }
// A SpdyBufferProducer implementation that creates an HTTP/2 frame by adding
// stream ID to greased frame parameters.
class GreasedBufferProducer : public SpdyBufferProducer {
public:
GreasedBufferProducer() = delete;
GreasedBufferProducer(
base::WeakPtr<SpdyStream> stream,
const SpdySessionPool::GreasedHttp2Frame* greased_http2_frame,
BufferedSpdyFramer* buffered_spdy_framer)
: stream_(stream),
greased_http2_frame_(greased_http2_frame),
buffered_spdy_framer_(buffered_spdy_framer) {}
~GreasedBufferProducer() override = default;
std::unique_ptr<SpdyBuffer> ProduceBuffer() override {
const spdy::SpdyStreamId stream_id = stream_ ? stream_->stream_id() : 0;
spdy::SpdyUnknownIR frame(stream_id, greased_http2_frame_->type,
greased_http2_frame_->flags,
greased_http2_frame_->payload);
auto serialized_frame = std::make_unique<spdy::SpdySerializedFrame>(
buffered_spdy_framer_->SerializeFrame(frame));
return std::make_unique<SpdyBuffer>(std::move(serialized_frame));
}
size_t EstimateMemoryUsage() const override {
return base::trace_event::EstimateMemoryUsage(
greased_http2_frame_->payload);
}
private:
base::WeakPtr<SpdyStream> stream_;
const SpdySessionPool::GreasedHttp2Frame* const greased_http2_frame_;
BufferedSpdyFramer* buffered_spdy_framer_;
};
bool IsSpdySettingAtDefaultInitialValue(spdy::SpdySettingsId setting_id, bool IsSpdySettingAtDefaultInitialValue(spdy::SpdySettingsId setting_id,
uint32_t value) { uint32_t value) {
switch (setting_id) { switch (setting_id) {
...@@ -784,6 +820,8 @@ SpdySession::SpdySession( ...@@ -784,6 +820,8 @@ SpdySession::SpdySession(
bool is_trusted_proxy, bool is_trusted_proxy,
size_t session_max_recv_window_size, size_t session_max_recv_window_size,
const spdy::SettingsMap& initial_settings, const spdy::SettingsMap& initial_settings,
const base::Optional<SpdySessionPool::GreasedHttp2Frame>&
greased_http2_frame,
TimeFunc time_func, TimeFunc time_func,
ServerPushDelegate* push_delegate, ServerPushDelegate* push_delegate,
NetLog* net_log) NetLog* net_log)
...@@ -807,6 +845,7 @@ SpdySession::SpdySession( ...@@ -807,6 +845,7 @@ SpdySession::SpdySession(
write_state_(WRITE_STATE_IDLE), write_state_(WRITE_STATE_IDLE),
error_on_close_(OK), error_on_close_(OK),
initial_settings_(initial_settings), initial_settings_(initial_settings),
greased_http2_frame_(greased_http2_frame),
max_concurrent_streams_(kInitialMaxConcurrentStreams), max_concurrent_streams_(kInitialMaxConcurrentStreams),
max_concurrent_pushed_streams_( max_concurrent_pushed_streams_(
initial_settings.at(spdy::SETTINGS_MAX_CONCURRENT_STREAMS)), initial_settings.at(spdy::SETTINGS_MAX_CONCURRENT_STREAMS)),
...@@ -854,6 +893,12 @@ SpdySession::SpdySession( ...@@ -854,6 +893,12 @@ SpdySession::SpdySession(
DCHECK( DCHECK(
base::ContainsKey(initial_settings_, spdy::SETTINGS_INITIAL_WINDOW_SIZE)); base::ContainsKey(initial_settings_, spdy::SETTINGS_INITIAL_WINDOW_SIZE));
if (greased_http2_frame_) {
// See https://tools.ietf.org/html/draft-bishop-httpbis-grease-00
// for reserved frame types.
DCHECK_EQ(0x0b, greased_http2_frame_.value().type % 0x1f);
}
// TODO(mbelshe): consider randomization of the stream_hi_water_mark. // TODO(mbelshe): consider randomization of the stream_hi_water_mark.
} }
...@@ -2558,6 +2603,15 @@ void SpdySession::EnqueueWrite( ...@@ -2558,6 +2603,15 @@ void SpdySession::EnqueueWrite(
write_queue_.Enqueue(priority, frame_type, std::move(producer), stream, write_queue_.Enqueue(priority, frame_type, std::move(producer), stream,
traffic_annotation); traffic_annotation);
if (greased_http2_frame_ && (frame_type == spdy::SpdyFrameType::SETTINGS ||
frame_type == spdy::SpdyFrameType::HEADERS)) {
write_queue_.Enqueue(
priority,
static_cast<spdy::SpdyFrameType>(greased_http2_frame_.value().type),
std::make_unique<GreasedBufferProducer>(
stream, &greased_http2_frame_.value(), buffered_spdy_framer_.get()),
stream, traffic_annotation);
}
MaybePostWriteLoop(); MaybePostWriteLoop();
} }
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "net/base/completion_once_callback.h" #include "net/base/completion_once_callback.h"
...@@ -303,6 +304,8 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface, ...@@ -303,6 +304,8 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
bool is_trusted_proxy, bool is_trusted_proxy,
size_t session_max_recv_window_size, size_t session_max_recv_window_size,
const spdy::SettingsMap& initial_settings, const spdy::SettingsMap& initial_settings,
const base::Optional<SpdySessionPool::GreasedHttp2Frame>&
greased_http2_frame,
TimeFunc time_func, TimeFunc time_func,
ServerPushDelegate* push_delegate, ServerPushDelegate* push_delegate,
NetLog* net_log); NetLog* net_log);
...@@ -1030,6 +1033,11 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface, ...@@ -1030,6 +1033,11 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
// and maximum HPACK dynamic table size. // and maximum HPACK dynamic table size.
const spdy::SettingsMap initial_settings_; const spdy::SettingsMap initial_settings_;
// If set, an HTTP/2 frame with a reserved frame type will be sent after every
// valid HTTP/2 frame. See
// https://tools.ietf.org/html/draft-bishop-httpbis-grease-00.
const base::Optional<SpdySessionPool::GreasedHttp2Frame> greased_http2_frame_;
// Limits // Limits
size_t max_concurrent_streams_; size_t max_concurrent_streams_;
size_t max_concurrent_pushed_streams_; size_t max_concurrent_pushed_streams_;
......
...@@ -56,6 +56,7 @@ SpdySessionPool::SpdySessionPool( ...@@ -56,6 +56,7 @@ SpdySessionPool::SpdySessionPool(
bool support_ietf_format_quic_altsvc, bool support_ietf_format_quic_altsvc,
size_t session_max_recv_window_size, size_t session_max_recv_window_size,
const spdy::SettingsMap& initial_settings, const spdy::SettingsMap& initial_settings,
const base::Optional<GreasedHttp2Frame>& greased_http2_frame,
SpdySessionPool::TimeFunc time_func) SpdySessionPool::TimeFunc time_func)
: http_server_properties_(http_server_properties), : http_server_properties_(http_server_properties),
transport_security_state_(transport_security_state), transport_security_state_(transport_security_state),
...@@ -68,6 +69,7 @@ SpdySessionPool::SpdySessionPool( ...@@ -68,6 +69,7 @@ SpdySessionPool::SpdySessionPool(
support_ietf_format_quic_altsvc_(support_ietf_format_quic_altsvc), support_ietf_format_quic_altsvc_(support_ietf_format_quic_altsvc),
session_max_recv_window_size_(session_max_recv_window_size), session_max_recv_window_size_(session_max_recv_window_size),
initial_settings_(initial_settings), initial_settings_(initial_settings),
greased_http2_frame_(greased_http2_frame),
time_func_(time_func), time_func_(time_func),
push_delegate_(nullptr) { push_delegate_(nullptr) {
NetworkChangeNotifier::AddIPAddressObserver(this); NetworkChangeNotifier::AddIPAddressObserver(this);
...@@ -110,8 +112,8 @@ base::WeakPtr<SpdySession> SpdySessionPool::CreateAvailableSessionFromSocket( ...@@ -110,8 +112,8 @@ base::WeakPtr<SpdySession> SpdySessionPool::CreateAvailableSessionFromSocket(
ssl_config_service_, quic_supported_versions_, ssl_config_service_, quic_supported_versions_,
enable_sending_initial_data_, enable_ping_based_connection_checking_, enable_sending_initial_data_, enable_ping_based_connection_checking_,
support_ietf_format_quic_altsvc_, is_trusted_proxy, support_ietf_format_quic_altsvc_, is_trusted_proxy,
session_max_recv_window_size_, initial_settings_, time_func_, session_max_recv_window_size_, initial_settings_, greased_http2_frame_,
push_delegate_, net_log.net_log()); time_func_, push_delegate_, net_log.net_log());
new_session->InitializeWithSocket(std::move(connection), this); new_session->InitializeWithSocket(std::move(connection), this);
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "net/base/host_port_pair.h" #include "net/base/host_port_pair.h"
#include "net/base/ip_endpoint.h" #include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
...@@ -56,6 +57,16 @@ class NET_EXPORT SpdySessionPool ...@@ -56,6 +57,16 @@ class NET_EXPORT SpdySessionPool
public: public:
typedef base::TimeTicks (*TimeFunc)(void); typedef base::TimeTicks (*TimeFunc)(void);
// Struct to hold randomly generated frame parameters to be used for sending
// frames on the wire to "grease" frame type. Frame type has to be one of
// the reserved values defined in
// https://tools.ietf.org/html/draft-bishop-httpbis-grease-00.
struct GreasedHttp2Frame {
uint8_t type;
uint8_t flags;
std::string payload;
};
SpdySessionPool( SpdySessionPool(
HostResolver* host_resolver, HostResolver* host_resolver,
SSLConfigService* ssl_config_service, SSLConfigService* ssl_config_service,
...@@ -66,6 +77,7 @@ class NET_EXPORT SpdySessionPool ...@@ -66,6 +77,7 @@ class NET_EXPORT SpdySessionPool
bool support_ietf_format_quic_altsvc, bool support_ietf_format_quic_altsvc,
size_t session_max_recv_window_size, size_t session_max_recv_window_size,
const spdy::SettingsMap& initial_settings, const spdy::SettingsMap& initial_settings,
const base::Optional<GreasedHttp2Frame>& greased_http2_frame,
SpdySessionPool::TimeFunc time_func); SpdySessionPool::TimeFunc time_func);
~SpdySessionPool() override; ~SpdySessionPool() override;
...@@ -276,6 +288,11 @@ class NET_EXPORT SpdySessionPool ...@@ -276,6 +288,11 @@ class NET_EXPORT SpdySessionPool
// and maximum HPACK dynamic table size. // and maximum HPACK dynamic table size.
const spdy::SettingsMap initial_settings_; const spdy::SettingsMap initial_settings_;
// If set, an HTTP/2 frame with a reserved frame type will be sent after every
// valid HTTP/2 frame. See
// https://tools.ietf.org/html/draft-bishop-httpbis-grease-00.
const base::Optional<GreasedHttp2Frame> greased_http2_frame_;
// TODO(xunjieli): Merge these two. // TODO(xunjieli): Merge these two.
SpdySessionRequestMap spdy_session_request_map_; SpdySessionRequestMap spdy_session_request_map_;
typedef std::map<SpdySessionKey, std::list<base::Closure>> typedef std::map<SpdySessionKey, std::list<base::Closure>>
......
...@@ -12,9 +12,11 @@ ...@@ -12,9 +12,11 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/test/metrics/histogram_tester.h" #include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h" #include "base/test/scoped_task_environment.h"
#include "net/base/hex_utils.h"
#include "net/base/host_port_pair.h" #include "net/base/host_port_pair.h"
#include "net/base/io_buffer.h" #include "net/base/io_buffer.h"
#include "net/base/ip_endpoint.h" #include "net/base/ip_endpoint.h"
...@@ -5890,6 +5892,96 @@ TEST_F(SpdySessionTest, EnableWebSocketThenDisableIsProtocolError) { ...@@ -5890,6 +5892,96 @@ TEST_F(SpdySessionTest, EnableWebSocketThenDisableIsProtocolError) {
EXPECT_FALSE(session_); EXPECT_FALSE(session_);
} }
TEST_F(SpdySessionTest, GreaseFrameType) {
const uint8_t type = 0x0b;
const uint8_t flags = 0xcc;
const std::string payload("foo");
session_deps_.greased_http2_frame =
base::Optional<net::SpdySessionPool::GreasedHttp2Frame>(
{type, flags, payload});
// Connection preface.
spdy::SpdySerializedFrame preface(
const_cast<char*>(spdy::kHttp2ConnectionHeaderPrefix),
spdy::kHttp2ConnectionHeaderPrefixSize,
/* owns_buffer = */ false);
// Initial SETTINGS frame.
spdy::SettingsMap expected_settings;
expected_settings[spdy::SETTINGS_HEADER_TABLE_SIZE] = kSpdyMaxHeaderTableSize;
expected_settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] =
kSpdyMaxConcurrentPushedStreams;
spdy::SpdySerializedFrame settings_frame(
spdy_util_.ConstructSpdySettings(expected_settings));
spdy::SpdySerializedFrame combined_frame =
CombineFrames({&preface, &settings_frame});
// Greased frame sent on stream 0 after initial SETTINGS frame.
const char kRawFrameData0[] = {
0x00, 0x00, 0x03, // length
0x0b, // type
0xcc, // flags
0x00, 0x00, 0x00, 0x00, // stream ID
'f', 'o', 'o' // payload
};
spdy::SpdySerializedFrame grease0(const_cast<char*>(kRawFrameData0),
base::size(kRawFrameData0),
/* owns_buffer = */ false);
spdy::SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, DEFAULT_PRIORITY));
// Greased frame sent on stream 1 after request.
const char kRawFrameData1[] = {
0x00, 0x00, 0x03, // length
0x0b, // type
0xcc, // flags
0x00, 0x00, 0x00, 0x01, // stream ID
'f', 'o', 'o' // payload
};
spdy::SpdySerializedFrame grease1(const_cast<char*>(kRawFrameData1),
base::size(kRawFrameData1),
/* owns_buffer = */ false);
MockWrite writes[] = {CreateMockWrite(combined_frame, 0),
CreateMockWrite(grease0, 1), CreateMockWrite(req, 2),
CreateMockWrite(grease1, 3)};
spdy::SpdySerializedFrame resp(
spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {CreateMockRead(resp, 4), CreateMockRead(body, 5),
MockRead(ASYNC, 0, 6)};
SequencedSocketData data(reads, writes);
session_deps_.socket_factory->AddSocketDataProvider(&data);
AddSSLSocketData();
CreateNetworkSession();
SpdySessionPoolPeer pool_peer(spdy_session_pool_);
pool_peer.SetEnableSendingInitialData(true);
CreateSpdySession();
base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, DEFAULT_PRIORITY,
NetLogWithSource());
test::StreamDelegateDoNothing delegate(stream);
stream->SetDelegate(&delegate);
stream->SendRequestHeaders(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl),
NO_MORE_DATA_TO_SEND);
EXPECT_THAT(delegate.WaitForClose(), IsOk());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(data.AllWriteDataConsumed());
EXPECT_TRUE(data.AllReadDataConsumed());
}
enum ReadIfReadySupport { enum ReadIfReadySupport {
// ReadIfReady() field trial is enabled, and ReadIfReady() is implemented. // ReadIfReady() field trial is enabled, and ReadIfReady() is implemented.
READ_IF_READY_ENABLED_SUPPORTED, READ_IF_READY_ENABLED_SUPPORTED,
......
...@@ -586,6 +586,12 @@ void SpdyStream::OnFrameWriteComplete(spdy::SpdyFrameType frame_type, ...@@ -586,6 +586,12 @@ void SpdyStream::OnFrameWriteComplete(spdy::SpdyFrameType frame_type,
return; return;
} }
// Frame types reserved in
// https://tools.ietf.org/html/draft-bishop-httpbis-grease-00 ought to be
// ignored.
if (static_cast<uint8_t>(frame_type) % 0x1f == 0x0b)
return;
DCHECK_NE(type_, SPDY_PUSH_STREAM); DCHECK_NE(type_, SPDY_PUSH_STREAM);
CHECK(frame_type == spdy::SpdyFrameType::HEADERS || CHECK(frame_type == spdy::SpdyFrameType::HEADERS ||
frame_type == spdy::SpdyFrameType::DATA) frame_type == spdy::SpdyFrameType::DATA)
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include "net/socket/transport_client_socket_pool.h" #include "net/socket/transport_client_socket_pool.h"
#include "net/spdy/buffered_spdy_framer.h" #include "net/spdy/buffered_spdy_framer.h"
#include "net/spdy/spdy_http_utils.h" #include "net/spdy/spdy_http_utils.h"
#include "net/spdy/spdy_session_pool.h"
#include "net/spdy/spdy_stream.h" #include "net/spdy/spdy_stream.h"
#include "net/test/gtest_util.h" #include "net/test/gtest_util.h"
#include "net/third_party/spdy/core/spdy_alt_svc_wire_format.h" #include "net/third_party/spdy/core/spdy_alt_svc_wire_format.h"
...@@ -385,6 +384,7 @@ HttpNetworkSession::Params SpdySessionDependencies::CreateSessionParams( ...@@ -385,6 +384,7 @@ HttpNetworkSession::Params SpdySessionDependencies::CreateSessionParams(
session_deps->enable_http2_alternative_service; session_deps->enable_http2_alternative_service;
params.enable_websocket_over_http2 = params.enable_websocket_over_http2 =
session_deps->enable_websocket_over_http2; session_deps->enable_websocket_over_http2;
params.greased_http2_frame = session_deps->greased_http2_frame;
params.http_09_on_non_default_ports_enabled = params.http_09_on_non_default_ports_enabled =
session_deps->http_09_on_non_default_ports_enabled; session_deps->http_09_on_non_default_ports_enabled;
params.disable_idle_sockets_close_on_memory_pressure = params.disable_idle_sockets_close_on_memory_pressure =
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "net/proxy_resolution/proxy_resolution_service.h" #include "net/proxy_resolution/proxy_resolution_service.h"
#include "net/socket/socket_test_util.h" #include "net/socket/socket_test_util.h"
#include "net/spdy/spdy_session.h" #include "net/spdy/spdy_session.h"
#include "net/spdy/spdy_session_pool.h"
#include "net/ssl/ssl_config_service_defaults.h" #include "net/ssl/ssl_config_service_defaults.h"
#include "net/third_party/spdy/core/spdy_protocol.h" #include "net/third_party/spdy/core/spdy_protocol.h"
#include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context.h"
...@@ -49,7 +50,6 @@ class HashValue; ...@@ -49,7 +50,6 @@ class HashValue;
class HostPortPair; class HostPortPair;
class NetLogWithSource; class NetLogWithSource;
class SpdySessionKey; class SpdySessionKey;
class SpdySessionPool;
class SpdyStream; class SpdyStream;
class SpdyStreamRequest; class SpdyStreamRequest;
class TransportSecurityState; class TransportSecurityState;
...@@ -215,6 +215,7 @@ struct SpdySessionDependencies { ...@@ -215,6 +215,7 @@ struct SpdySessionDependencies {
std::unique_ptr<ProxyDelegate> proxy_delegate; std::unique_ptr<ProxyDelegate> proxy_delegate;
bool enable_http2_alternative_service; bool enable_http2_alternative_service;
bool enable_websocket_over_http2; bool enable_websocket_over_http2;
base::Optional<SpdySessionPool::GreasedHttp2Frame> greased_http2_frame;
NetLog* net_log; NetLog* net_log;
bool http_09_on_non_default_ports_enabled; bool http_09_on_non_default_ports_enabled;
bool disable_idle_sockets_close_on_memory_pressure; bool disable_idle_sockets_close_on_memory_pressure;
......
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