Skip to content

Commit

Permalink
http2: support custom SETTINGS parameters (#9964)
Browse files Browse the repository at this point in the history
Signed-off-by: Andres Guedez <aguedez@google.com>
  • Loading branch information
AndresGuedez authored Mar 19, 2020
1 parent 404d73c commit 56e5b84
Show file tree
Hide file tree
Showing 46 changed files with 1,214 additions and 417 deletions.
43 changes: 42 additions & 1 deletion api/envoy/api/v2/core/protocol.proto
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,21 @@ message Http1ProtocolOptions {
bool enable_trailers = 5;
}

// [#next-free-field: 13]
// [#next-free-field: 14]
message Http2ProtocolOptions {
// Defines a parameter to be sent in the SETTINGS frame.
// See `RFC7540, sec. 6.5.1 <https://tools.ietf.org/html/rfc7540#section-6.5.1>`_ for details.
message SettingsParameter {
// The 16 bit parameter identifier.
google.protobuf.UInt32Value identifier = 1 [
(validate.rules).uint32 = {lte: 65536 gte: 1},
(validate.rules).message = {required: true}
];

// The 32 bit parameter value.
google.protobuf.UInt32Value value = 2 [(validate.rules).message = {required: true}];
}

// `Maximum table size <https://httpwg.org/specs/rfc7541.html#rfc.section.4.2>`_
// (in octets) that the encoder is permitted to use for the dynamic HPACK table. Valid values
// range from 0 to 4294967295 (2^32 - 1) and defaults to 4096. 0 effectively disables header
Expand Down Expand Up @@ -216,6 +229,34 @@ message Http2ProtocolOptions {
//
// See `RFC7540, sec. 8.1 <https://tools.ietf.org/html/rfc7540#section-8.1>`_ for details.
bool stream_error_on_invalid_http_messaging = 12;

// [#not-implemented-hide:]
// Specifies SETTINGS frame parameters to be sent to the peer, with two exceptions:
//
// 1. SETTINGS_ENABLE_PUSH (0x2) is not configurable as HTTP/2 server push is not supported by
// Envoy.
//
// 2. SETTINGS_ENABLE_CONNECT_PROTOCOL (0x8) is only configurable through the named field
// 'allow_connect'.
//
// Note that custom parameters specified through this field can not also be set in the
// corresponding named parameters:
//
// .. code-block:: text
//
// ID Field Name
// ----------------
// 0x1 hpack_table_size
// 0x3 max_concurrent_streams
// 0x4 initial_stream_window_size
//
// Collisions will trigger config validation failure on load/update. Likewise, inconsistencies
// between custom parameters with the same identifier will trigger a failure.
//
// See `IANA HTTP/2 Settings
// <https://www.iana.org/assignments/http2-parameters/http2-parameters.xhtml#settings>`_ for
// standardized identifiers.
repeated SettingsParameter custom_settings_parameters = 13;
}

// [#not-implemented-hide:]
Expand Down
46 changes: 45 additions & 1 deletion api/envoy/config/core/v3/protocol.proto
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,27 @@ message Http1ProtocolOptions {
bool enable_trailers = 5;
}

// [#next-free-field: 13]
// [#next-free-field: 14]
message Http2ProtocolOptions {
option (udpa.annotations.versioning).previous_message_type =
"envoy.api.v2.core.Http2ProtocolOptions";

// Defines a parameter to be sent in the SETTINGS frame.
// See `RFC7540, sec. 6.5.1 <https://tools.ietf.org/html/rfc7540#section-6.5.1>`_ for details.
message SettingsParameter {
option (udpa.annotations.versioning).previous_message_type =
"envoy.api.v2.core.Http2ProtocolOptions.SettingsParameter";

// The 16 bit parameter identifier.
google.protobuf.UInt32Value identifier = 1 [
(validate.rules).uint32 = {lte: 65536 gte: 1},
(validate.rules).message = {required: true}
];

// The 32 bit parameter value.
google.protobuf.UInt32Value value = 2 [(validate.rules).message = {required: true}];
}

// `Maximum table size <https://httpwg.org/specs/rfc7541.html#rfc.section.4.2>`_
// (in octets) that the encoder is permitted to use for the dynamic HPACK table. Valid values
// range from 0 to 4294967295 (2^32 - 1) and defaults to 4096. 0 effectively disables header
Expand Down Expand Up @@ -235,6 +251,34 @@ message Http2ProtocolOptions {
//
// See `RFC7540, sec. 8.1 <https://tools.ietf.org/html/rfc7540#section-8.1>`_ for details.
bool stream_error_on_invalid_http_messaging = 12;

// [#not-implemented-hide:]
// Specifies SETTINGS frame parameters to be sent to the peer, with two exceptions:
//
// 1. SETTINGS_ENABLE_PUSH (0x2) is not configurable as HTTP/2 server push is not supported by
// Envoy.
//
// 2. SETTINGS_ENABLE_CONNECT_PROTOCOL (0x8) is only configurable through the named field
// 'allow_connect'.
//
// Note that custom parameters specified through this field can not also be set in the
// corresponding named parameters:
//
// .. code-block:: text
//
// ID Field Name
// ----------------
// 0x1 hpack_table_size
// 0x3 max_concurrent_streams
// 0x4 initial_stream_window_size
//
// Collisions will trigger config validation failure on load/update. Likewise, inconsistencies
// between custom parameters with the same identifier will trigger a failure.
//
// See `IANA HTTP/2 Settings
// <https://www.iana.org/assignments/http2-parameters/http2-parameters.xhtml#settings>`_ for
// standardized identifiers.
repeated SettingsParameter custom_settings_parameters = 13;
}

// [#not-implemented-hide:]
Expand Down
5 changes: 5 additions & 0 deletions bazel/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,11 @@ def _com_google_absl():
actual = "@com_google_absl//absl/time:time",
)

native.bind(
name = "abseil_algorithm",
actual = "@com_google_absl//absl/algorithm:algorithm",
)

def _com_google_protobuf():
_repository_impl("rules_python")
_repository_impl(
Expand Down
43 changes: 42 additions & 1 deletion generated_api_shadow/envoy/api/v2/core/protocol.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 45 additions & 1 deletion generated_api_shadow/envoy/config/core/v3/protocol.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

72 changes: 0 additions & 72 deletions include/envoy/http/codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -326,78 +326,6 @@ struct Http1Settings {
HeaderKeyFormat header_key_format_{HeaderKeyFormat::Default};
};

/**
* HTTP/2 codec settings
*/
struct Http2Settings {
// TODO(jwfang): support other HTTP/2 settings
uint32_t hpack_table_size_{DEFAULT_HPACK_TABLE_SIZE};
uint32_t max_concurrent_streams_{DEFAULT_MAX_CONCURRENT_STREAMS};
uint32_t initial_stream_window_size_{DEFAULT_INITIAL_STREAM_WINDOW_SIZE};
uint32_t initial_connection_window_size_{DEFAULT_INITIAL_CONNECTION_WINDOW_SIZE};
bool allow_connect_{DEFAULT_ALLOW_CONNECT};
bool allow_metadata_{DEFAULT_ALLOW_METADATA};
bool stream_error_on_invalid_http_messaging_{DEFAULT_STREAM_ERROR_ON_INVALID_HTTP_MESSAGING};
uint32_t max_outbound_frames_{DEFAULT_MAX_OUTBOUND_FRAMES};
uint32_t max_outbound_control_frames_{DEFAULT_MAX_OUTBOUND_CONTROL_FRAMES};
uint32_t max_consecutive_inbound_frames_with_empty_payload_{
DEFAULT_MAX_CONSECUTIVE_INBOUND_FRAMES_WITH_EMPTY_PAYLOAD};
uint32_t max_inbound_priority_frames_per_stream_{DEFAULT_MAX_INBOUND_PRIORITY_FRAMES_PER_STREAM};
uint32_t max_inbound_window_update_frames_per_data_frame_sent_{
DEFAULT_MAX_INBOUND_WINDOW_UPDATE_FRAMES_PER_DATA_FRAME_SENT};

// disable HPACK compression
static const uint32_t MIN_HPACK_TABLE_SIZE = 0;
// initial value from HTTP/2 spec, same as NGHTTP2_DEFAULT_HEADER_TABLE_SIZE from nghttp2
static const uint32_t DEFAULT_HPACK_TABLE_SIZE = (1 << 12);
// no maximum from HTTP/2 spec, use unsigned 32-bit maximum
static const uint32_t MAX_HPACK_TABLE_SIZE = std::numeric_limits<uint32_t>::max();

// TODO(jwfang): make this 0, the HTTP/2 spec minimum
static const uint32_t MIN_MAX_CONCURRENT_STREAMS = 1;
// defaults to maximum, same as nghttp2
static const uint32_t DEFAULT_MAX_CONCURRENT_STREAMS = (1U << 31) - 1;
// no maximum from HTTP/2 spec, total streams is unsigned 32-bit maximum,
// one-side (client/server) is half that, and we need to exclude stream 0.
// same as NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS from nghttp2
static const uint32_t MAX_MAX_CONCURRENT_STREAMS = (1U << 31) - 1;

// initial value from HTTP/2 spec, same as NGHTTP2_INITIAL_WINDOW_SIZE from nghttp2
// NOTE: we only support increasing window size now, so this is also the minimum
// TODO(jwfang): make this 0 to support decrease window size
static const uint32_t MIN_INITIAL_STREAM_WINDOW_SIZE = (1 << 16) - 1;
// initial value from HTTP/2 spec is 65535, but we want more (256MiB)
static const uint32_t DEFAULT_INITIAL_STREAM_WINDOW_SIZE = 256 * 1024 * 1024;
// maximum from HTTP/2 spec, same as NGHTTP2_MAX_WINDOW_SIZE from nghttp2
static const uint32_t MAX_INITIAL_STREAM_WINDOW_SIZE = (1U << 31) - 1;

// CONNECTION_WINDOW_SIZE is similar to STREAM_WINDOW_SIZE, but for connection-level window
// TODO(jwfang): make this 0 to support decrease window size
static const uint32_t MIN_INITIAL_CONNECTION_WINDOW_SIZE = (1 << 16) - 1;
// nghttp2's default connection-level window equals to its stream-level,
// our default connection-level window also equals to our stream-level
static const uint32_t DEFAULT_INITIAL_CONNECTION_WINDOW_SIZE = 256 * 1024 * 1024;
static const uint32_t MAX_INITIAL_CONNECTION_WINDOW_SIZE = (1U << 31) - 1;
// By default both nghttp2 and Envoy do not allow CONNECT over H2.
static const bool DEFAULT_ALLOW_CONNECT = false;
// By default Envoy does not allow METADATA support.
static const bool DEFAULT_ALLOW_METADATA = false;
// By default Envoy does not allow invalid headers.
static const bool DEFAULT_STREAM_ERROR_ON_INVALID_HTTP_MESSAGING = false;

// Default limit on the number of outbound frames of all types.
static const uint32_t DEFAULT_MAX_OUTBOUND_FRAMES = 10000;
// Default limit on the number of outbound frames of types PING, SETTINGS and RST_STREAM.
static const uint32_t DEFAULT_MAX_OUTBOUND_CONTROL_FRAMES = 1000;
// Default limit on the number of consecutive inbound frames with an empty payload
// and no end stream flag.
static const uint32_t DEFAULT_MAX_CONSECUTIVE_INBOUND_FRAMES_WITH_EMPTY_PAYLOAD = 1;
// Default limit on the number of inbound frames of type PRIORITY (per stream).
static const uint32_t DEFAULT_MAX_INBOUND_PRIORITY_FRAMES_PER_STREAM = 100;
// Default limit on the number of inbound frames of type WINDOW_UPDATE (per DATA frame sent).
static const uint32_t DEFAULT_MAX_INBOUND_WINDOW_UPDATE_FRAMES_PER_DATA_FRAME_SENT = 10;
};

/**
* A connection (client or server) that owns multiple streams.
*/
Expand Down
7 changes: 4 additions & 3 deletions include/envoy/upstream/upstream.h
Original file line number Diff line number Diff line change
Expand Up @@ -720,10 +720,11 @@ class ClusterInfo {
virtual const Http::Http1Settings& http1Settings() const PURE;

/**
* @return const Http::Http2Settings& for HTTP/2 connections created on behalf of this cluster.
* @see Http::Http2Settings.
* @return const envoy::config::core::v3::Http2ProtocolOptions& for HTTP/2 connections
* created on behalf of this cluster.
* @see envoy::config::core::v3::Http2ProtocolOptions.
*/
virtual const Http::Http2Settings& http2Settings() const PURE;
virtual const envoy::config::core::v3::Http2ProtocolOptions& http2Options() const PURE;

/**
* @param name std::string containing the well-known name of the extension for which protocol
Expand Down
1 change: 1 addition & 0 deletions source/common/http/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ envoy_cc_library(
external_deps = [
"abseil_optional",
"http_parser",
"nghttp2",
],
deps = [
":exception_lib",
Expand Down
2 changes: 1 addition & 1 deletion source/common/http/codec_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ CodecClientProd::CodecClientProd(Type type, Network::ClientConnectionPtr&& conne
}
case Type::HTTP2: {
codec_ = std::make_unique<Http2::ClientConnectionImpl>(
*connection_, *this, host->cluster().statsScope(), host->cluster().http2Settings(),
*connection_, *this, host->cluster().statsScope(), host->cluster().http2Options(),
Http::DEFAULT_MAX_REQUEST_HEADERS_KB, host->cluster().maxResponseHeadersCount());
break;
}
Expand Down
6 changes: 3 additions & 3 deletions source/common/http/conn_manager_utility.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ std::string ConnectionManagerUtility::determineNextProtocol(Network::Connection&
ServerConnectionPtr ConnectionManagerUtility::autoCreateCodec(
Network::Connection& connection, const Buffer::Instance& data,
ServerConnectionCallbacks& callbacks, Stats::Scope& scope, const Http1Settings& http1_settings,
const Http2Settings& http2_settings, uint32_t max_request_headers_kb,
uint32_t max_request_headers_count) {
const envoy::config::core::v3::Http2ProtocolOptions& http2_options,
uint32_t max_request_headers_kb, uint32_t max_request_headers_count) {
if (determineNextProtocol(connection, data) == Http2::ALPN_STRING) {
return std::make_unique<Http2::ServerConnectionImpl>(connection, callbacks, scope,
http2_settings, max_request_headers_kb,
http2_options, max_request_headers_kb,
max_request_headers_count);
} else {
return std::make_unique<Http1::ServerConnectionImpl>(connection, scope, callbacks,
Expand Down
3 changes: 2 additions & 1 deletion source/common/http/conn_manager_utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ class ConnectionManagerUtility {
static ServerConnectionPtr
autoCreateCodec(Network::Connection& connection, const Buffer::Instance& data,
ServerConnectionCallbacks& callbacks, Stats::Scope& scope,
const Http1Settings& http1_settings, const Http2Settings& http2_settings,
const Http1Settings& http1_settings,
const envoy::config::core::v3::Http2ProtocolOptions& http2_options,
uint32_t max_request_headers_kb, uint32_t max_request_headers_count);

/**
Expand Down
Loading

0 comments on commit 56e5b84

Please sign in to comment.