diff --git a/docs/root/intro/version_history.rst b/docs/root/intro/version_history.rst index e6f55e59f3c5f..eb2bfe7f6752c 100644 --- a/docs/root/intro/version_history.rst +++ b/docs/root/intro/version_history.rst @@ -18,16 +18,18 @@ Version history `. This defaults to 5 minutes; if you have other timeouts (e.g. connection idle timeout, upstream response per-retry) that are longer than this in duration, you may want to consider setting a non-default per-stream idle timeout. +* http: added generic :ref:`Upgrade support + `. * http: better handling of HEAD requests. Now sending transfer-encoding: chunked rather than content-length: 0. * http: response filters not applied to early error paths such as http_parser generated 400s. -* proxy_protocol: added support for HAProxy Proxy Protocol v2 (AF_INET/AF_INET6 only). -* http: added generic +:ref:`Upgrade support - ` +* http: :ref:`hpack_table_size ` now controls + dynamic table size of both: encoder and decoder. * listeners: added the ability to match :ref:`FilterChain ` using :ref:`destination_port ` and :ref:`prefix_ranges `. * lua: added :ref:`connection() ` wrapper and *ssl()* API. * lua: added :ref:`requestInfo() ` wrapper and *protocol()* API. +* proxy_protocol: added support for HAProxy Proxy Protocol v2 (AF_INET/AF_INET6 only). * ratelimit: added support for :repo:`api/envoy/service/ratelimit/v2/rls.proto`. Lyft's reference implementation of the `ratelimit `_ service also supports the data-plane-api proto as of v1.1.0. Envoy can use either proto to send client requests to a ratelimit server with the use of the diff --git a/source/common/http/http2/codec_impl.cc b/source/common/http/http2/codec_impl.cc index dfecb1298648a..11dc48e2da8b4 100644 --- a/source/common/http/http2/codec_impl.cc +++ b/source/common/http/http2/codec_impl.cc @@ -37,8 +37,6 @@ bool Utility::reconstituteCrumbledCookies(const HeaderString& key, const HeaderS } ConnectionImpl::Http2Callbacks ConnectionImpl::http2_callbacks_; -ConnectionImpl::Http2Options ConnectionImpl::http2_options_; -ConnectionImpl::ClientHttp2Options ConnectionImpl::client_http2_options_; /** * Helper to remove const during a cast. nghttp2 takes non-const pointers for headers even though @@ -724,7 +722,7 @@ ConnectionImpl::Http2Callbacks::Http2Callbacks() { ConnectionImpl::Http2Callbacks::~Http2Callbacks() { nghttp2_session_callbacks_del(callbacks_); } -ConnectionImpl::Http2Options::Http2Options() { +ConnectionImpl::Http2Options::Http2Options(const Http2Settings& http2_settings) { nghttp2_option_new(&options_); // Currently we do not do anything with stream priority. Setting the following option prevents // nghttp2 from keeping around closed streams for use during stream priority dependency graph @@ -732,11 +730,16 @@ ConnectionImpl::Http2Options::Http2Options() { // of kept alive HTTP/2 connections. nghttp2_option_set_no_closed_streams(options_, 1); nghttp2_option_set_no_auto_window_update(options_, 1); + + if (http2_settings.hpack_table_size_ != NGHTTP2_DEFAULT_HEADER_TABLE_SIZE) { + nghttp2_option_set_max_deflate_dynamic_table_size(options_, http2_settings.hpack_table_size_); + } } ConnectionImpl::Http2Options::~Http2Options() { nghttp2_option_del(options_); } -ConnectionImpl::ClientHttp2Options::ClientHttp2Options() : Http2Options() { +ConnectionImpl::ClientHttp2Options::ClientHttp2Options(const Http2Settings& http2_settings) + : Http2Options(http2_settings) { // Temporarily disable initial max streams limit/protection, since we might want to create // more than 100 streams before receiving the HTTP/2 SETTINGS frame from the server. // @@ -749,8 +752,9 @@ ClientConnectionImpl::ClientConnectionImpl(Network::Connection& connection, Http::ConnectionCallbacks& callbacks, Stats::Scope& stats, const Http2Settings& http2_settings) : ConnectionImpl(connection, stats, http2_settings), callbacks_(callbacks) { + ClientHttp2Options client_http2_options(http2_settings); nghttp2_session_client_new2(&session_, http2_callbacks_.callbacks(), base(), - client_http2_options_.options()); + client_http2_options.options()); sendSettings(http2_settings, true); } @@ -794,8 +798,9 @@ ServerConnectionImpl::ServerConnectionImpl(Network::Connection& connection, Http::ServerConnectionCallbacks& callbacks, Stats::Scope& scope, const Http2Settings& http2_settings) : ConnectionImpl(connection, scope, http2_settings), callbacks_(callbacks) { + Http2Options http2_options(http2_settings); nghttp2_session_server_new2(&session_, http2_callbacks_.callbacks(), base(), - http2_options_.options()); + http2_options.options()); sendSettings(http2_settings, false); } diff --git a/source/common/http/http2/codec_impl.h b/source/common/http/http2/codec_impl.h index b835a5b864a5d..6b4e0016a72c0 100644 --- a/source/common/http/http2/codec_impl.h +++ b/source/common/http/http2/codec_impl.h @@ -118,7 +118,7 @@ class ConnectionImpl : public virtual Connection, protected Logger::Loggable active_streams_; nghttp2_session* session_{}; diff --git a/test/common/http/http2/codec_impl_test.cc b/test/common/http/http2/codec_impl_test.cc index 7e679543ca369..2894363830efb 100644 --- a/test/common/http/http2/codec_impl_test.cc +++ b/test/common/http/http2/codec_impl_test.cc @@ -783,6 +783,34 @@ TEST_P(Http2CodecImplTest, TestCodecHeaderLimits) { request_encoder_->encodeHeaders(request_headers, false); } +TEST_P(Http2CodecImplTest, TestCodecHeaderCompression) { + initialize(); + + TestHeaderMapImpl request_headers; + HttpTestUtility::addDefaultHeaders(request_headers); + EXPECT_CALL(request_decoder_, decodeHeaders_(_, true)); + request_encoder_->encodeHeaders(request_headers, true); + + TestHeaderMapImpl response_headers{{":status", "200"}, {"compression", "test"}}; + EXPECT_CALL(response_decoder_, decodeHeaders_(_, true)); + response_encoder_->encodeHeaders(response_headers, true); + + // Sanity check to verify that state of encoders and decoders matches. + EXPECT_EQ(nghttp2_session_get_hd_deflate_dynamic_table_size(server_.session()), + nghttp2_session_get_hd_inflate_dynamic_table_size(client_.session())); + EXPECT_EQ(nghttp2_session_get_hd_deflate_dynamic_table_size(client_.session()), + nghttp2_session_get_hd_inflate_dynamic_table_size(server_.session())); + + // Verify that headers are compressed only when both client and server advertise table size > 0: + if (client_http2settings_.hpack_table_size_ && server_http2settings_.hpack_table_size_) { + EXPECT_NE(0, nghttp2_session_get_hd_deflate_dynamic_table_size(client_.session())); + EXPECT_NE(0, nghttp2_session_get_hd_deflate_dynamic_table_size(server_.session())); + } else { + EXPECT_EQ(0, nghttp2_session_get_hd_deflate_dynamic_table_size(client_.session())); + EXPECT_EQ(0, nghttp2_session_get_hd_deflate_dynamic_table_size(server_.session())); + } +} + } // namespace Http2 } // namespace Http } // namespace Envoy