From b4d5b67f39835fbff3c730214c84ac76e952e2bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jul 2024 10:57:18 +0300 Subject: [PATCH 01/30] build(deps): bump docker/setup-buildx-action from 3.3.0 to 3.4.0 (#6543) Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3.3.0 to 3.4.0. - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](https://github.com/docker/setup-buildx-action/compare/d70bba72b1f3fd22344832f00baa16ece964efeb...4fd812986e6c8c2a69e18311145f9371337f27d4) --- updated-dependencies: - dependency-name: docker/setup-buildx-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: chaosbox --- .github/workflows/build_main.yaml | 2 +- .github/workflows/build_tag.yaml | 2 +- .github/workflows/prbuild.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build_main.yaml b/.github/workflows/build_main.yaml index 8a5f1fc9186..029d788b887 100644 --- a/.github/workflows/build_main.yaml +++ b/.github/workflows/build_main.yaml @@ -21,7 +21,7 @@ jobs: with: persist-credentials: false - name: Set up Docker Buildx - uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0 + uses: docker/setup-buildx-action@4fd812986e6c8c2a69e18311145f9371337f27d4 # v3.4.0 with: version: latest - name: Log in to GHCR diff --git a/.github/workflows/build_tag.yaml b/.github/workflows/build_tag.yaml index b7e7a4990d9..69c2e1e5475 100644 --- a/.github/workflows/build_tag.yaml +++ b/.github/workflows/build_tag.yaml @@ -31,7 +31,7 @@ jobs: with: persist-credentials: false - name: Set up Docker Buildx - uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0 + uses: docker/setup-buildx-action@4fd812986e6c8c2a69e18311145f9371337f27d4 # v3.4.0 with: version: latest - name: Log in to GHCR diff --git a/.github/workflows/prbuild.yaml b/.github/workflows/prbuild.yaml index 13dab29ca94..0feae896984 100644 --- a/.github/workflows/prbuild.yaml +++ b/.github/workflows/prbuild.yaml @@ -103,7 +103,7 @@ jobs: with: persist-credentials: false - name: Set up Docker Buildx - uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0 + uses: docker/setup-buildx-action@4fd812986e6c8c2a69e18311145f9371337f27d4 # v3.4.0 with: version: latest - name: Build image From 081a47c42df23ca45db9aeea7cfd101eee16dd36 Mon Sep 17 00:00:00 2001 From: chaosbox Date: Tue, 9 Jul 2024 09:37:07 +0100 Subject: [PATCH 02/30] Adds "disableCompression" as a feature to turnon/off Envoy's GZIP response compression Signed-off-by: chaosbox --- apis/projectcontour/v1alpha1/contourconfig.go | 6 + cmd/contour/serve.go | 1 + cmd/contour/servecontext.go | 1 + cmd/contour/servecontext_test.go | 2 + examples/contour/01-crds.yaml | 12 ++ examples/render/contour-deployment.yaml | 12 ++ .../render/contour-gateway-provisioner.yaml | 12 ++ examples/render/contour-gateway.yaml | 12 ++ examples/render/contour.yaml | 12 ++ internal/envoy/v3/listener.go | 62 +++++---- internal/featuretests/v3/compression_test.go | 121 ++++++++++++++++++ internal/xdscache/v3/listener.go | 8 ++ internal/xdscache/v3/listener_test.go | 42 ++++++ pkg/config/parameters.go | 5 + .../docs/main/config/api-reference.html | 15 +++ test/e2e/httpproxy/envoy_compression_test.go | 79 ++++++++++++ test/e2e/httpproxy/httpproxy_test.go | 13 ++ 17 files changed, 389 insertions(+), 26 deletions(-) create mode 100644 internal/featuretests/v3/compression_test.go create mode 100644 test/e2e/httpproxy/envoy_compression_test.go diff --git a/apis/projectcontour/v1alpha1/contourconfig.go b/apis/projectcontour/v1alpha1/contourconfig.go index 08fd76a23fc..db8fe9cdf4d 100644 --- a/apis/projectcontour/v1alpha1/contourconfig.go +++ b/apis/projectcontour/v1alpha1/contourconfig.go @@ -341,6 +341,12 @@ type EnvoyListenerConfig struct { // +optional UseProxyProto *bool `json:"useProxyProtocol,omitempty"` + // DisableCompression disables GZIP compression HTTP filter from the default Listener filters + // Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + // Contour's default is false. + // +optional + DisableCompression bool `json:"disableCompression,omitempty"` + // DisableAllowChunkedLength disables the RFC-compliant Envoy behavior to // strip the "Content-Length" header if "Transfer-Encoding: chunked" is // also set. This is an emergency off-switch to revert back to Envoy's diff --git a/cmd/contour/serve.go b/cmd/contour/serve.go index e3cdd0adeeb..0af00921b58 100644 --- a/cmd/contour/serve.go +++ b/cmd/contour/serve.go @@ -447,6 +447,7 @@ func (s *Server) doServe() error { } listenerConfig := xdscache_v3.ListenerConfig{ + DisableCompression: contourConfiguration.Envoy.Listener.DisableCompression, UseProxyProto: *contourConfiguration.Envoy.Listener.UseProxyProto, HTTPAccessLog: contourConfiguration.Envoy.HTTPListener.AccessLog, HTTPSAccessLog: contourConfiguration.Envoy.HTTPSListener.AccessLog, diff --git a/cmd/contour/servecontext.go b/cmd/contour/servecontext.go index 3a1057b6479..67451bc0ad7 100644 --- a/cmd/contour/servecontext.go +++ b/cmd/contour/servecontext.go @@ -519,6 +519,7 @@ func (ctx *serveContext) convertToContourConfigurationSpec() contour_v1alpha1.Co Envoy: &contour_v1alpha1.EnvoyConfig{ Listener: &contour_v1alpha1.EnvoyListenerConfig{ UseProxyProto: &ctx.useProxyProto, + DisableCompression: ctx.Config.DisableCompression, DisableAllowChunkedLength: &ctx.Config.DisableAllowChunkedLength, DisableMergeSlashes: &ctx.Config.DisableMergeSlashes, ServerHeaderTransformation: serverHeaderTransformation, diff --git a/cmd/contour/servecontext_test.go b/cmd/contour/servecontext_test.go index 766a2f0af83..27335f40913 100644 --- a/cmd/contour/servecontext_test.go +++ b/cmd/contour/servecontext_test.go @@ -892,12 +892,14 @@ func TestConvertServeContext(t *testing.T) { ctx.Config.Listener.MaxRequestsPerIOCycle = ptr.To(uint32(10)) ctx.Config.Listener.HTTP2MaxConcurrentStreams = ptr.To(uint32(30)) ctx.Config.Listener.MaxConnectionsPerListener = ptr.To(uint32(50)) + ctx.Config.DisableCompression = true return ctx }, getContourConfiguration: func(cfg contour_v1alpha1.ContourConfigurationSpec) contour_v1alpha1.ContourConfigurationSpec { cfg.Envoy.Listener.MaxRequestsPerIOCycle = ptr.To(uint32(10)) cfg.Envoy.Listener.HTTP2MaxConcurrentStreams = ptr.To(uint32(30)) cfg.Envoy.Listener.MaxConnectionsPerListener = ptr.To(uint32(50)) + cfg.Envoy.Listener.DisableCompression = true return cfg }, }, diff --git a/examples/contour/01-crds.yaml b/examples/contour/01-crds.yaml index 00aebca5e95..83ff28dbfeb 100644 --- a/examples/contour/01-crds.yaml +++ b/examples/contour/01-crds.yaml @@ -293,6 +293,12 @@ spec: See: https://github.com/projectcontour/contour/issues/3221 Contour's default is false. type: boolean + disableCompression: + description: |- + DisableCompression disables GZIP compression HTTP filter from the default Listener filters + Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + Contour's default is false. + type: boolean disableMergeSlashes: description: |- DisableMergeSlashes disables Envoy's non-standard merge_slashes path transformation option @@ -4067,6 +4073,12 @@ spec: See: https://github.com/projectcontour/contour/issues/3221 Contour's default is false. type: boolean + disableCompression: + description: |- + DisableCompression disables GZIP compression HTTP filter from the default Listener filters + Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + Contour's default is false. + type: boolean disableMergeSlashes: description: |- DisableMergeSlashes disables Envoy's non-standard merge_slashes path transformation option diff --git a/examples/render/contour-deployment.yaml b/examples/render/contour-deployment.yaml index b7663b38be1..6ebab58bdc5 100644 --- a/examples/render/contour-deployment.yaml +++ b/examples/render/contour-deployment.yaml @@ -513,6 +513,12 @@ spec: See: https://github.com/projectcontour/contour/issues/3221 Contour's default is false. type: boolean + disableCompression: + description: |- + DisableCompression disables GZIP compression HTTP filter from the default Listener filters + Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + Contour's default is false. + type: boolean disableMergeSlashes: description: |- DisableMergeSlashes disables Envoy's non-standard merge_slashes path transformation option @@ -4287,6 +4293,12 @@ spec: See: https://github.com/projectcontour/contour/issues/3221 Contour's default is false. type: boolean + disableCompression: + description: |- + DisableCompression disables GZIP compression HTTP filter from the default Listener filters + Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + Contour's default is false. + type: boolean disableMergeSlashes: description: |- DisableMergeSlashes disables Envoy's non-standard merge_slashes path transformation option diff --git a/examples/render/contour-gateway-provisioner.yaml b/examples/render/contour-gateway-provisioner.yaml index 91a8ac8a800..8d623f73656 100644 --- a/examples/render/contour-gateway-provisioner.yaml +++ b/examples/render/contour-gateway-provisioner.yaml @@ -304,6 +304,12 @@ spec: See: https://github.com/projectcontour/contour/issues/3221 Contour's default is false. type: boolean + disableCompression: + description: |- + DisableCompression disables GZIP compression HTTP filter from the default Listener filters + Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + Contour's default is false. + type: boolean disableMergeSlashes: description: |- DisableMergeSlashes disables Envoy's non-standard merge_slashes path transformation option @@ -4078,6 +4084,12 @@ spec: See: https://github.com/projectcontour/contour/issues/3221 Contour's default is false. type: boolean + disableCompression: + description: |- + DisableCompression disables GZIP compression HTTP filter from the default Listener filters + Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + Contour's default is false. + type: boolean disableMergeSlashes: description: |- DisableMergeSlashes disables Envoy's non-standard merge_slashes path transformation option diff --git a/examples/render/contour-gateway.yaml b/examples/render/contour-gateway.yaml index 0d70b6c4c4f..c9df01c0e82 100644 --- a/examples/render/contour-gateway.yaml +++ b/examples/render/contour-gateway.yaml @@ -329,6 +329,12 @@ spec: See: https://github.com/projectcontour/contour/issues/3221 Contour's default is false. type: boolean + disableCompression: + description: |- + DisableCompression disables GZIP compression HTTP filter from the default Listener filters + Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + Contour's default is false. + type: boolean disableMergeSlashes: description: |- DisableMergeSlashes disables Envoy's non-standard merge_slashes path transformation option @@ -4103,6 +4109,12 @@ spec: See: https://github.com/projectcontour/contour/issues/3221 Contour's default is false. type: boolean + disableCompression: + description: |- + DisableCompression disables GZIP compression HTTP filter from the default Listener filters + Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + Contour's default is false. + type: boolean disableMergeSlashes: description: |- DisableMergeSlashes disables Envoy's non-standard merge_slashes path transformation option diff --git a/examples/render/contour.yaml b/examples/render/contour.yaml index b44c26538bc..3f80b104e89 100644 --- a/examples/render/contour.yaml +++ b/examples/render/contour.yaml @@ -513,6 +513,12 @@ spec: See: https://github.com/projectcontour/contour/issues/3221 Contour's default is false. type: boolean + disableCompression: + description: |- + DisableCompression disables GZIP compression HTTP filter from the default Listener filters + Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + Contour's default is false. + type: boolean disableMergeSlashes: description: |- DisableMergeSlashes disables Envoy's non-standard merge_slashes path transformation option @@ -4287,6 +4293,12 @@ spec: See: https://github.com/projectcontour/contour/issues/3221 Contour's default is false. type: boolean + disableCompression: + description: |- + DisableCompression disables GZIP compression HTTP filter from the default Listener filters + Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + Contour's default is false. + type: boolean disableMergeSlashes: description: |- DisableMergeSlashes disables Envoy's non-standard merge_slashes path transformation option diff --git a/internal/envoy/v3/listener.go b/internal/envoy/v3/listener.go index 5d1f2c233ce..fc57b436645 100644 --- a/internal/envoy/v3/listener.go +++ b/internal/envoy/v3/listener.go @@ -188,6 +188,7 @@ type httpConnectionManagerBuilder struct { maxRequestsPerConnection *uint32 http2MaxConcurrentStreams *uint32 enableWebsockets bool + disableCompression bool } func (b *httpConnectionManagerBuilder) EnableWebsockets(enable bool) *httpConnectionManagerBuilder { @@ -271,6 +272,11 @@ func (b *httpConnectionManagerBuilder) MergeSlashes(enabled bool) *httpConnectio return b } +func (b *httpConnectionManagerBuilder) DisableCompression(disabled bool) *httpConnectionManagerBuilder { + b.disableCompression = disabled + return b +} + func (b *httpConnectionManagerBuilder) ServerHeaderTransformation(value contour_v1alpha1.ServerHeaderTransformationType) *httpConnectionManagerBuilder { switch value { case contour_v1alpha1.OverwriteServerHeader: @@ -308,34 +314,38 @@ func (b *httpConnectionManagerBuilder) DefaultFilters() *httpConnectionManagerBu // Add a default set of ordered http filters. // The names are not required to match anything and are // identified by the TypeURL of each filter. - b.filters = append(b.filters, - &envoy_filter_network_http_connection_manager_v3.HttpFilter{ - Name: CompressorFilterName, - ConfigType: &envoy_filter_network_http_connection_manager_v3.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_filter_http_compressor_v3.Compressor{ - CompressorLibrary: &envoy_config_core_v3.TypedExtensionConfig{ - Name: "gzip", - TypedConfig: protobuf.MustMarshalAny( - &envoy_compression_gzip_compressor_v3.Gzip{}, - ), - }, - ResponseDirectionConfig: &envoy_filter_http_compressor_v3.Compressor_ResponseDirectionConfig{ - CommonConfig: &envoy_filter_http_compressor_v3.Compressor_CommonDirectionConfig{ - ContentType: []string{ - // Default content-types https://github.com/envoyproxy/envoy/blob/e74999dbdb12aa4d6b7a5d62d51731ea86bf72be/source/extensions/filters/http/compressor/compressor_filter.cc#L35-L38 - "text/html", "text/plain", "text/css", "application/javascript", "application/x-javascript", - "text/javascript", "text/x-javascript", "text/ecmascript", "text/js", "text/jscript", - "text/x-js", "application/ecmascript", "application/x-json", "application/xml", - "application/json", "image/svg+xml", "text/xml", "application/xhtml+xml", - // Additional content-types for grpc-web https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md#protocol-differences-vs-grpc-over-http2 - "application/grpc-web", "application/grpc-web+proto", "application/grpc-web+json", "application/grpc-web+thrift", - "application/grpc-web-text", "application/grpc-web-text+proto", "application/grpc-web-text+thrift", + if !b.disableCompression { + // If compression is enabled add compressor filter + b.filters = append(b.filters, + &envoy_filter_network_http_connection_manager_v3.HttpFilter{ + Name: CompressorFilterName, + ConfigType: &envoy_filter_network_http_connection_manager_v3.HttpFilter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&envoy_filter_http_compressor_v3.Compressor{ + CompressorLibrary: &envoy_config_core_v3.TypedExtensionConfig{ + Name: "gzip", + TypedConfig: protobuf.MustMarshalAny( + &envoy_compression_gzip_compressor_v3.Gzip{}, + ), + }, + ResponseDirectionConfig: &envoy_filter_http_compressor_v3.Compressor_ResponseDirectionConfig{ + CommonConfig: &envoy_filter_http_compressor_v3.Compressor_CommonDirectionConfig{ + ContentType: []string{ + // Default content-types https://github.com/envoyproxy/envoy/blob/e74999dbdb12aa4d6b7a5d62d51731ea86bf72be/source/extensions/filters/http/compressor/compressor_filter.cc#L35-L38 + "text/html", "text/plain", "text/css", "application/javascript", "application/x-javascript", + "text/javascript", "text/x-javascript", "text/ecmascript", "text/js", "text/jscript", + "text/x-js", "application/ecmascript", "application/x-json", "application/xml", + "application/json", "image/svg+xml", "text/xml", "application/xhtml+xml", + // Additional content-types for grpc-web https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md#protocol-differences-vs-grpc-over-http2 + "application/grpc-web", "application/grpc-web+proto", "application/grpc-web+json", "application/grpc-web+thrift", + "application/grpc-web-text", "application/grpc-web-text+proto", "application/grpc-web-text+thrift", + }, }, }, - }, - }), - }, - }, + }), + }, + }) + } + b.filters = append(b.filters, &envoy_filter_network_http_connection_manager_v3.HttpFilter{ Name: GRPCWebFilterName, ConfigType: &envoy_filter_network_http_connection_manager_v3.HttpFilter_TypedConfig{ diff --git a/internal/featuretests/v3/compression_test.go b/internal/featuretests/v3/compression_test.go new file mode 100644 index 00000000000..af5e71f6f6a --- /dev/null +++ b/internal/featuretests/v3/compression_test.go @@ -0,0 +1,121 @@ +// Copyright Project Contour Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v3 + +import ( + envoy_service_discovery_v3 "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" + core_v1 "k8s.io/api/core/v1" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "testing" + + contour_v1 "github.com/projectcontour/contour/apis/projectcontour/v1" + contour_v1alpha1 "github.com/projectcontour/contour/apis/projectcontour/v1alpha1" + envoy_v3 "github.com/projectcontour/contour/internal/envoy/v3" + "github.com/projectcontour/contour/internal/fixture" + xdscache_v3 "github.com/projectcontour/contour/internal/xdscache/v3" +) + +func TestDefaultCompression(t *testing.T) { + withDefaultListenerConfig := func(conf *xdscache_v3.ListenerConfig) { + } + + rh, c, done := setup(t, withDefaultListenerConfig) + defer done() + + s1 := fixture.NewService("backend"). + WithPorts(core_v1.ServicePort{Name: "http", Port: 80}) + rh.OnAdd(s1) + + hp1 := &contour_v1.HTTPProxy{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: "simple", + Namespace: s1.Namespace, + }, + Spec: contour_v1.HTTPProxySpec{ + VirtualHost: &contour_v1.VirtualHost{ + Fqdn: "example.com", + }, + Routes: []contour_v1.Route{{ + Conditions: matchconditions(prefixMatchCondition("/")), + Services: []contour_v1.Service{{ + Name: s1.Name, + Port: 80, + }}, + }}, + }, + } + rh.OnAdd(hp1) + + httpListener := defaultHTTPListener() + httpListener.FilterChains = envoy_v3.FilterChains(envoy_v3.HTTPConnectionManagerBuilder(). + RouteConfigName(xdscache_v3.ENVOY_HTTP_LISTENER). + MetricsPrefix(xdscache_v3.ENVOY_HTTP_LISTENER). + AccessLoggers(envoy_v3.FileAccessLogEnvoy(xdscache_v3.DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). + DefaultFilters(). + Get(), + ) + + c.Request(listenerType, xdscache_v3.ENVOY_HTTP_LISTENER).Equals(&envoy_service_discovery_v3.DiscoveryResponse{ + TypeUrl: listenerType, + Resources: resources(t, httpListener), + }) +} + +func TestDisableCompression(t *testing.T) { + withDisableCompression := func(conf *xdscache_v3.ListenerConfig) { + conf.DisableCompression = true + } + + rh, c, done := setup(t, withDisableCompression) + defer done() + + s1 := fixture.NewService("backend"). + WithPorts(core_v1.ServicePort{Name: "http", Port: 80}) + rh.OnAdd(s1) + + hp1 := &contour_v1.HTTPProxy{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: "simple", + Namespace: s1.Namespace, + }, + Spec: contour_v1.HTTPProxySpec{ + VirtualHost: &contour_v1.VirtualHost{ + Fqdn: "example.com", + }, + Routes: []contour_v1.Route{{ + Conditions: matchconditions(prefixMatchCondition("/")), + Services: []contour_v1.Service{{ + Name: s1.Name, + Port: 80, + }}, + }}, + }, + } + rh.OnAdd(hp1) + + httpListener := defaultHTTPListener() + httpListener.FilterChains = envoy_v3.FilterChains(envoy_v3.HTTPConnectionManagerBuilder(). + DisableCompression(true). + RouteConfigName(xdscache_v3.ENVOY_HTTP_LISTENER). + MetricsPrefix(xdscache_v3.ENVOY_HTTP_LISTENER). + AccessLoggers(envoy_v3.FileAccessLogEnvoy(xdscache_v3.DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). + DefaultFilters(). + Get(), + ) + + c.Request(listenerType, xdscache_v3.ENVOY_HTTP_LISTENER).Equals(&envoy_service_discovery_v3.DiscoveryResponse{ + TypeUrl: listenerType, + Resources: resources(t, httpListener), + }) +} diff --git a/internal/xdscache/v3/listener.go b/internal/xdscache/v3/listener.go index 975c0654743..23869ea2e81 100644 --- a/internal/xdscache/v3/listener.go +++ b/internal/xdscache/v3/listener.go @@ -66,6 +66,11 @@ type ListenerConfig struct { // If not set, defaults to false. UseProxyProto bool + // DisableCompression configures listener to ignore adding compression filter as part of the defaultFilters + // Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + // If not set, defaults to false. + DisableCompression bool + // MinimumTLSVersion defines the minimum TLS protocol version the proxy should accept. MinimumTLSVersion string @@ -393,6 +398,7 @@ func (c *ListenerCache) OnChange(root *dag.DAG) { // order for the HTTPS virtualhosts. if len(listener.VirtualHosts) > 0 { cm := envoy_v3.HTTPConnectionManagerBuilder(). + DisableCompression(cfg.DisableCompression). Codec(envoy_v3.CodecForVersions(cfg.DefaultHTTPVersions...)). DefaultFilters(). RouteConfigName(httpRouteConfigName(listener)). @@ -465,6 +471,7 @@ func (c *ListenerCache) OnChange(root *dag.DAG) { // Contour versions since the metrics prefix will be // coded into monitoring dashboards. cm := envoy_v3.HTTPConnectionManagerBuilder(). + DisableCompression(cfg.DisableCompression). Codec(envoy_v3.CodecForVersions(cfg.DefaultHTTPVersions...)). AddFilter(envoy_v3.FilterMisdirectedRequests(vh.VirtualHost.Name)). DefaultFilters(). @@ -544,6 +551,7 @@ func (c *ListenerCache) OnChange(root *dag.DAG) { ) cm := envoy_v3.HTTPConnectionManagerBuilder(). + DisableCompression(cfg.DisableCompression). DefaultFilters(). RouteConfigName(fallbackCertRouteConfigName(listener)). MetricsPrefix(listener.Name). diff --git a/internal/xdscache/v3/listener_test.go b/internal/xdscache/v3/listener_test.go index 095f248210a..1b85ab968b0 100644 --- a/internal/xdscache/v3/listener_test.go +++ b/internal/xdscache/v3/listener_test.go @@ -3074,6 +3074,48 @@ func TestListenerVisit(t *testing.T) { SocketOptions: envoy_v3.NewSocketOptions().TCPKeepalive().Build(), }), }, + "httpproxy with DisableCompression set in listener config": { + ListenerConfig: ListenerConfig{ + DisableCompression: true, + }, + objs: []any{ + &contour_v1.HTTPProxy{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: "simple", + Namespace: "default", + }, + Spec: contour_v1.HTTPProxySpec{ + VirtualHost: &contour_v1.VirtualHost{ + Fqdn: "www.example.com", + }, + Routes: []contour_v1.Route{{ + Conditions: []contour_v1.MatchCondition{{ + Prefix: "/", + }}, + Services: []contour_v1.Service{{ + Name: "backend", + Port: 80, + }}, + }}, + }, + }, + service, + }, + want: listenermap(&envoy_config_listener_v3.Listener{ + Name: ENVOY_HTTP_LISTENER, + Address: envoy_v3.SocketAddress("0.0.0.0", 8080), + FilterChains: envoy_v3.FilterChains( + envoy_v3.HTTPConnectionManagerBuilder(). + DisableCompression(true). + RouteConfigName(ENVOY_HTTP_LISTENER). + MetricsPrefix(ENVOY_HTTP_LISTENER). + AccessLoggers(envoy_v3.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). + DefaultFilters(). + Get(), + ), + SocketOptions: envoy_v3.NewSocketOptions().TCPKeepalive().Build(), + }), + }, "httpsproxy with PerConnectionBufferLimitBytes set in listener config": { ListenerConfig: ListenerConfig{ PerConnectionBufferLimitBytes: ptr.To(uint32(32768)), diff --git a/pkg/config/parameters.go b/pkg/config/parameters.go index b4c7aaa3869..21bfb0bf794 100644 --- a/pkg/config/parameters.go +++ b/pkg/config/parameters.go @@ -649,6 +649,11 @@ type Parameters struct { // which strips duplicate slashes from request URL paths. DisableMergeSlashes bool `yaml:"disableMergeSlashes,omitempty"` + // DisableCompression disables GZIP compression HTTP filter + // Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + // If not set, defaults to false. + DisableCompression bool `yaml:"disableCompression,omitempty"` + // Defines the action to be applied to the Server header on the response path. // When configured as overwrite, overwrites any Server header with "envoy". // When configured as append_if_absent, if a Server header is present, pass it through, otherwise set it to "envoy". diff --git a/site/content/docs/main/config/api-reference.html b/site/content/docs/main/config/api-reference.html index b9ba8f7400d..6c7c52e6cf5 100644 --- a/site/content/docs/main/config/api-reference.html +++ b/site/content/docs/main/config/api-reference.html @@ -6800,6 +6800,21 @@

EnvoyListenerConfig +disableCompression +
+ +bool + + + +(Optional) +

DisableCompression disables GZIP compression HTTP filter from the default Listener filters +Setting this true will enable Envoy skip “Accept-Encoding: gzip,deflate” request header and always return uncompressed response +Contour’s default is false.

+ + + + disableAllowChunkedLength
diff --git a/test/e2e/httpproxy/envoy_compression_test.go b/test/e2e/httpproxy/envoy_compression_test.go new file mode 100644 index 00000000000..06ae85bbd41 --- /dev/null +++ b/test/e2e/httpproxy/envoy_compression_test.go @@ -0,0 +1,79 @@ +// Copyright Project Contour Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build e2e + +package httpproxy + +import ( + "fmt" + . "github.com/onsi/ginkgo/v2" + "github.com/stretchr/testify/require" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "net/http" + + contour_v1 "github.com/projectcontour/contour/apis/projectcontour/v1" + "github.com/projectcontour/contour/test/e2e" +) + +func testEnvoyDisableCompression(namespace string, enabled bool) { + testSpec := "responses compressed with default settings" + if enabled { + testSpec = "responses are plaintext when compression disabled" + } + FSpecify(testSpec, func() { + resp := "minimum_text_to_enable_gzipminimum_text_to_enable_gzipminimum_text_to_enable_gzipminimum_text_to_enable_gzipminimum_text_to_enable_gzipminimum_text_to_enable_gzip" + p := &contour_v1.HTTPProxy{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: "direct-response", + Namespace: namespace, + }, + Spec: contour_v1.HTTPProxySpec{ + VirtualHost: &contour_v1.VirtualHost{ + Fqdn: fmt.Sprintf("%s-fqdn.projectcontour.io", namespace), + }, Routes: []contour_v1.Route{ + { + Conditions: []contour_v1.MatchCondition{{ + Prefix: "/directresponse", + }}, + DirectResponsePolicy: &contour_v1.HTTPDirectResponsePolicy{ + StatusCode: 200, + Body: resp, + }, + }}, + }, + } + require.True(f.T(), f.CreateHTTPProxyAndWaitFor(p, e2e.HTTPProxyValid)) + + // Send HTTP request, we will check backend connection was over HTTPS. + res, ok := f.HTTP.RequestUntil(&e2e.HTTPRequestOpts{ + Path: "/directresponse", + Host: p.Spec.VirtualHost.Fqdn, + RequestOpts: []func(*http.Request){ + e2e.OptSetHeaders(map[string]string{ + "Accept-Encoding": "gzip, deflate", + }), + }, + Condition: e2e.HasStatusCode(200), + }) + require.NotNil(f.T(), res, "request never succeeded") + require.Truef(f.T(), ok, "expected 200 response code, got %d", res.StatusCode) + fmt.Printf("response: %+v\n", res.Headers) + if enabled { + require.NotContains(f.T(), res.Headers["Content-Encoding"], "gzip", "expected plain text") + return + } + require.Contains(f.T(), res.Headers["Content-Encoding"], "gzip", "expected plain text") + + }) +} diff --git a/test/e2e/httpproxy/httpproxy_test.go b/test/e2e/httpproxy/httpproxy_test.go index ff01a0af897..42edb73bd9c 100644 --- a/test/e2e/httpproxy/httpproxy_test.go +++ b/test/e2e/httpproxy/httpproxy_test.go @@ -388,6 +388,19 @@ var _ = Describe("HTTPProxy", func() { }) }) + f.NamespacedTest("httpproxy-default-compression", func(namespace string) { + testEnvoyDisableCompression(namespace, false) + }) + + f.NamespacedTest("httpproxy-disable-compression", func(namespace string) { + Context("with compression disabled", func() { + BeforeEach(func() { + contourConfig.DisableCompression = true + }) + testEnvoyDisableCompression(namespace, true) + }) + }) + f.NamespacedTest("httpproxy-external-auth", testExternalAuth) f.NamespacedTest("httpproxy-http-health-checks", testHTTPHealthChecks) From 7ddb6f02363b96044c2445ab5a346b7dae41e84f Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Thu, 22 Aug 2024 17:46:08 +0100 Subject: [PATCH 03/30] This fixes linter nag parameter 'conf' seems to be unused Co-authored-by: Tero Saarni Signed-off-by: Geoff Macartney --- internal/featuretests/v3/compression_test.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/internal/featuretests/v3/compression_test.go b/internal/featuretests/v3/compression_test.go index af5e71f6f6a..4aea4b7e1cb 100644 --- a/internal/featuretests/v3/compression_test.go +++ b/internal/featuretests/v3/compression_test.go @@ -27,10 +27,7 @@ import ( ) func TestDefaultCompression(t *testing.T) { - withDefaultListenerConfig := func(conf *xdscache_v3.ListenerConfig) { - } - - rh, c, done := setup(t, withDefaultListenerConfig) + rh, c, done := setup(t) defer done() s1 := fixture.NewService("backend"). From 8df07e29b4563673fb07ba94871c6bef11c1e685 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Thu, 22 Aug 2024 17:47:50 +0100 Subject: [PATCH 04/30] This fixes linter nag File is not gci-ed with ... Co-authored-by: Tero Saarni Signed-off-by: Geoff Macartney --- test/e2e/httpproxy/envoy_compression_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/e2e/httpproxy/envoy_compression_test.go b/test/e2e/httpproxy/envoy_compression_test.go index 06ae85bbd41..3224d0469cd 100644 --- a/test/e2e/httpproxy/envoy_compression_test.go +++ b/test/e2e/httpproxy/envoy_compression_test.go @@ -17,10 +17,11 @@ package httpproxy import ( "fmt" + "net/http" + . "github.com/onsi/ginkgo/v2" "github.com/stretchr/testify/require" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "net/http" contour_v1 "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/projectcontour/contour/test/e2e" From 100bf40de4dad160b8df57922194625d5db35218 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Thu, 22 Aug 2024 17:48:27 +0100 Subject: [PATCH 05/30] This fixes linter nag File is not gci-ed with ... Co-authored-by: Tero Saarni Signed-off-by: Geoff Macartney --- internal/featuretests/v3/compression_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/featuretests/v3/compression_test.go b/internal/featuretests/v3/compression_test.go index 4aea4b7e1cb..1c16eaaa77b 100644 --- a/internal/featuretests/v3/compression_test.go +++ b/internal/featuretests/v3/compression_test.go @@ -14,10 +14,11 @@ package v3 import ( + "testing" + envoy_service_discovery_v3 "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" core_v1 "k8s.io/api/core/v1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "testing" contour_v1 "github.com/projectcontour/contour/apis/projectcontour/v1" contour_v1alpha1 "github.com/projectcontour/contour/apis/projectcontour/v1alpha1" From 56e4ee7442436f6c59bd810ac78fcf1125d1e447 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Thu, 22 Aug 2024 17:49:01 +0100 Subject: [PATCH 06/30] This fixes linter nag File is not gofumpt-ed with -extra Co-authored-by: Tero Saarni Signed-off-by: Geoff Macartney --- test/e2e/httpproxy/envoy_compression_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/e2e/httpproxy/envoy_compression_test.go b/test/e2e/httpproxy/envoy_compression_test.go index 3224d0469cd..44ff5d66987 100644 --- a/test/e2e/httpproxy/envoy_compression_test.go +++ b/test/e2e/httpproxy/envoy_compression_test.go @@ -51,7 +51,8 @@ func testEnvoyDisableCompression(namespace string, enabled bool) { StatusCode: 200, Body: resp, }, - }}, + }, + }, }, } require.True(f.T(), f.CreateHTTPProxyAndWaitFor(p, e2e.HTTPProxyValid)) From 548981ee0ee5b3cfc4d4d619f647de3b4bd8588a Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Thu, 22 Aug 2024 17:49:54 +0100 Subject: [PATCH 07/30] This fixes linter nag File is not gofumpt-ed with -extra Co-authored-by: Tero Saarni Signed-off-by: Geoff Macartney --- test/e2e/httpproxy/envoy_compression_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/test/e2e/httpproxy/envoy_compression_test.go b/test/e2e/httpproxy/envoy_compression_test.go index 44ff5d66987..9fd81366f4c 100644 --- a/test/e2e/httpproxy/envoy_compression_test.go +++ b/test/e2e/httpproxy/envoy_compression_test.go @@ -76,6 +76,5 @@ func testEnvoyDisableCompression(namespace string, enabled bool) { return } require.Contains(f.T(), res.Headers["Content-Encoding"], "gzip", "expected plain text") - }) } From 934ca4885b8371d3b541fdfd9b448007315fbf20 Mon Sep 17 00:00:00 2001 From: geomacy Date: Wed, 21 Aug 2024 17:53:15 +0100 Subject: [PATCH 08/30] Fix table borders This change is solely a formatting change and does not change any of the text of the table Signed-off-by: Geoff Macartney --- site/content/docs/main/configuration.md | 62 ++++++++++++------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/site/content/docs/main/configuration.md b/site/content/docs/main/configuration.md index 5277ab79e38..c13583b3b91 100644 --- a/site/content/docs/main/configuration.md +++ b/site/content/docs/main/configuration.md @@ -72,37 +72,37 @@ The Contour configuration file is optional. In its absence, Contour will operate with reasonable defaults. Where Contour settings can also be specified with command-line flags, the command-line value takes precedence over the configuration file. -| Field Name | Type | Default | Description | -|---------------------------| ---------------------- |------------------------------------------------------------------------------------------------------| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| accesslog-format | string | `envoy` | This key sets the global [access log format][2] for Envoy. Valid options are `envoy` or `json`. | -| accesslog-format-string | string | None | If present, this specifies custom access log format for Envoy. See [Envoy documentation](https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage) for more information about the syntax. This field only has effect if `accesslog-format` is `envoy` | -| accesslog-level | string | `info` | This field specifies the verbosity level of the access log. Valid options are `info` (default, all requests are logged), `error` (all non-success, i.e. 300+ response code, requests are logged), `critical` (all server error, i.e. 500+ response code, requests are logged) and `disabled`. | -| debug | boolean | `false` | Enables debug logging. | -| default-http-versions | string array | HTTP/1.1
HTTP/2 | This array specifies the HTTP versions that Contour should program Envoy to serve. HTTP versions are specified as strings of the form "HTTP/x", where "x" represents the version number. | -| disableAllowChunkedLength | boolean | `false` | If this field is true, Contour will disable the RFC-compliant Envoy behavior to strip the `Content-Length` header if `Transfer-Encoding: chunked` is also set. This is an emergency off-switch to revert back to Envoy's default behavior in case of failures. -| disableMergeSlashes | boolean | `false` | This field disables Envoy's non-standard merge_slashes path transformation behavior that strips duplicate slashes from request URL paths. -| serverHeaderTransformation | string | `overwrite` | This field defines the action to be applied to the Server header on the response path. Values: `overwrite` (default), `append_if_absent`, `pass_through` -| disablePermitInsecure | boolean | `false` | If this field is true, Contour will ignore `PermitInsecure` field in HTTPProxy documents. | -| envoy-service-name | string | `envoy` | This sets the service name that will be inspected for address details to be applied to Ingress objects. | -| envoy-service-namespace | string | `projectcontour` | This sets the namespace of the service that will be inspected for address details to be applied to Ingress objects. If the `CONTOUR_NAMESPACE` environment variable is present, Contour will populate this field with its value. | -| ingress-status-address | string | None | If present, this specifies the address that will be copied into the Ingress status for each Ingress that Contour manages. It is exclusive with `envoy-service-name` and `envoy-service-namespace`. | -| incluster | boolean | `false` | This field specifies that Contour is running in a Kubernetes cluster and should use the in-cluster client access configuration. | -| json-fields | string array | [fields][5] | This is the list the field names to include in the JSON [access log format][2]. This field only has effect if `accesslog-format` is `json`. | -| kubeconfig | string | `$HOME/.kube/config` | Path to a Kubernetes [kubeconfig file][3] for when Contour is executed outside a cluster. | -| kubernetesClientQPS | float32 | | QPS allowed for the Kubernetes client. | -| kubernetesClientBurst | int | | Burst allowed for the Kubernetes client. | -| policy | PolicyConfig | | The default [policy configuration](#policy-configuration). | -| tls | TLS | | The default [TLS configuration](#tls-configuration). | -| timeouts | TimeoutConfig | | The [timeout configuration](#timeout-configuration). | -| cluster | ClusterConfig | | The [cluster configuration](#cluster-configuration). | -| network | NetworkConfig | | The [network configuration](#network-configuration). | -| listener | ListenerConfig | | The [listener configuration](#listener-configuration). | -| server | ServerConfig | | The [server configuration](#server-configuration) for `contour serve` command. | -| gateway | GatewayConfig | | The [gateway-api Gateway configuration](#gateway-configuration). | -| rateLimitService | RateLimitServiceConfig | | The [rate limit service configuration](#rate-limit-service-configuration). | -| enableExternalNameService | boolean | `false` | Enable ExternalName Service processing. Enabling this has security implications. Please see the [advisory](https://github.com/projectcontour/contour/security/advisories/GHSA-5ph6-qq5x-7jwc) for more details. | -| metrics | MetricsParameters | | The [metrics configuration](#metrics-configuration) | -| featureFlags | string array | `[]` | Defines the toggle to enable new contour features. Available toggles are:
1. `useEndpointSlices` - configures contour to fetch endpoint data from k8s endpoint slices. | +| Field Name | Type | Default | Description | +|----------------------------|------------------------|------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| accesslog-format | string | `envoy` | This key sets the global [access log format][2] for Envoy. Valid options are `envoy` or `json`. | +| accesslog-format-string | string | None | If present, this specifies custom access log format for Envoy. See [Envoy documentation](https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage) for more information about the syntax. This field only has effect if `accesslog-format` is `envoy` | +| accesslog-level | string | `info` | This field specifies the verbosity level of the access log. Valid options are `info` (default, all requests are logged), `error` (all non-success, i.e. 300+ response code, requests are logged), `critical` (all server error, i.e. 500+ response code, requests are logged) and `disabled`. | +| debug | boolean | `false` | Enables debug logging. | +| default-http-versions | string array | HTTP/1.1
HTTP/2 | This array specifies the HTTP versions that Contour should program Envoy to serve. HTTP versions are specified as strings of the form "HTTP/x", where "x" represents the version number. | +| disableAllowChunkedLength | boolean | `false` | If this field is true, Contour will disable the RFC-compliant Envoy behavior to strip the `Content-Length` header if `Transfer-Encoding: chunked` is also set. This is an emergency off-switch to revert back to Envoy's default behavior in case of failures. | +| disableMergeSlashes | boolean | `false` | This field disables Envoy's non-standard merge_slashes path transformation behavior that strips duplicate slashes from request URL paths. | +| serverHeaderTransformation | string | `overwrite` | This field defines the action to be applied to the Server header on the response path. Values: `overwrite` (default), `append_if_absent`, `pass_through` | +| disablePermitInsecure | boolean | `false` | If this field is true, Contour will ignore `PermitInsecure` field in HTTPProxy documents. | +| envoy-service-name | string | `envoy` | This sets the service name that will be inspected for address details to be applied to Ingress objects. | +| envoy-service-namespace | string | `projectcontour` | This sets the namespace of the service that will be inspected for address details to be applied to Ingress objects. If the `CONTOUR_NAMESPACE` environment variable is present, Contour will populate this field with its value. | +| ingress-status-address | string | None | If present, this specifies the address that will be copied into the Ingress status for each Ingress that Contour manages. It is exclusive with `envoy-service-name` and `envoy-service-namespace`. | +| incluster | boolean | `false` | This field specifies that Contour is running in a Kubernetes cluster and should use the in-cluster client access configuration. | +| json-fields | string array | [fields][5] | This is the list the field names to include in the JSON [access log format][2]. This field only has effect if `accesslog-format` is `json`. | +| kubeconfig | string | `$HOME/.kube/config` | Path to a Kubernetes [kubeconfig file][3] for when Contour is executed outside a cluster. | +| kubernetesClientQPS | float32 | | QPS allowed for the Kubernetes client. | +| kubernetesClientBurst | int | | Burst allowed for the Kubernetes client. | +| policy | PolicyConfig | | The default [policy configuration](#policy-configuration). | +| tls | TLS | | The default [TLS configuration](#tls-configuration). | +| timeouts | TimeoutConfig | | The [timeout configuration](#timeout-configuration). | +| cluster | ClusterConfig | | The [cluster configuration](#cluster-configuration). | +| network | NetworkConfig | | The [network configuration](#network-configuration). | +| listener | ListenerConfig | | The [listener configuration](#listener-configuration). | +| server | ServerConfig | | The [server configuration](#server-configuration) for `contour serve` command. | +| gateway | GatewayConfig | | The [gateway-api Gateway configuration](#gateway-configuration). | +| rateLimitService | RateLimitServiceConfig | | The [rate limit service configuration](#rate-limit-service-configuration). | +| enableExternalNameService | boolean | `false` | Enable ExternalName Service processing. Enabling this has security implications. Please see the [advisory](https://github.com/projectcontour/contour/security/advisories/GHSA-5ph6-qq5x-7jwc) for more details. | +| metrics | MetricsParameters | | The [metrics configuration](#metrics-configuration) | +| featureFlags | string array | `[]` | Defines the toggle to enable new contour features. Available toggles are:
1. `useEndpointSlices` - configures contour to fetch endpoint data from k8s endpoint slices. | ### TLS Configuration From 2efb693d8230eeef88cdb0a553d7d3842f72a69d Mon Sep 17 00:00:00 2001 From: geomacy Date: Wed, 21 Aug 2024 17:57:38 +0100 Subject: [PATCH 09/30] Add disableCompression flag to configuration docs. Signed-off-by: Geoff Macartney --- site/content/docs/main/configuration.md | 1 + 1 file changed, 1 insertion(+) diff --git a/site/content/docs/main/configuration.md b/site/content/docs/main/configuration.md index c13583b3b91..588ce55be29 100644 --- a/site/content/docs/main/configuration.md +++ b/site/content/docs/main/configuration.md @@ -80,6 +80,7 @@ Where Contour settings can also be specified with command-line flags, the comman | debug | boolean | `false` | Enables debug logging. | | default-http-versions | string array | HTTP/1.1
HTTP/2 | This array specifies the HTTP versions that Contour should program Envoy to serve. HTTP versions are specified as strings of the form "HTTP/x", where "x" represents the version number. | | disableAllowChunkedLength | boolean | `false` | If this field is true, Contour will disable the RFC-compliant Envoy behavior to strip the `Content-Length` header if `Transfer-Encoding: chunked` is also set. This is an emergency off-switch to revert back to Envoy's default behavior in case of failures. | +| disableCompression | boolean | `false` | This disables GZIP compression HTTP filter from the default Listener filters. Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response. | | disableMergeSlashes | boolean | `false` | This field disables Envoy's non-standard merge_slashes path transformation behavior that strips duplicate slashes from request URL paths. | | serverHeaderTransformation | string | `overwrite` | This field defines the action to be applied to the Server header on the response path. Values: `overwrite` (default), `append_if_absent`, `pass_through` | | disablePermitInsecure | boolean | `false` | If this field is true, Contour will ignore `PermitInsecure` field in HTTPProxy documents. | From b0cfe71408ff38baebede555600871fd9ef7f0af Mon Sep 17 00:00:00 2001 From: geomacy Date: Thu, 22 Aug 2024 17:26:27 +0100 Subject: [PATCH 10/30] add changelog file Signed-off-by: Geoff Macartney --- changelogs/unreleased/6546-chaosbox-small.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/unreleased/6546-chaosbox-small.md diff --git a/changelogs/unreleased/6546-chaosbox-small.md b/changelogs/unreleased/6546-chaosbox-small.md new file mode 100644 index 00000000000..18f2b2138e1 --- /dev/null +++ b/changelogs/unreleased/6546-chaosbox-small.md @@ -0,0 +1 @@ +Add disableCompression boolean flag to disable GZIP compression HTTP filter from the default Listener filters. From 7e843b7a1fddb6b56d65a19385a052008250f4d0 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Sat, 7 Sep 2024 23:35:44 +0100 Subject: [PATCH 11/30] rework as --compression flag with options gzip, brotli, zstd, disabled Signed-off-by: Geoff Macartney --- apis/projectcontour/v1alpha1/compression.go | 41 +++++ .../v1alpha1/compression_test.go | 32 ++++ apis/projectcontour/v1alpha1/contourconfig.go | 8 +- changelogs/unreleased/6546-chaosbox-small.md | 2 +- cmd/contour/serve.go | 5 +- cmd/contour/servecontext.go | 14 +- cmd/contour/servecontext_test.go | 5 +- examples/contour/01-crds.yaml | 24 +-- examples/render/contour-deployment.yaml | 24 +-- .../render/contour-gateway-provisioner.yaml | 24 +-- examples/render/contour-gateway.yaml | 24 +-- examples/render/contour.yaml | 24 +-- .../contourconfig/contourconfiguration.go | 1 + .../contourconfiguration_test.go | 5 +- internal/envoy/v3/listener.go | 31 +++- internal/featuretests/v3/compression_test.go | 100 +++++++++- internal/xdscache/v3/listener.go | 14 +- internal/xdscache/v3/listener_test.go | 174 +++++++++++++++++- pkg/config/parameters.go | 30 ++- pkg/config/parameters_test.go | 1 + .../docs/main/config/api-reference.html | 41 ++++- site/content/docs/main/configuration.md | 64 +++---- test/e2e/deployment.go | 2 +- test/e2e/fixtures.go | 1 + test/e2e/httpproxy/envoy_compression_test.go | 50 ++--- test/e2e/httpproxy/httpproxy_test.go | 27 ++- 26 files changed, 611 insertions(+), 157 deletions(-) create mode 100644 apis/projectcontour/v1alpha1/compression.go create mode 100644 apis/projectcontour/v1alpha1/compression_test.go diff --git a/apis/projectcontour/v1alpha1/compression.go b/apis/projectcontour/v1alpha1/compression.go new file mode 100644 index 00000000000..9c850934eda --- /dev/null +++ b/apis/projectcontour/v1alpha1/compression.go @@ -0,0 +1,41 @@ +// Copyright Project Contour Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1alpha1 + +import "fmt" + +type EnvoyCompressionType string + +func (c EnvoyCompressionType) Validate() error { + switch c { + case BrotliCompression, DisabledCompression, GzipCompression, ZstdCompression: + return nil + default: + return fmt.Errorf("invalid compression type: %q", c) + } +} + +const ( + // BrotliCompression specifies brotli as the default HTTP filter chain compression mechanism + BrotliCompression EnvoyCompressionType = "brotli" + + // DisabledCompression specifies that there will be no compression in the default HTTP filter chain + DisabledCompression EnvoyCompressionType = "disabled" + + // GzipCompression specifies gzip as the default HTTP filter chain compression mechanism + GzipCompression EnvoyCompressionType = "gzip" + + // ZstdCompression specifies zstd as the default HTTP filter chain compression mechanism + ZstdCompression EnvoyCompressionType = "zstd" +) diff --git a/apis/projectcontour/v1alpha1/compression_test.go b/apis/projectcontour/v1alpha1/compression_test.go new file mode 100644 index 00000000000..d90ad832aa4 --- /dev/null +++ b/apis/projectcontour/v1alpha1/compression_test.go @@ -0,0 +1,32 @@ +// Copyright Project Contour Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1alpha1_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + contour_v1alpha1 "github.com/projectcontour/contour/apis/projectcontour/v1alpha1" +) + +func TestValidateEnvoyCompressionType(t *testing.T) { + require.Error(t, contour_v1alpha1.EnvoyCompressionType("").Validate()) + require.Error(t, contour_v1alpha1.EnvoyCompressionType("foo").Validate()) + + require.NoError(t, contour_v1alpha1.BrotliCompression.Validate()) + require.NoError(t, contour_v1alpha1.DisabledCompression.Validate()) + require.NoError(t, contour_v1alpha1.GzipCompression.Validate()) + require.NoError(t, contour_v1alpha1.ZstdCompression.Validate()) +} diff --git a/apis/projectcontour/v1alpha1/contourconfig.go b/apis/projectcontour/v1alpha1/contourconfig.go index 8a51321a077..d96ff51691b 100644 --- a/apis/projectcontour/v1alpha1/contourconfig.go +++ b/apis/projectcontour/v1alpha1/contourconfig.go @@ -348,11 +348,11 @@ type EnvoyListenerConfig struct { // +optional UseProxyProto *bool `json:"useProxyProtocol,omitempty"` - // DisableCompression disables GZIP compression HTTP filter from the default Listener filters - // Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - // Contour's default is false. + // Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. + // Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + // Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response // +optional - DisableCompression bool `json:"disableCompression,omitempty"` + Compression EnvoyCompressionType `json:"compression,omitempty"` // DisableAllowChunkedLength disables the RFC-compliant Envoy behavior to // strip the "Content-Length" header if "Transfer-Encoding: chunked" is diff --git a/changelogs/unreleased/6546-chaosbox-small.md b/changelogs/unreleased/6546-chaosbox-small.md index 18f2b2138e1..5f156b7289d 100644 --- a/changelogs/unreleased/6546-chaosbox-small.md +++ b/changelogs/unreleased/6546-chaosbox-small.md @@ -1 +1 @@ -Add disableCompression boolean flag to disable GZIP compression HTTP filter from the default Listener filters. +Add "compression" flag to set/disable the compression type applied in the default HTTP filter chain. diff --git a/cmd/contour/serve.go b/cmd/contour/serve.go index 5ab881936ec..b361a56d2b1 100644 --- a/cmd/contour/serve.go +++ b/cmd/contour/serve.go @@ -125,6 +125,7 @@ func registerServe(app *kingpin.Application) (*kingpin.CmdClause, *serveContext) } serve.Flag("accesslog-format", "Format for Envoy access logs.").PlaceHolder("").StringVar((*string)(&ctx.Config.AccessLogFormat)) + serve.Flag("compression", "Set or disable compression type in default Listener filters.").PlaceHolder("").StringVar((*string)(&ctx.Config.Compression)) serve.Flag("config-path", "Path to base configuration.").Short('c').PlaceHolder("/path/to/file").Action(parseConfig).ExistingFileVar(&configFile) serve.Flag("contour-cafile", "CA bundle file name for serving gRPC with TLS.").Envar("CONTOUR_CAFILE").StringVar(&ctx.caFile) serve.Flag("contour-cert-file", "Contour certificate file name for serving gRPC over TLS.").PlaceHolder("/path/to/file").Envar("CONTOUR_CERT_FILE").StringVar(&ctx.contourCert) @@ -447,7 +448,7 @@ func (s *Server) doServe() error { } listenerConfig := xdscache_v3.ListenerConfig{ - DisableCompression: contourConfiguration.Envoy.Listener.DisableCompression, + Compression: contourConfiguration.Envoy.Listener.Compression, UseProxyProto: *contourConfiguration.Envoy.Listener.UseProxyProto, HTTPAccessLog: contourConfiguration.Envoy.HTTPListener.AccessLog, HTTPSAccessLog: contourConfiguration.Envoy.HTTPSListener.AccessLog, @@ -472,6 +473,8 @@ func (s *Server) doServe() error { SocketOptions: contourConfiguration.Envoy.Listener.SocketOptions, } + s.log.WithField("context", "listenerConfig").Infof("compression setting: %s", listenerConfig.Compression) + if listenerConfig.TracingConfig, err = s.setupTracingService(contourConfiguration.Tracing); err != nil { return err } diff --git a/cmd/contour/servecontext.go b/cmd/contour/servecontext.go index 67451bc0ad7..37d0936e18f 100644 --- a/cmd/contour/servecontext.go +++ b/cmd/contour/servecontext.go @@ -333,6 +333,18 @@ func (ctx *serveContext) convertToContourConfigurationSpec() contour_v1alpha1.Co accessLogLevel = contour_v1alpha1.LogLevelDisabled } + var compression contour_v1alpha1.EnvoyCompressionType + switch ctx.Config.Compression { + case config.CompressionBrotli: + compression = contour_v1alpha1.BrotliCompression + case config.CompressionDisabled: + compression = contour_v1alpha1.DisabledCompression + case config.CompressionGzip: + compression = contour_v1alpha1.GzipCompression + case config.CompressionZstd: + compression = contour_v1alpha1.ZstdCompression + } + var defaultHTTPVersions []contour_v1alpha1.HTTPVersionType for _, version := range ctx.Config.DefaultHTTPVersions { switch version { @@ -519,7 +531,7 @@ func (ctx *serveContext) convertToContourConfigurationSpec() contour_v1alpha1.Co Envoy: &contour_v1alpha1.EnvoyConfig{ Listener: &contour_v1alpha1.EnvoyListenerConfig{ UseProxyProto: &ctx.useProxyProto, - DisableCompression: ctx.Config.DisableCompression, + Compression: compression, DisableAllowChunkedLength: &ctx.Config.DisableAllowChunkedLength, DisableMergeSlashes: &ctx.Config.DisableMergeSlashes, ServerHeaderTransformation: serverHeaderTransformation, diff --git a/cmd/contour/servecontext_test.go b/cmd/contour/servecontext_test.go index b6bf90738e1..5f946f18e6a 100644 --- a/cmd/contour/servecontext_test.go +++ b/cmd/contour/servecontext_test.go @@ -408,6 +408,7 @@ func TestConvertServeContext(t *testing.T) { }, Listener: &contour_v1alpha1.EnvoyListenerConfig{ UseProxyProto: ptr.To(false), + Compression: "gzip", DisableAllowChunkedLength: ptr.To(false), DisableMergeSlashes: ptr.To(false), ServerHeaderTransformation: contour_v1alpha1.OverwriteServerHeader, @@ -892,14 +893,14 @@ func TestConvertServeContext(t *testing.T) { ctx.Config.Listener.MaxRequestsPerIOCycle = ptr.To(uint32(10)) ctx.Config.Listener.HTTP2MaxConcurrentStreams = ptr.To(uint32(30)) ctx.Config.Listener.MaxConnectionsPerListener = ptr.To(uint32(50)) - ctx.Config.DisableCompression = true + ctx.Config.Compression = "gzip" return ctx }, getContourConfiguration: func(cfg contour_v1alpha1.ContourConfigurationSpec) contour_v1alpha1.ContourConfigurationSpec { cfg.Envoy.Listener.MaxRequestsPerIOCycle = ptr.To(uint32(10)) cfg.Envoy.Listener.HTTP2MaxConcurrentStreams = ptr.To(uint32(30)) cfg.Envoy.Listener.MaxConnectionsPerListener = ptr.To(uint32(50)) - cfg.Envoy.Listener.DisableCompression = true + cfg.Envoy.Listener.Compression = "gzip" return cfg }, }, diff --git a/examples/contour/01-crds.yaml b/examples/contour/01-crds.yaml index 6118314e158..911f670200e 100644 --- a/examples/contour/01-crds.yaml +++ b/examples/contour/01-crds.yaml @@ -281,6 +281,12 @@ spec: description: Listener hold various configurable Envoy listener values. properties: + compression: + description: |- + Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. + Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + type: string connectionBalancer: description: |- ConnectionBalancer. If the value is exact, the listener will use the exact connection balancer @@ -299,12 +305,6 @@ spec: See: https://github.com/projectcontour/contour/issues/3221 Contour's default is false. type: boolean - disableCompression: - description: |- - DisableCompression disables GZIP compression HTTP filter from the default Listener filters - Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - Contour's default is false. - type: boolean disableMergeSlashes: description: |- DisableMergeSlashes disables Envoy's non-standard merge_slashes path transformation option @@ -4069,6 +4069,12 @@ spec: description: Listener hold various configurable Envoy listener values. properties: + compression: + description: |- + Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. + Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + type: string connectionBalancer: description: |- ConnectionBalancer. If the value is exact, the listener will use the exact connection balancer @@ -4087,12 +4093,6 @@ spec: See: https://github.com/projectcontour/contour/issues/3221 Contour's default is false. type: boolean - disableCompression: - description: |- - DisableCompression disables GZIP compression HTTP filter from the default Listener filters - Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - Contour's default is false. - type: boolean disableMergeSlashes: description: |- DisableMergeSlashes disables Envoy's non-standard merge_slashes path transformation option diff --git a/examples/render/contour-deployment.yaml b/examples/render/contour-deployment.yaml index 89fa0c0118d..08de1688e9a 100644 --- a/examples/render/contour-deployment.yaml +++ b/examples/render/contour-deployment.yaml @@ -501,6 +501,12 @@ spec: description: Listener hold various configurable Envoy listener values. properties: + compression: + description: |- + Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. + Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + type: string connectionBalancer: description: |- ConnectionBalancer. If the value is exact, the listener will use the exact connection balancer @@ -519,12 +525,6 @@ spec: See: https://github.com/projectcontour/contour/issues/3221 Contour's default is false. type: boolean - disableCompression: - description: |- - DisableCompression disables GZIP compression HTTP filter from the default Listener filters - Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - Contour's default is false. - type: boolean disableMergeSlashes: description: |- DisableMergeSlashes disables Envoy's non-standard merge_slashes path transformation option @@ -4289,6 +4289,12 @@ spec: description: Listener hold various configurable Envoy listener values. properties: + compression: + description: |- + Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. + Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + type: string connectionBalancer: description: |- ConnectionBalancer. If the value is exact, the listener will use the exact connection balancer @@ -4307,12 +4313,6 @@ spec: See: https://github.com/projectcontour/contour/issues/3221 Contour's default is false. type: boolean - disableCompression: - description: |- - DisableCompression disables GZIP compression HTTP filter from the default Listener filters - Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - Contour's default is false. - type: boolean disableMergeSlashes: description: |- DisableMergeSlashes disables Envoy's non-standard merge_slashes path transformation option diff --git a/examples/render/contour-gateway-provisioner.yaml b/examples/render/contour-gateway-provisioner.yaml index 8b02f26cae0..9302324f810 100644 --- a/examples/render/contour-gateway-provisioner.yaml +++ b/examples/render/contour-gateway-provisioner.yaml @@ -292,6 +292,12 @@ spec: description: Listener hold various configurable Envoy listener values. properties: + compression: + description: |- + Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. + Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + type: string connectionBalancer: description: |- ConnectionBalancer. If the value is exact, the listener will use the exact connection balancer @@ -310,12 +316,6 @@ spec: See: https://github.com/projectcontour/contour/issues/3221 Contour's default is false. type: boolean - disableCompression: - description: |- - DisableCompression disables GZIP compression HTTP filter from the default Listener filters - Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - Contour's default is false. - type: boolean disableMergeSlashes: description: |- DisableMergeSlashes disables Envoy's non-standard merge_slashes path transformation option @@ -4080,6 +4080,12 @@ spec: description: Listener hold various configurable Envoy listener values. properties: + compression: + description: |- + Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. + Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + type: string connectionBalancer: description: |- ConnectionBalancer. If the value is exact, the listener will use the exact connection balancer @@ -4098,12 +4104,6 @@ spec: See: https://github.com/projectcontour/contour/issues/3221 Contour's default is false. type: boolean - disableCompression: - description: |- - DisableCompression disables GZIP compression HTTP filter from the default Listener filters - Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - Contour's default is false. - type: boolean disableMergeSlashes: description: |- DisableMergeSlashes disables Envoy's non-standard merge_slashes path transformation option diff --git a/examples/render/contour-gateway.yaml b/examples/render/contour-gateway.yaml index db7f84f459f..a993637fc75 100644 --- a/examples/render/contour-gateway.yaml +++ b/examples/render/contour-gateway.yaml @@ -317,6 +317,12 @@ spec: description: Listener hold various configurable Envoy listener values. properties: + compression: + description: |- + Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. + Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + type: string connectionBalancer: description: |- ConnectionBalancer. If the value is exact, the listener will use the exact connection balancer @@ -335,12 +341,6 @@ spec: See: https://github.com/projectcontour/contour/issues/3221 Contour's default is false. type: boolean - disableCompression: - description: |- - DisableCompression disables GZIP compression HTTP filter from the default Listener filters - Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - Contour's default is false. - type: boolean disableMergeSlashes: description: |- DisableMergeSlashes disables Envoy's non-standard merge_slashes path transformation option @@ -4105,6 +4105,12 @@ spec: description: Listener hold various configurable Envoy listener values. properties: + compression: + description: |- + Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. + Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + type: string connectionBalancer: description: |- ConnectionBalancer. If the value is exact, the listener will use the exact connection balancer @@ -4123,12 +4129,6 @@ spec: See: https://github.com/projectcontour/contour/issues/3221 Contour's default is false. type: boolean - disableCompression: - description: |- - DisableCompression disables GZIP compression HTTP filter from the default Listener filters - Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - Contour's default is false. - type: boolean disableMergeSlashes: description: |- DisableMergeSlashes disables Envoy's non-standard merge_slashes path transformation option diff --git a/examples/render/contour.yaml b/examples/render/contour.yaml index 12cc1c7cd6a..ffd55e0337d 100644 --- a/examples/render/contour.yaml +++ b/examples/render/contour.yaml @@ -501,6 +501,12 @@ spec: description: Listener hold various configurable Envoy listener values. properties: + compression: + description: |- + Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. + Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + type: string connectionBalancer: description: |- ConnectionBalancer. If the value is exact, the listener will use the exact connection balancer @@ -519,12 +525,6 @@ spec: See: https://github.com/projectcontour/contour/issues/3221 Contour's default is false. type: boolean - disableCompression: - description: |- - DisableCompression disables GZIP compression HTTP filter from the default Listener filters - Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - Contour's default is false. - type: boolean disableMergeSlashes: description: |- DisableMergeSlashes disables Envoy's non-standard merge_slashes path transformation option @@ -4289,6 +4289,12 @@ spec: description: Listener hold various configurable Envoy listener values. properties: + compression: + description: |- + Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. + Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + type: string connectionBalancer: description: |- ConnectionBalancer. If the value is exact, the listener will use the exact connection balancer @@ -4307,12 +4313,6 @@ spec: See: https://github.com/projectcontour/contour/issues/3221 Contour's default is false. type: boolean - disableCompression: - description: |- - DisableCompression disables GZIP compression HTTP filter from the default Listener filters - Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - Contour's default is false. - type: boolean disableMergeSlashes: description: |- DisableMergeSlashes disables Envoy's non-standard merge_slashes path transformation option diff --git a/internal/contourconfig/contourconfiguration.go b/internal/contourconfig/contourconfiguration.go index 0c369f170cb..9dbaf7e1d40 100644 --- a/internal/contourconfig/contourconfiguration.go +++ b/internal/contourconfig/contourconfiguration.go @@ -66,6 +66,7 @@ func Defaults() contour_v1alpha1.ContourConfigurationSpec { Envoy: &contour_v1alpha1.EnvoyConfig{ Listener: &contour_v1alpha1.EnvoyListenerConfig{ UseProxyProto: ptr.To(false), + Compression: contour_v1alpha1.GzipCompression, DisableAllowChunkedLength: ptr.To(false), DisableMergeSlashes: ptr.To(false), ServerHeaderTransformation: contour_v1alpha1.OverwriteServerHeader, diff --git a/internal/contourconfig/contourconfiguration_test.go b/internal/contourconfig/contourconfiguration_test.go index bb13b8229da..7ee574985cd 100644 --- a/internal/contourconfig/contourconfiguration_test.go +++ b/internal/contourconfig/contourconfiguration_test.go @@ -55,10 +55,11 @@ func TestOverlayOnDefaults(t *testing.T) { Envoy: &contour_v1alpha1.EnvoyConfig{ Listener: &contour_v1alpha1.EnvoyListenerConfig{ UseProxyProto: ptr.To(true), - DisableAllowChunkedLength: ptr.To(true), - DisableMergeSlashes: ptr.To(true), + Compression: "brotli", MaxRequestsPerConnection: ptr.To(uint32(1)), HTTP2MaxConcurrentStreams: ptr.To(uint32(10)), + DisableAllowChunkedLength: ptr.To(true), + DisableMergeSlashes: ptr.To(true), ServerHeaderTransformation: contour_v1alpha1.PassThroughServerHeader, ConnectionBalancer: "yesplease", TLS: &contour_v1alpha1.EnvoyTLS{ diff --git a/internal/envoy/v3/listener.go b/internal/envoy/v3/listener.go index fc57b436645..63d71d77340 100644 --- a/internal/envoy/v3/listener.go +++ b/internal/envoy/v3/listener.go @@ -23,7 +23,9 @@ import ( envoy_config_accesslog_v3 "github.com/envoyproxy/go-control-plane/envoy/config/accesslog/v3" envoy_config_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" envoy_config_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" + envoy_compression_brotli_compressor_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/compression/brotli/compressor/v3" envoy_compression_gzip_compressor_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/compression/gzip/compressor/v3" + envoy_compression_zstd_compressor_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/compression/zstd/compressor/v3" envoy_filter_http_compressor_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/compressor/v3" envoy_filter_http_cors_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/cors/v3" envoy_filter_http_ext_authz_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/ext_authz/v3" @@ -41,6 +43,7 @@ import ( envoy_transport_socket_tls_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3" envoy_type_v3 "github.com/envoyproxy/go-control-plane/envoy/type/v3" "github.com/envoyproxy/go-control-plane/pkg/wellknown" + "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/wrapperspb" @@ -188,7 +191,7 @@ type httpConnectionManagerBuilder struct { maxRequestsPerConnection *uint32 http2MaxConcurrentStreams *uint32 enableWebsockets bool - disableCompression bool + compression contour_v1alpha1.EnvoyCompressionType } func (b *httpConnectionManagerBuilder) EnableWebsockets(enable bool) *httpConnectionManagerBuilder { @@ -272,8 +275,8 @@ func (b *httpConnectionManagerBuilder) MergeSlashes(enabled bool) *httpConnectio return b } -func (b *httpConnectionManagerBuilder) DisableCompression(disabled bool) *httpConnectionManagerBuilder { - b.disableCompression = disabled +func (b *httpConnectionManagerBuilder) Compression(compressor contour_v1alpha1.EnvoyCompressionType) *httpConnectionManagerBuilder { + b.compression = compressor return b } @@ -314,7 +317,23 @@ func (b *httpConnectionManagerBuilder) DefaultFilters() *httpConnectionManagerBu // Add a default set of ordered http filters. // The names are not required to match anything and are // identified by the TypeURL of each filter. - if !b.disableCompression { + var compressor proto.Message + compressorName := "" + switch b.compression { + case contour_v1alpha1.BrotliCompression: + compressorName = "brotli" + compressor = &envoy_compression_brotli_compressor_v3.Brotli{} + case contour_v1alpha1.DisabledCompression: + compressor = nil + case contour_v1alpha1.ZstdCompression: + compressorName = "zstd" + compressor = &envoy_compression_zstd_compressor_v3.Zstd{} + default: + compressorName = "gzip" + compressor = &envoy_compression_gzip_compressor_v3.Gzip{} + } + + if compressor != nil { // If compression is enabled add compressor filter b.filters = append(b.filters, &envoy_filter_network_http_connection_manager_v3.HttpFilter{ @@ -322,9 +341,9 @@ func (b *httpConnectionManagerBuilder) DefaultFilters() *httpConnectionManagerBu ConfigType: &envoy_filter_network_http_connection_manager_v3.HttpFilter_TypedConfig{ TypedConfig: protobuf.MustMarshalAny(&envoy_filter_http_compressor_v3.Compressor{ CompressorLibrary: &envoy_config_core_v3.TypedExtensionConfig{ - Name: "gzip", + Name: compressorName, TypedConfig: protobuf.MustMarshalAny( - &envoy_compression_gzip_compressor_v3.Gzip{}, + compressor, ), }, ResponseDirectionConfig: &envoy_filter_http_compressor_v3.Compressor_ResponseDirectionConfig{ diff --git a/internal/featuretests/v3/compression_test.go b/internal/featuretests/v3/compression_test.go index 1c16eaaa77b..a0c941438c8 100644 --- a/internal/featuretests/v3/compression_test.go +++ b/internal/featuretests/v3/compression_test.go @@ -72,7 +72,7 @@ func TestDefaultCompression(t *testing.T) { func TestDisableCompression(t *testing.T) { withDisableCompression := func(conf *xdscache_v3.ListenerConfig) { - conf.DisableCompression = true + conf.Compression = "disabled" } rh, c, done := setup(t, withDisableCompression) @@ -104,7 +104,103 @@ func TestDisableCompression(t *testing.T) { httpListener := defaultHTTPListener() httpListener.FilterChains = envoy_v3.FilterChains(envoy_v3.HTTPConnectionManagerBuilder(). - DisableCompression(true). + Compression("disabled"). + RouteConfigName(xdscache_v3.ENVOY_HTTP_LISTENER). + MetricsPrefix(xdscache_v3.ENVOY_HTTP_LISTENER). + AccessLoggers(envoy_v3.FileAccessLogEnvoy(xdscache_v3.DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). + DefaultFilters(). + Get(), + ) + + c.Request(listenerType, xdscache_v3.ENVOY_HTTP_LISTENER).Equals(&envoy_service_discovery_v3.DiscoveryResponse{ + TypeUrl: listenerType, + Resources: resources(t, httpListener), + }) +} + +func TestBrotliCompression(t *testing.T) { + withBrotliCompression := func(conf *xdscache_v3.ListenerConfig) { + conf.Compression = "brotli" + } + + rh, c, done := setup(t, withBrotliCompression) + defer done() + + s1 := fixture.NewService("backend"). + WithPorts(core_v1.ServicePort{Name: "http", Port: 80}) + rh.OnAdd(s1) + + hp1 := &contour_v1.HTTPProxy{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: "simple", + Namespace: s1.Namespace, + }, + Spec: contour_v1.HTTPProxySpec{ + VirtualHost: &contour_v1.VirtualHost{ + Fqdn: "example.com", + }, + Routes: []contour_v1.Route{{ + Conditions: matchconditions(prefixMatchCondition("/")), + Services: []contour_v1.Service{{ + Name: s1.Name, + Port: 80, + }}, + }}, + }, + } + rh.OnAdd(hp1) + + httpListener := defaultHTTPListener() + httpListener.FilterChains = envoy_v3.FilterChains(envoy_v3.HTTPConnectionManagerBuilder(). + Compression("brotli"). + RouteConfigName(xdscache_v3.ENVOY_HTTP_LISTENER). + MetricsPrefix(xdscache_v3.ENVOY_HTTP_LISTENER). + AccessLoggers(envoy_v3.FileAccessLogEnvoy(xdscache_v3.DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). + DefaultFilters(). + Get(), + ) + + c.Request(listenerType, xdscache_v3.ENVOY_HTTP_LISTENER).Equals(&envoy_service_discovery_v3.DiscoveryResponse{ + TypeUrl: listenerType, + Resources: resources(t, httpListener), + }) +} + +func TestZstdCompression(t *testing.T) { + withZstdCompression := func(conf *xdscache_v3.ListenerConfig) { + conf.Compression = "zstd" + } + + rh, c, done := setup(t, withZstdCompression) + defer done() + + s1 := fixture.NewService("backend"). + WithPorts(core_v1.ServicePort{Name: "http", Port: 80}) + rh.OnAdd(s1) + + hp1 := &contour_v1.HTTPProxy{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: "simple", + Namespace: s1.Namespace, + }, + Spec: contour_v1.HTTPProxySpec{ + VirtualHost: &contour_v1.VirtualHost{ + Fqdn: "example.com", + }, + Routes: []contour_v1.Route{{ + Conditions: matchconditions(prefixMatchCondition("/")), + Services: []contour_v1.Service{{ + Name: s1.Name, + Port: 80, + }}, + }}, + }, + } + rh.OnAdd(hp1) + + httpListener := defaultHTTPListener() + httpListener.FilterChains = envoy_v3.FilterChains(envoy_v3.HTTPConnectionManagerBuilder(). + Compression("zstd"). RouteConfigName(xdscache_v3.ENVOY_HTTP_LISTENER). MetricsPrefix(xdscache_v3.ENVOY_HTTP_LISTENER). AccessLoggers(envoy_v3.FileAccessLogEnvoy(xdscache_v3.DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). diff --git a/internal/xdscache/v3/listener.go b/internal/xdscache/v3/listener.go index 94190b2f5d5..36ad156a32b 100644 --- a/internal/xdscache/v3/listener.go +++ b/internal/xdscache/v3/listener.go @@ -66,10 +66,10 @@ type ListenerConfig struct { // If not set, defaults to false. UseProxyProto bool - // DisableCompression configures listener to ignore adding compression filter as part of the defaultFilters - // Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - // If not set, defaults to false. - DisableCompression bool + // Compression configures which compression, if any, the listener uses in the compression filter as part of the defaultFilters. + // Valid values: `gzip` (default), `brotli`, `zstd`, `disabled`. + // Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + Compression contour_v1alpha1.EnvoyCompressionType // MinimumTLSVersion defines the minimum TLS protocol version the proxy should accept. MinimumTLSVersion string @@ -398,7 +398,7 @@ func (c *ListenerCache) OnChange(root *dag.DAG) { // order for the HTTPS virtualhosts. if len(listener.VirtualHosts) > 0 { cm := envoy_v3.HTTPConnectionManagerBuilder(). - DisableCompression(cfg.DisableCompression). + Compression(cfg.Compression). Codec(envoy_v3.CodecForVersions(cfg.DefaultHTTPVersions...)). DefaultFilters(). RouteConfigName(httpRouteConfigName(listener)). @@ -471,7 +471,7 @@ func (c *ListenerCache) OnChange(root *dag.DAG) { // Contour versions since the metrics prefix will be // coded into monitoring dashboards. cm := envoy_v3.HTTPConnectionManagerBuilder(). - DisableCompression(cfg.DisableCompression). + Compression(cfg.Compression). Codec(envoy_v3.CodecForVersions(cfg.DefaultHTTPVersions...)). AddFilter(envoy_v3.FilterMisdirectedRequests(vh.VirtualHost.Name)). DefaultFilters(). @@ -556,7 +556,7 @@ func (c *ListenerCache) OnChange(root *dag.DAG) { } cm := envoy_v3.HTTPConnectionManagerBuilder(). - DisableCompression(cfg.DisableCompression). + Compression(cfg.Compression). DefaultFilters(). AddFilter(authzFilter). RouteConfigName(fallbackCertRouteConfigName(listener)). diff --git a/internal/xdscache/v3/listener_test.go b/internal/xdscache/v3/listener_test.go index 1b85ab968b0..a7223d48ce3 100644 --- a/internal/xdscache/v3/listener_test.go +++ b/internal/xdscache/v3/listener_test.go @@ -3074,9 +3074,9 @@ func TestListenerVisit(t *testing.T) { SocketOptions: envoy_v3.NewSocketOptions().TCPKeepalive().Build(), }), }, - "httpproxy with DisableCompression set in listener config": { + "httpproxy with disabled compression set in listener config": { ListenerConfig: ListenerConfig{ - DisableCompression: true, + Compression: "disabled", }, objs: []any{ &contour_v1.HTTPProxy{ @@ -3106,7 +3106,175 @@ func TestListenerVisit(t *testing.T) { Address: envoy_v3.SocketAddress("0.0.0.0", 8080), FilterChains: envoy_v3.FilterChains( envoy_v3.HTTPConnectionManagerBuilder(). - DisableCompression(true). + Compression("disabled"). + RouteConfigName(ENVOY_HTTP_LISTENER). + MetricsPrefix(ENVOY_HTTP_LISTENER). + AccessLoggers(envoy_v3.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). + DefaultFilters(). + Get(), + ), + SocketOptions: envoy_v3.NewSocketOptions().TCPKeepalive().Build(), + }), + }, + "httpproxy with gzip compression set in listener config": { + ListenerConfig: ListenerConfig{ + Compression: "gzip", + }, + objs: []any{ + &contour_v1.HTTPProxy{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: "simple", + Namespace: "default", + }, + Spec: contour_v1.HTTPProxySpec{ + VirtualHost: &contour_v1.VirtualHost{ + Fqdn: "www.example.com", + }, + Routes: []contour_v1.Route{{ + Conditions: []contour_v1.MatchCondition{{ + Prefix: "/", + }}, + Services: []contour_v1.Service{{ + Name: "backend", + Port: 80, + }}, + }}, + }, + }, + service, + }, + want: listenermap(&envoy_config_listener_v3.Listener{ + Name: ENVOY_HTTP_LISTENER, + Address: envoy_v3.SocketAddress("0.0.0.0", 8080), + FilterChains: envoy_v3.FilterChains( + envoy_v3.HTTPConnectionManagerBuilder(). + Compression("gzip"). + RouteConfigName(ENVOY_HTTP_LISTENER). + MetricsPrefix(ENVOY_HTTP_LISTENER). + AccessLoggers(envoy_v3.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). + DefaultFilters(). + Get(), + ), + SocketOptions: envoy_v3.NewSocketOptions().TCPKeepalive().Build(), + }), + }, + "httpproxy with brotli compression set in listener config": { + ListenerConfig: ListenerConfig{ + Compression: "brotli", + }, + objs: []any{ + &contour_v1.HTTPProxy{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: "simple", + Namespace: "default", + }, + Spec: contour_v1.HTTPProxySpec{ + VirtualHost: &contour_v1.VirtualHost{ + Fqdn: "www.example.com", + }, + Routes: []contour_v1.Route{{ + Conditions: []contour_v1.MatchCondition{{ + Prefix: "/", + }}, + Services: []contour_v1.Service{{ + Name: "backend", + Port: 80, + }}, + }}, + }, + }, + service, + }, + want: listenermap(&envoy_config_listener_v3.Listener{ + Name: ENVOY_HTTP_LISTENER, + Address: envoy_v3.SocketAddress("0.0.0.0", 8080), + FilterChains: envoy_v3.FilterChains( + envoy_v3.HTTPConnectionManagerBuilder(). + Compression("brotli"). + RouteConfigName(ENVOY_HTTP_LISTENER). + MetricsPrefix(ENVOY_HTTP_LISTENER). + AccessLoggers(envoy_v3.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). + DefaultFilters(). + Get(), + ), + SocketOptions: envoy_v3.NewSocketOptions().TCPKeepalive().Build(), + }), + }, + "httpproxy with zstd compression set in listener config": { + ListenerConfig: ListenerConfig{ + Compression: "zstd", + }, + objs: []any{ + &contour_v1.HTTPProxy{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: "simple", + Namespace: "default", + }, + Spec: contour_v1.HTTPProxySpec{ + VirtualHost: &contour_v1.VirtualHost{ + Fqdn: "www.example.com", + }, + Routes: []contour_v1.Route{{ + Conditions: []contour_v1.MatchCondition{{ + Prefix: "/", + }}, + Services: []contour_v1.Service{{ + Name: "backend", + Port: 80, + }}, + }}, + }, + }, + service, + }, + want: listenermap(&envoy_config_listener_v3.Listener{ + Name: ENVOY_HTTP_LISTENER, + Address: envoy_v3.SocketAddress("0.0.0.0", 8080), + FilterChains: envoy_v3.FilterChains( + envoy_v3.HTTPConnectionManagerBuilder(). + Compression("zstd"). + RouteConfigName(ENVOY_HTTP_LISTENER). + MetricsPrefix(ENVOY_HTTP_LISTENER). + AccessLoggers(envoy_v3.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). + DefaultFilters(). + Get(), + ), + SocketOptions: envoy_v3.NewSocketOptions().TCPKeepalive().Build(), + }), + }, + "httpproxy with invalid compression set in listener config": { + ListenerConfig: ListenerConfig{ + Compression: "invalid value", + }, + objs: []any{ + &contour_v1.HTTPProxy{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: "simple", + Namespace: "default", + }, + Spec: contour_v1.HTTPProxySpec{ + VirtualHost: &contour_v1.VirtualHost{ + Fqdn: "www.example.com", + }, + Routes: []contour_v1.Route{{ + Conditions: []contour_v1.MatchCondition{{ + Prefix: "/", + }}, + Services: []contour_v1.Service{{ + Name: "backend", + Port: 80, + }}, + }}, + }, + }, + service, + }, + want: listenermap(&envoy_config_listener_v3.Listener{ + Name: ENVOY_HTTP_LISTENER, + Address: envoy_v3.SocketAddress("0.0.0.0", 8080), + FilterChains: envoy_v3.FilterChains( + envoy_v3.HTTPConnectionManagerBuilder(). + Compression("gzip"). RouteConfigName(ENVOY_HTTP_LISTENER). MetricsPrefix(ENVOY_HTTP_LISTENER). AccessLoggers(envoy_v3.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). diff --git a/pkg/config/parameters.go b/pkg/config/parameters.go index 211fb956a01..d349c632a4b 100644 --- a/pkg/config/parameters.go +++ b/pkg/config/parameters.go @@ -651,10 +651,11 @@ type Parameters struct { // which strips duplicate slashes from request URL paths. DisableMergeSlashes bool `yaml:"disableMergeSlashes,omitempty"` - // DisableCompression disables GZIP compression HTTP filter - // Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - // If not set, defaults to false. - DisableCompression bool `yaml:"disableCompression,omitempty"` + // Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. + // Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + // Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + // +optional + Compression EnvoyCompressionType `yaml:"compression,omitempty"` // Defines the action to be applied to the Server header on the response path. // When configured as overwrite, overwrites any Server header with "envoy". @@ -971,6 +972,19 @@ const ( LogLevelDisabled AccessLogLevel = "disabled" ) +type EnvoyCompressionType string + +func (c EnvoyCompressionType) Validate() error { + return contour_v1alpha1.EnvoyCompressionType(c).Validate() +} + +const ( + CompressionGzip EnvoyCompressionType = "gzip" + CompressionBrotli EnvoyCompressionType = "brotli" + CompressionDisabled EnvoyCompressionType = "disabled" + CompressionZstd EnvoyCompressionType = "zstd" +) + // Validate verifies that the parameter values do not have any syntax errors. func (p *Parameters) Validate() error { if err := p.Cluster.DNSLookupFamily.Validate(); err != nil { @@ -1001,6 +1015,10 @@ func (p *Parameters) Validate() error { return err } + if err := p.Compression.Validate(); err != nil { + return err + } + if err := p.TLS.Validate(); err != nil { return err } @@ -1034,6 +1052,9 @@ func (p *Parameters) Validate() error { return p.Listener.Validate() } +// DefaultCompressionFilter is the compression mechanism in the default HTTP filter chain +const DefaultCompressionFilter = CompressionGzip + // Defaults returns the default set of parameters. func Defaults() Parameters { contourNamespace := GetenvOr("CONTOUR_NAMESPACE", "projectcontour") @@ -1053,6 +1074,7 @@ func Defaults() Parameters { DisablePermitInsecure: false, DisableAllowChunkedLength: false, DisableMergeSlashes: false, + Compression: DefaultCompressionFilter, ServerHeaderTransformation: OverwriteServerHeader, Timeouts: TimeoutParameters{ // This is chosen as a rough default to stop idle connections wasting resources, diff --git a/pkg/config/parameters_test.go b/pkg/config/parameters_test.go index 7f6ad7a7dcd..5ba18a0fb7c 100644 --- a/pkg/config/parameters_test.go +++ b/pkg/config/parameters_test.go @@ -75,6 +75,7 @@ json-fields: - grpc_status - grpc_status_number accesslog-level: info +compression: gzip serverHeaderTransformation: overwrite timeouts: connection-idle-timeout: 60s diff --git a/site/content/docs/main/config/api-reference.html b/site/content/docs/main/config/api-reference.html index d6c95cdb9b3..aa21e8084c8 100644 --- a/site/content/docs/main/config/api-reference.html +++ b/site/content/docs/main/config/api-reference.html @@ -6595,6 +6595,35 @@

DeploymentSettings +

EnvoyCompressionType +(string alias)

+

+(Appears on: +EnvoyListenerConfig) +

+

+

+ + + + + + + + + + + + + + + + +
ValueDescription

"brotli"

BrotliCompression specifies brotli as the default HTTP filter chain compression mechanism

+

"disabled"

DisabledCompression specifies that there will be no compression in the default HTTP filter chain

+

"gzip"

GzipCompression specifies gzip as the default HTTP filter chain compression mechanism

+

"zstd"

ZstdCompression specifies zstd as the default HTTP filter chain compression mechanism

+

EnvoyConfig

@@ -6900,17 +6929,19 @@

EnvoyListenerConfig -disableCompression +compression
-bool + +EnvoyCompressionType + (Optional) -

DisableCompression disables GZIP compression HTTP filter from the default Listener filters -Setting this true will enable Envoy skip “Accept-Encoding: gzip,deflate” request header and always return uncompressed response -Contour’s default is false.

+

Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. +Values: gzip (default), brotli, zstd, disabled. +Setting this to disabled will make Envoy skip “Accept-Encoding: gzip,deflate” request header and always return uncompressed response

diff --git a/site/content/docs/main/configuration.md b/site/content/docs/main/configuration.md index 588ce55be29..8e2a3e168c4 100644 --- a/site/content/docs/main/configuration.md +++ b/site/content/docs/main/configuration.md @@ -72,38 +72,38 @@ The Contour configuration file is optional. In its absence, Contour will operate with reasonable defaults. Where Contour settings can also be specified with command-line flags, the command-line value takes precedence over the configuration file. -| Field Name | Type | Default | Description | -|----------------------------|------------------------|------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| accesslog-format | string | `envoy` | This key sets the global [access log format][2] for Envoy. Valid options are `envoy` or `json`. | -| accesslog-format-string | string | None | If present, this specifies custom access log format for Envoy. See [Envoy documentation](https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage) for more information about the syntax. This field only has effect if `accesslog-format` is `envoy` | -| accesslog-level | string | `info` | This field specifies the verbosity level of the access log. Valid options are `info` (default, all requests are logged), `error` (all non-success, i.e. 300+ response code, requests are logged), `critical` (all server error, i.e. 500+ response code, requests are logged) and `disabled`. | -| debug | boolean | `false` | Enables debug logging. | -| default-http-versions | string array | HTTP/1.1
HTTP/2 | This array specifies the HTTP versions that Contour should program Envoy to serve. HTTP versions are specified as strings of the form "HTTP/x", where "x" represents the version number. | -| disableAllowChunkedLength | boolean | `false` | If this field is true, Contour will disable the RFC-compliant Envoy behavior to strip the `Content-Length` header if `Transfer-Encoding: chunked` is also set. This is an emergency off-switch to revert back to Envoy's default behavior in case of failures. | -| disableCompression | boolean | `false` | This disables GZIP compression HTTP filter from the default Listener filters. Setting this true will enable Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response. | -| disableMergeSlashes | boolean | `false` | This field disables Envoy's non-standard merge_slashes path transformation behavior that strips duplicate slashes from request URL paths. | -| serverHeaderTransformation | string | `overwrite` | This field defines the action to be applied to the Server header on the response path. Values: `overwrite` (default), `append_if_absent`, `pass_through` | -| disablePermitInsecure | boolean | `false` | If this field is true, Contour will ignore `PermitInsecure` field in HTTPProxy documents. | -| envoy-service-name | string | `envoy` | This sets the service name that will be inspected for address details to be applied to Ingress objects. | -| envoy-service-namespace | string | `projectcontour` | This sets the namespace of the service that will be inspected for address details to be applied to Ingress objects. If the `CONTOUR_NAMESPACE` environment variable is present, Contour will populate this field with its value. | -| ingress-status-address | string | None | If present, this specifies the address that will be copied into the Ingress status for each Ingress that Contour manages. It is exclusive with `envoy-service-name` and `envoy-service-namespace`. | -| incluster | boolean | `false` | This field specifies that Contour is running in a Kubernetes cluster and should use the in-cluster client access configuration. | -| json-fields | string array | [fields][5] | This is the list the field names to include in the JSON [access log format][2]. This field only has effect if `accesslog-format` is `json`. | -| kubeconfig | string | `$HOME/.kube/config` | Path to a Kubernetes [kubeconfig file][3] for when Contour is executed outside a cluster. | -| kubernetesClientQPS | float32 | | QPS allowed for the Kubernetes client. | -| kubernetesClientBurst | int | | Burst allowed for the Kubernetes client. | -| policy | PolicyConfig | | The default [policy configuration](#policy-configuration). | -| tls | TLS | | The default [TLS configuration](#tls-configuration). | -| timeouts | TimeoutConfig | | The [timeout configuration](#timeout-configuration). | -| cluster | ClusterConfig | | The [cluster configuration](#cluster-configuration). | -| network | NetworkConfig | | The [network configuration](#network-configuration). | -| listener | ListenerConfig | | The [listener configuration](#listener-configuration). | -| server | ServerConfig | | The [server configuration](#server-configuration) for `contour serve` command. | -| gateway | GatewayConfig | | The [gateway-api Gateway configuration](#gateway-configuration). | -| rateLimitService | RateLimitServiceConfig | | The [rate limit service configuration](#rate-limit-service-configuration). | -| enableExternalNameService | boolean | `false` | Enable ExternalName Service processing. Enabling this has security implications. Please see the [advisory](https://github.com/projectcontour/contour/security/advisories/GHSA-5ph6-qq5x-7jwc) for more details. | -| metrics | MetricsParameters | | The [metrics configuration](#metrics-configuration) | -| featureFlags | string array | `[]` | Defines the toggle to enable new contour features. Available toggles are:
1. `useEndpointSlices` - configures contour to fetch endpoint data from k8s endpoint slices. | +| Field Name | Type | Default | Description | +|----------------------------|------------------------|------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| accesslog-format | string | `envoy` | This key sets the global [access log format][2] for Envoy. Valid options are `envoy` or `json`. | +| accesslog-format-string | string | None | If present, this specifies custom access log format for Envoy. See [Envoy documentation](https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage) for more information about the syntax. This field only has effect if `accesslog-format` is `envoy` | +| accesslog-level | string | `info` | This field specifies the verbosity level of the access log. Valid options are `info` (default, all requests are logged), `error` (all non-success, i.e. 300+ response code, requests are logged), `critical` (all server error, i.e. 500+ response code, requests are logged) and `disabled`. | +| debug | boolean | `false` | Enables debug logging. | +| default-http-versions | string array | HTTP/1.1
HTTP/2 | This array specifies the HTTP versions that Contour should program Envoy to serve. HTTP versions are specified as strings of the form "HTTP/x", where "x" represents the version number. | +| disableAllowChunkedLength | boolean | `false` | If this field is true, Contour will disable the RFC-compliant Envoy behavior to strip the `Content-Length` header if `Transfer-Encoding: chunked` is also set. This is an emergency off-switch to revert back to Envoy's default behavior in case of failures. | +| compression | string | `gzip` | Sets the compression type applied in the compression HTTP filter of the default Listener filters. Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response. Values:`gzip` (default), `brotli`, `zstd`, `disabled`. | +| disableMergeSlashes | boolean | `false` | This field disables Envoy's non-standard merge_slashes path transformation behavior that strips duplicate slashes from request URL paths. | +| serverHeaderTransformation | string | `overwrite` | This field defines the action to be applied to the Server header on the response path. Values: `overwrite` (default), `append_if_absent`, `pass_through` | +| disablePermitInsecure | boolean | `false` | If this field is true, Contour will ignore `PermitInsecure` field in HTTPProxy documents. | +| envoy-service-name | string | `envoy` | This sets the service name that will be inspected for address details to be applied to Ingress objects. | +| envoy-service-namespace | string | `projectcontour` | This sets the namespace of the service that will be inspected for address details to be applied to Ingress objects. If the `CONTOUR_NAMESPACE` environment variable is present, Contour will populate this field with its value. | +| ingress-status-address | string | None | If present, this specifies the address that will be copied into the Ingress status for each Ingress that Contour manages. It is exclusive with `envoy-service-name` and `envoy-service-namespace`. | +| incluster | boolean | `false` | This field specifies that Contour is running in a Kubernetes cluster and should use the in-cluster client access configuration. | +| json-fields | string array | [fields][5] | This is the list the field names to include in the JSON [access log format][2]. This field only has effect if `accesslog-format` is `json`. | +| kubeconfig | string | `$HOME/.kube/config` | Path to a Kubernetes [kubeconfig file][3] for when Contour is executed outside a cluster. | +| kubernetesClientQPS | float32 | | QPS allowed for the Kubernetes client. | +| kubernetesClientBurst | int | | Burst allowed for the Kubernetes client. | +| policy | PolicyConfig | | The default [policy configuration](#policy-configuration). | +| tls | TLS | | The default [TLS configuration](#tls-configuration). | +| timeouts | TimeoutConfig | | The [timeout configuration](#timeout-configuration). | +| cluster | ClusterConfig | | The [cluster configuration](#cluster-configuration). | +| network | NetworkConfig | | The [network configuration](#network-configuration). | +| listener | ListenerConfig | | The [listener configuration](#listener-configuration). | +| server | ServerConfig | | The [server configuration](#server-configuration) for `contour serve` command. | +| gateway | GatewayConfig | | The [gateway-api Gateway configuration](#gateway-configuration). | +| rateLimitService | RateLimitServiceConfig | | The [rate limit service configuration](#rate-limit-service-configuration). | +| enableExternalNameService | boolean | `false` | Enable ExternalName Service processing. Enabling this has security implications. Please see the [advisory](https://github.com/projectcontour/contour/security/advisories/GHSA-5ph6-qq5x-7jwc) for more details. | +| metrics | MetricsParameters | | The [metrics configuration](#metrics-configuration) | +| featureFlags | string array | `[]` | Defines the toggle to enable new contour features. Available toggles are:
1. `useEndpointSlices` - configures contour to fetch endpoint data from k8s endpoint slices. | ### TLS Configuration diff --git a/test/e2e/deployment.go b/test/e2e/deployment.go index 6fc95eec9a5..4128f0d524b 100644 --- a/test/e2e/deployment.go +++ b/test/e2e/deployment.go @@ -490,7 +490,7 @@ func (d *Deployment) EnsureResourcesForLocalContour() error { return err } - session.Wait("2s") + session.Wait("3s") bootstrapContents, err := io.ReadAll(bFile) if err != nil { return err diff --git a/test/e2e/fixtures.go b/test/e2e/fixtures.go index 4cc20831bf6..6d819bc1174 100644 --- a/test/e2e/fixtures.go +++ b/test/e2e/fixtures.go @@ -583,6 +583,7 @@ func DefaultContourConfiguration() *contour_v1alpha1.ContourConfiguration { }, Listener: &contour_v1alpha1.EnvoyListenerConfig{ UseProxyProto: ptr.To(false), + Compression: "gzip", DisableAllowChunkedLength: ptr.To(false), ConnectionBalancer: "", TLS: &contour_v1alpha1.EnvoyTLS{ diff --git a/test/e2e/httpproxy/envoy_compression_test.go b/test/e2e/httpproxy/envoy_compression_test.go index 9fd81366f4c..5b069af8470 100644 --- a/test/e2e/httpproxy/envoy_compression_test.go +++ b/test/e2e/httpproxy/envoy_compression_test.go @@ -18,8 +18,10 @@ package httpproxy import ( "fmt" "net/http" + "time" . "github.com/onsi/ginkgo/v2" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -27,12 +29,13 @@ import ( "github.com/projectcontour/contour/test/e2e" ) -func testEnvoyDisableCompression(namespace string, enabled bool) { - testSpec := "responses compressed with default settings" - if enabled { +func testEnvoyDisableCompression(namespace, acceptEncoding, contentEncoding string, disabled bool) { + testSpec := fmt.Sprintf("responses compressed with accept-encoding %s expecting content-encoding %s", acceptEncoding, contentEncoding) + if disabled { testSpec = "responses are plaintext when compression disabled" } - FSpecify(testSpec, func() { + + Specify(testSpec, func() { resp := "minimum_text_to_enable_gzipminimum_text_to_enable_gzipminimum_text_to_enable_gzipminimum_text_to_enable_gzipminimum_text_to_enable_gzipminimum_text_to_enable_gzip" p := &contour_v1.HTTPProxy{ ObjectMeta: meta_v1.ObjectMeta{ @@ -57,24 +60,25 @@ func testEnvoyDisableCompression(namespace string, enabled bool) { } require.True(f.T(), f.CreateHTTPProxyAndWaitFor(p, e2e.HTTPProxyValid)) - // Send HTTP request, we will check backend connection was over HTTPS. - res, ok := f.HTTP.RequestUntil(&e2e.HTTPRequestOpts{ - Path: "/directresponse", - Host: p.Spec.VirtualHost.Fqdn, - RequestOpts: []func(*http.Request){ - e2e.OptSetHeaders(map[string]string{ - "Accept-Encoding": "gzip, deflate", - }), - }, - Condition: e2e.HasStatusCode(200), - }) - require.NotNil(f.T(), res, "request never succeeded") - require.Truef(f.T(), ok, "expected 200 response code, got %d", res.StatusCode) - fmt.Printf("response: %+v\n", res.Headers) - if enabled { - require.NotContains(f.T(), res.Headers["Content-Encoding"], "gzip", "expected plain text") - return - } - require.Contains(f.T(), res.Headers["Content-Encoding"], "gzip", "expected plain text") + require.EventuallyWithT(f.T(), func(c *assert.CollectT) { + res, ok := f.HTTP.RequestUntil(&e2e.HTTPRequestOpts{ + Path: "/directresponse", + Host: p.Spec.VirtualHost.Fqdn, + RequestOpts: []func(*http.Request){ + e2e.OptSetHeaders(map[string]string{ + "Accept-Encoding": fmt.Sprintf("%s, deflate", acceptEncoding), + }), + }, + Condition: e2e.HasStatusCode(200), + }) + assert.NotNil(c, res, "request never succeeded") + assert.Truef(c, ok, "expected 200 response code, got %d", res.StatusCode) + contentEncodingHeaderValue := res.Headers.Get("Content-Encoding") + if disabled { + assert.NotEqual(c, contentEncodingHeaderValue, contentEncoding, "expected plain text") + return + } + assert.Equal(c, contentEncodingHeaderValue, contentEncoding, "expected plain text") + }, 15*time.Second, f.RetryInterval) }) } diff --git a/test/e2e/httpproxy/httpproxy_test.go b/test/e2e/httpproxy/httpproxy_test.go index 42edb73bd9c..c8e85cef70e 100644 --- a/test/e2e/httpproxy/httpproxy_test.go +++ b/test/e2e/httpproxy/httpproxy_test.go @@ -389,15 +389,36 @@ var _ = Describe("HTTPProxy", func() { }) f.NamespacedTest("httpproxy-default-compression", func(namespace string) { - testEnvoyDisableCompression(namespace, false) + testEnvoyDisableCompression(namespace, "gzip", "gzip", false) }) f.NamespacedTest("httpproxy-disable-compression", func(namespace string) { Context("with compression disabled", func() { BeforeEach(func() { - contourConfig.DisableCompression = true + contourConfig.Compression = "disabled" + contourConfiguration.Spec.Envoy.Listener.Compression = "disabled" }) - testEnvoyDisableCompression(namespace, true) + testEnvoyDisableCompression(namespace, "gzip", "gzip", true) + }) + }) + + f.NamespacedTest("httpproxy-brotli-compression", func(namespace string) { + Context("with brotli compression", func() { + BeforeEach(func() { + contourConfig.Compression = "brotli" + contourConfiguration.Spec.Envoy.Listener.Compression = "brotli" + }) + testEnvoyDisableCompression(namespace, "br", "br", false) + }) + }) + + f.NamespacedTest("httpproxy-zstd-compression", func(namespace string) { + Context("with zstd compression", func() { + BeforeEach(func() { + contourConfig.Compression = "zstd" + contourConfiguration.Spec.Envoy.Listener.Compression = "zstd" + }) + testEnvoyDisableCompression(namespace, "zstd", "zstd", false) }) }) From f7b261b22d9a6ddb2e5d3e0f8991ab6b3d0fc69b Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Sat, 19 Oct 2024 12:41:10 +0100 Subject: [PATCH 12/30] add validation to crd compression field Signed-off-by: Geoff Macartney --- apis/projectcontour/v1alpha1/contourconfig.go | 1 + examples/contour/01-crds.yaml | 10 ++++++++++ examples/render/contour-deployment.yaml | 10 ++++++++++ examples/render/contour-gateway-provisioner.yaml | 10 ++++++++++ examples/render/contour-gateway.yaml | 10 ++++++++++ examples/render/contour.yaml | 10 ++++++++++ 6 files changed, 51 insertions(+) diff --git a/apis/projectcontour/v1alpha1/contourconfig.go b/apis/projectcontour/v1alpha1/contourconfig.go index d96ff51691b..b4145b41edc 100644 --- a/apis/projectcontour/v1alpha1/contourconfig.go +++ b/apis/projectcontour/v1alpha1/contourconfig.go @@ -351,6 +351,7 @@ type EnvoyListenerConfig struct { // Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. // Values: `gzip` (default), `brotli`, `zstd`, `disabled`. // Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + // +kubebuilder:validation:Enum="gzip";"brotli";"zstd";"disabled" // +optional Compression EnvoyCompressionType `json:"compression,omitempty"` diff --git a/examples/contour/01-crds.yaml b/examples/contour/01-crds.yaml index 911f670200e..808b7eba36b 100644 --- a/examples/contour/01-crds.yaml +++ b/examples/contour/01-crds.yaml @@ -286,6 +286,11 @@ spec: Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. Values: `gzip` (default), `brotli`, `zstd`, `disabled`. Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + enum: + - gzip + - brotli + - zstd + - disabled type: string connectionBalancer: description: |- @@ -4074,6 +4079,11 @@ spec: Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. Values: `gzip` (default), `brotli`, `zstd`, `disabled`. Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + enum: + - gzip + - brotli + - zstd + - disabled type: string connectionBalancer: description: |- diff --git a/examples/render/contour-deployment.yaml b/examples/render/contour-deployment.yaml index 08de1688e9a..1b453c8f9a4 100644 --- a/examples/render/contour-deployment.yaml +++ b/examples/render/contour-deployment.yaml @@ -506,6 +506,11 @@ spec: Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. Values: `gzip` (default), `brotli`, `zstd`, `disabled`. Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + enum: + - gzip + - brotli + - zstd + - disabled type: string connectionBalancer: description: |- @@ -4294,6 +4299,11 @@ spec: Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. Values: `gzip` (default), `brotli`, `zstd`, `disabled`. Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + enum: + - gzip + - brotli + - zstd + - disabled type: string connectionBalancer: description: |- diff --git a/examples/render/contour-gateway-provisioner.yaml b/examples/render/contour-gateway-provisioner.yaml index 9302324f810..efec845de1f 100644 --- a/examples/render/contour-gateway-provisioner.yaml +++ b/examples/render/contour-gateway-provisioner.yaml @@ -297,6 +297,11 @@ spec: Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. Values: `gzip` (default), `brotli`, `zstd`, `disabled`. Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + enum: + - gzip + - brotli + - zstd + - disabled type: string connectionBalancer: description: |- @@ -4085,6 +4090,11 @@ spec: Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. Values: `gzip` (default), `brotli`, `zstd`, `disabled`. Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + enum: + - gzip + - brotli + - zstd + - disabled type: string connectionBalancer: description: |- diff --git a/examples/render/contour-gateway.yaml b/examples/render/contour-gateway.yaml index a993637fc75..b462381a9cd 100644 --- a/examples/render/contour-gateway.yaml +++ b/examples/render/contour-gateway.yaml @@ -322,6 +322,11 @@ spec: Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. Values: `gzip` (default), `brotli`, `zstd`, `disabled`. Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + enum: + - gzip + - brotli + - zstd + - disabled type: string connectionBalancer: description: |- @@ -4110,6 +4115,11 @@ spec: Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. Values: `gzip` (default), `brotli`, `zstd`, `disabled`. Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + enum: + - gzip + - brotli + - zstd + - disabled type: string connectionBalancer: description: |- diff --git a/examples/render/contour.yaml b/examples/render/contour.yaml index ffd55e0337d..b09b87cdeff 100644 --- a/examples/render/contour.yaml +++ b/examples/render/contour.yaml @@ -506,6 +506,11 @@ spec: Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. Values: `gzip` (default), `brotli`, `zstd`, `disabled`. Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + enum: + - gzip + - brotli + - zstd + - disabled type: string connectionBalancer: description: |- @@ -4294,6 +4299,11 @@ spec: Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. Values: `gzip` (default), `brotli`, `zstd`, `disabled`. Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + enum: + - gzip + - brotli + - zstd + - disabled type: string connectionBalancer: description: |- From b68f0b1dd9e7d8cfdf58c9b91719a7b65878954d Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Sat, 19 Oct 2024 12:41:31 +0100 Subject: [PATCH 13/30] delete unnecessary output log Signed-off-by: Geoff Macartney --- cmd/contour/serve.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmd/contour/serve.go b/cmd/contour/serve.go index b361a56d2b1..b2414214c03 100644 --- a/cmd/contour/serve.go +++ b/cmd/contour/serve.go @@ -473,8 +473,6 @@ func (s *Server) doServe() error { SocketOptions: contourConfiguration.Envoy.Listener.SocketOptions, } - s.log.WithField("context", "listenerConfig").Infof("compression setting: %s", listenerConfig.Compression) - if listenerConfig.TracingConfig, err = s.setupTracingService(contourConfiguration.Tracing); err != nil { return err } From 5dcdc33aeb0d1b27c24527e34734857ea2583612 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Mon, 21 Oct 2024 15:11:22 +0100 Subject: [PATCH 14/30] define compression with a struct for API extensibility Signed-off-by: Geoff Macartney --- apis/projectcontour/v1alpha1/compression.go | 28 +++++-- .../v1alpha1/compression_test.go | 6 +- apis/projectcontour/v1alpha1/contourconfig.go | 7 +- changelogs/unreleased/6546-chaosbox-small.md | 2 +- cmd/contour/serve.go | 9 ++- cmd/contour/servecontext.go | 26 ++++--- cmd/contour/servecontext_test.go | 3 - examples/contour/01-crds.yaml | 50 +++++++----- examples/render/contour-deployment.yaml | 50 +++++++----- .../render/contour-gateway-provisioner.yaml | 50 +++++++----- examples/render/contour-gateway.yaml | 50 +++++++----- examples/render/contour.yaml | 50 +++++++----- .../contourconfig/contourconfiguration.go | 1 - .../contourconfiguration_test.go | 6 +- internal/envoy/v3/listener.go | 38 ++++----- internal/featuretests/v3/compression_test.go | 24 ++++-- internal/xdscache/v3/listener.go | 6 +- internal/xdscache/v3/listener_test.go | 40 +++++++--- pkg/config/parameters.go | 39 ++++++---- .../docs/main/config/api-reference.html | 77 ++++++++++++++----- test/e2e/fixtures.go | 1 - test/e2e/httpproxy/httpproxy_test.go | 24 ++++-- 22 files changed, 375 insertions(+), 212 deletions(-) diff --git a/apis/projectcontour/v1alpha1/compression.go b/apis/projectcontour/v1alpha1/compression.go index 9c850934eda..3ae14097acf 100644 --- a/apis/projectcontour/v1alpha1/compression.go +++ b/apis/projectcontour/v1alpha1/compression.go @@ -15,27 +15,39 @@ package v1alpha1 import "fmt" -type EnvoyCompressionType string +// CompressionAlgorithm defines the type of compression algorithm applied in default HTTP listener filter chain. +// Allowable values are defined as names of well known compression algorithms (plus "disabled"). +type CompressionAlgorithm string + +// EnvoyCompression defines configuration related to compression in the default HTTP Listener filter chain. +type EnvoyCompression struct { + // Algorithm selects the compression type applied in the compression HTTP filter of the default Listener filters. + // Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + // Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + // +kubebuilder:validation:Enum="gzip";"brotli";"zstd";"disabled" + // +optional + Algorithm CompressionAlgorithm `json:"algorithm,omitempty"` +} -func (c EnvoyCompressionType) Validate() error { - switch c { +func (a CompressionAlgorithm) Validate() error { + switch a { case BrotliCompression, DisabledCompression, GzipCompression, ZstdCompression: return nil default: - return fmt.Errorf("invalid compression type: %q", c) + return fmt.Errorf("invalid compression type: %q", a) } } const ( // BrotliCompression specifies brotli as the default HTTP filter chain compression mechanism - BrotliCompression EnvoyCompressionType = "brotli" + BrotliCompression CompressionAlgorithm = "brotli" // DisabledCompression specifies that there will be no compression in the default HTTP filter chain - DisabledCompression EnvoyCompressionType = "disabled" + DisabledCompression CompressionAlgorithm = "disabled" // GzipCompression specifies gzip as the default HTTP filter chain compression mechanism - GzipCompression EnvoyCompressionType = "gzip" + GzipCompression CompressionAlgorithm = "gzip" // ZstdCompression specifies zstd as the default HTTP filter chain compression mechanism - ZstdCompression EnvoyCompressionType = "zstd" + ZstdCompression CompressionAlgorithm = "zstd" ) diff --git a/apis/projectcontour/v1alpha1/compression_test.go b/apis/projectcontour/v1alpha1/compression_test.go index d90ad832aa4..0251c4d97eb 100644 --- a/apis/projectcontour/v1alpha1/compression_test.go +++ b/apis/projectcontour/v1alpha1/compression_test.go @@ -21,9 +21,9 @@ import ( contour_v1alpha1 "github.com/projectcontour/contour/apis/projectcontour/v1alpha1" ) -func TestValidateEnvoyCompressionType(t *testing.T) { - require.Error(t, contour_v1alpha1.EnvoyCompressionType("").Validate()) - require.Error(t, contour_v1alpha1.EnvoyCompressionType("foo").Validate()) +func TestValidateEnvoyCompressionAlgorithmType(t *testing.T) { + require.Error(t, contour_v1alpha1.CompressionAlgorithm("").Validate()) + require.Error(t, contour_v1alpha1.CompressionAlgorithm("foo").Validate()) require.NoError(t, contour_v1alpha1.BrotliCompression.Validate()) require.NoError(t, contour_v1alpha1.DisabledCompression.Validate()) diff --git a/apis/projectcontour/v1alpha1/contourconfig.go b/apis/projectcontour/v1alpha1/contourconfig.go index b4145b41edc..fcc6b38638c 100644 --- a/apis/projectcontour/v1alpha1/contourconfig.go +++ b/apis/projectcontour/v1alpha1/contourconfig.go @@ -348,12 +348,9 @@ type EnvoyListenerConfig struct { // +optional UseProxyProto *bool `json:"useProxyProtocol,omitempty"` - // Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. - // Values: `gzip` (default), `brotli`, `zstd`, `disabled`. - // Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - // +kubebuilder:validation:Enum="gzip";"brotli";"zstd";"disabled" + // Compression defines configuration related to compression in the default HTTP Listener filters. // +optional - Compression EnvoyCompressionType `json:"compression,omitempty"` + Compression *EnvoyCompression `json:"compression,omitempty"` // DisableAllowChunkedLength disables the RFC-compliant Envoy behavior to // strip the "Content-Length" header if "Transfer-Encoding: chunked" is diff --git a/changelogs/unreleased/6546-chaosbox-small.md b/changelogs/unreleased/6546-chaosbox-small.md index 5f156b7289d..6017d1b0588 100644 --- a/changelogs/unreleased/6546-chaosbox-small.md +++ b/changelogs/unreleased/6546-chaosbox-small.md @@ -1 +1 @@ -Add "compression" flag to set/disable the compression type applied in the default HTTP filter chain. +Add "compression" object to define settings in default HTTP filters, initially just supporting changing/disabling compression algorithm. diff --git a/cmd/contour/serve.go b/cmd/contour/serve.go index b2414214c03..8a4801bd137 100644 --- a/cmd/contour/serve.go +++ b/cmd/contour/serve.go @@ -123,9 +123,16 @@ func registerServe(app *kingpin.Application) (*kingpin.CmdClause, *serveContext) return nil } + + if ctx.Config.Compression == nil { + ctx.Config.Compression = &config.CompressionParameters{ + Algorithm: config.CompressionDefault, + } + } + serve.Flag("accesslog-format", "Format for Envoy access logs.").PlaceHolder("").StringVar((*string)(&ctx.Config.AccessLogFormat)) - serve.Flag("compression", "Set or disable compression type in default Listener filters.").PlaceHolder("").StringVar((*string)(&ctx.Config.Compression)) + serve.Flag("compression", "Set or disable compression type in default Listener filters.").PlaceHolder("").StringVar((*string)(&ctx.Config.Compression.Algorithm)) serve.Flag("config-path", "Path to base configuration.").Short('c').PlaceHolder("/path/to/file").Action(parseConfig).ExistingFileVar(&configFile) serve.Flag("contour-cafile", "CA bundle file name for serving gRPC with TLS.").Envar("CONTOUR_CAFILE").StringVar(&ctx.caFile) serve.Flag("contour-cert-file", "Contour certificate file name for serving gRPC over TLS.").PlaceHolder("/path/to/file").Envar("CONTOUR_CERT_FILE").StringVar(&ctx.contourCert) diff --git a/cmd/contour/servecontext.go b/cmd/contour/servecontext.go index 37d0936e18f..3bf62e9a541 100644 --- a/cmd/contour/servecontext.go +++ b/cmd/contour/servecontext.go @@ -333,16 +333,22 @@ func (ctx *serveContext) convertToContourConfigurationSpec() contour_v1alpha1.Co accessLogLevel = contour_v1alpha1.LogLevelDisabled } - var compression contour_v1alpha1.EnvoyCompressionType - switch ctx.Config.Compression { - case config.CompressionBrotli: - compression = contour_v1alpha1.BrotliCompression - case config.CompressionDisabled: - compression = contour_v1alpha1.DisabledCompression - case config.CompressionGzip: - compression = contour_v1alpha1.GzipCompression - case config.CompressionZstd: - compression = contour_v1alpha1.ZstdCompression + var compression *contour_v1alpha1.EnvoyCompression + if ctx.Config.Compression != nil { + var algorithm contour_v1alpha1.CompressionAlgorithm + switch ctx.Config.Compression.Algorithm { + case config.CompressionBrotli: + algorithm = contour_v1alpha1.BrotliCompression + case config.CompressionDisabled: + algorithm = contour_v1alpha1.DisabledCompression + case config.CompressionGzip: + algorithm = contour_v1alpha1.GzipCompression + case config.CompressionZstd: + algorithm = contour_v1alpha1.ZstdCompression + } + compression = &contour_v1alpha1.EnvoyCompression{ + Algorithm: algorithm, + } } var defaultHTTPVersions []contour_v1alpha1.HTTPVersionType diff --git a/cmd/contour/servecontext_test.go b/cmd/contour/servecontext_test.go index 5f946f18e6a..cf205d81a46 100644 --- a/cmd/contour/servecontext_test.go +++ b/cmd/contour/servecontext_test.go @@ -408,7 +408,6 @@ func TestConvertServeContext(t *testing.T) { }, Listener: &contour_v1alpha1.EnvoyListenerConfig{ UseProxyProto: ptr.To(false), - Compression: "gzip", DisableAllowChunkedLength: ptr.To(false), DisableMergeSlashes: ptr.To(false), ServerHeaderTransformation: contour_v1alpha1.OverwriteServerHeader, @@ -893,14 +892,12 @@ func TestConvertServeContext(t *testing.T) { ctx.Config.Listener.MaxRequestsPerIOCycle = ptr.To(uint32(10)) ctx.Config.Listener.HTTP2MaxConcurrentStreams = ptr.To(uint32(30)) ctx.Config.Listener.MaxConnectionsPerListener = ptr.To(uint32(50)) - ctx.Config.Compression = "gzip" return ctx }, getContourConfiguration: func(cfg contour_v1alpha1.ContourConfigurationSpec) contour_v1alpha1.ContourConfigurationSpec { cfg.Envoy.Listener.MaxRequestsPerIOCycle = ptr.To(uint32(10)) cfg.Envoy.Listener.HTTP2MaxConcurrentStreams = ptr.To(uint32(30)) cfg.Envoy.Listener.MaxConnectionsPerListener = ptr.To(uint32(50)) - cfg.Envoy.Listener.Compression = "gzip" return cfg }, }, diff --git a/examples/contour/01-crds.yaml b/examples/contour/01-crds.yaml index 808b7eba36b..48601e397a0 100644 --- a/examples/contour/01-crds.yaml +++ b/examples/contour/01-crds.yaml @@ -282,16 +282,21 @@ spec: values. properties: compression: - description: |- - Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. - Values: `gzip` (default), `brotli`, `zstd`, `disabled`. - Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - enum: - - gzip - - brotli - - zstd - - disabled - type: string + description: Compression defines configuration related to + compression in the default HTTP Listener filters. + properties: + algorithm: + description: |- + Algorithm selects the compression type applied in the compression HTTP filter of the default Listener filters. + Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + enum: + - gzip + - brotli + - zstd + - disabled + type: string + type: object connectionBalancer: description: |- ConnectionBalancer. If the value is exact, the listener will use the exact connection balancer @@ -4075,16 +4080,21 @@ spec: values. properties: compression: - description: |- - Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. - Values: `gzip` (default), `brotli`, `zstd`, `disabled`. - Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - enum: - - gzip - - brotli - - zstd - - disabled - type: string + description: Compression defines configuration related + to compression in the default HTTP Listener filters. + properties: + algorithm: + description: |- + Algorithm selects the compression type applied in the compression HTTP filter of the default Listener filters. + Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + enum: + - gzip + - brotli + - zstd + - disabled + type: string + type: object connectionBalancer: description: |- ConnectionBalancer. If the value is exact, the listener will use the exact connection balancer diff --git a/examples/render/contour-deployment.yaml b/examples/render/contour-deployment.yaml index 1b453c8f9a4..51aeaa1a389 100644 --- a/examples/render/contour-deployment.yaml +++ b/examples/render/contour-deployment.yaml @@ -502,16 +502,21 @@ spec: values. properties: compression: - description: |- - Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. - Values: `gzip` (default), `brotli`, `zstd`, `disabled`. - Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - enum: - - gzip - - brotli - - zstd - - disabled - type: string + description: Compression defines configuration related to + compression in the default HTTP Listener filters. + properties: + algorithm: + description: |- + Algorithm selects the compression type applied in the compression HTTP filter of the default Listener filters. + Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + enum: + - gzip + - brotli + - zstd + - disabled + type: string + type: object connectionBalancer: description: |- ConnectionBalancer. If the value is exact, the listener will use the exact connection balancer @@ -4295,16 +4300,21 @@ spec: values. properties: compression: - description: |- - Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. - Values: `gzip` (default), `brotli`, `zstd`, `disabled`. - Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - enum: - - gzip - - brotli - - zstd - - disabled - type: string + description: Compression defines configuration related + to compression in the default HTTP Listener filters. + properties: + algorithm: + description: |- + Algorithm selects the compression type applied in the compression HTTP filter of the default Listener filters. + Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + enum: + - gzip + - brotli + - zstd + - disabled + type: string + type: object connectionBalancer: description: |- ConnectionBalancer. If the value is exact, the listener will use the exact connection balancer diff --git a/examples/render/contour-gateway-provisioner.yaml b/examples/render/contour-gateway-provisioner.yaml index efec845de1f..7ea0dc3c500 100644 --- a/examples/render/contour-gateway-provisioner.yaml +++ b/examples/render/contour-gateway-provisioner.yaml @@ -293,16 +293,21 @@ spec: values. properties: compression: - description: |- - Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. - Values: `gzip` (default), `brotli`, `zstd`, `disabled`. - Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - enum: - - gzip - - brotli - - zstd - - disabled - type: string + description: Compression defines configuration related to + compression in the default HTTP Listener filters. + properties: + algorithm: + description: |- + Algorithm selects the compression type applied in the compression HTTP filter of the default Listener filters. + Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + enum: + - gzip + - brotli + - zstd + - disabled + type: string + type: object connectionBalancer: description: |- ConnectionBalancer. If the value is exact, the listener will use the exact connection balancer @@ -4086,16 +4091,21 @@ spec: values. properties: compression: - description: |- - Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. - Values: `gzip` (default), `brotli`, `zstd`, `disabled`. - Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - enum: - - gzip - - brotli - - zstd - - disabled - type: string + description: Compression defines configuration related + to compression in the default HTTP Listener filters. + properties: + algorithm: + description: |- + Algorithm selects the compression type applied in the compression HTTP filter of the default Listener filters. + Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + enum: + - gzip + - brotli + - zstd + - disabled + type: string + type: object connectionBalancer: description: |- ConnectionBalancer. If the value is exact, the listener will use the exact connection balancer diff --git a/examples/render/contour-gateway.yaml b/examples/render/contour-gateway.yaml index b462381a9cd..e7981bf7f37 100644 --- a/examples/render/contour-gateway.yaml +++ b/examples/render/contour-gateway.yaml @@ -318,16 +318,21 @@ spec: values. properties: compression: - description: |- - Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. - Values: `gzip` (default), `brotli`, `zstd`, `disabled`. - Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - enum: - - gzip - - brotli - - zstd - - disabled - type: string + description: Compression defines configuration related to + compression in the default HTTP Listener filters. + properties: + algorithm: + description: |- + Algorithm selects the compression type applied in the compression HTTP filter of the default Listener filters. + Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + enum: + - gzip + - brotli + - zstd + - disabled + type: string + type: object connectionBalancer: description: |- ConnectionBalancer. If the value is exact, the listener will use the exact connection balancer @@ -4111,16 +4116,21 @@ spec: values. properties: compression: - description: |- - Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. - Values: `gzip` (default), `brotli`, `zstd`, `disabled`. - Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - enum: - - gzip - - brotli - - zstd - - disabled - type: string + description: Compression defines configuration related + to compression in the default HTTP Listener filters. + properties: + algorithm: + description: |- + Algorithm selects the compression type applied in the compression HTTP filter of the default Listener filters. + Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + enum: + - gzip + - brotli + - zstd + - disabled + type: string + type: object connectionBalancer: description: |- ConnectionBalancer. If the value is exact, the listener will use the exact connection balancer diff --git a/examples/render/contour.yaml b/examples/render/contour.yaml index b09b87cdeff..c1b7b931224 100644 --- a/examples/render/contour.yaml +++ b/examples/render/contour.yaml @@ -502,16 +502,21 @@ spec: values. properties: compression: - description: |- - Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. - Values: `gzip` (default), `brotli`, `zstd`, `disabled`. - Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - enum: - - gzip - - brotli - - zstd - - disabled - type: string + description: Compression defines configuration related to + compression in the default HTTP Listener filters. + properties: + algorithm: + description: |- + Algorithm selects the compression type applied in the compression HTTP filter of the default Listener filters. + Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + enum: + - gzip + - brotli + - zstd + - disabled + type: string + type: object connectionBalancer: description: |- ConnectionBalancer. If the value is exact, the listener will use the exact connection balancer @@ -4295,16 +4300,21 @@ spec: values. properties: compression: - description: |- - Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. - Values: `gzip` (default), `brotli`, `zstd`, `disabled`. - Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - enum: - - gzip - - brotli - - zstd - - disabled - type: string + description: Compression defines configuration related + to compression in the default HTTP Listener filters. + properties: + algorithm: + description: |- + Algorithm selects the compression type applied in the compression HTTP filter of the default Listener filters. + Values: `gzip` (default), `brotli`, `zstd`, `disabled`. + Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + enum: + - gzip + - brotli + - zstd + - disabled + type: string + type: object connectionBalancer: description: |- ConnectionBalancer. If the value is exact, the listener will use the exact connection balancer diff --git a/internal/contourconfig/contourconfiguration.go b/internal/contourconfig/contourconfiguration.go index 9dbaf7e1d40..0c369f170cb 100644 --- a/internal/contourconfig/contourconfiguration.go +++ b/internal/contourconfig/contourconfiguration.go @@ -66,7 +66,6 @@ func Defaults() contour_v1alpha1.ContourConfigurationSpec { Envoy: &contour_v1alpha1.EnvoyConfig{ Listener: &contour_v1alpha1.EnvoyListenerConfig{ UseProxyProto: ptr.To(false), - Compression: contour_v1alpha1.GzipCompression, DisableAllowChunkedLength: ptr.To(false), DisableMergeSlashes: ptr.To(false), ServerHeaderTransformation: contour_v1alpha1.OverwriteServerHeader, diff --git a/internal/contourconfig/contourconfiguration_test.go b/internal/contourconfig/contourconfiguration_test.go index 7ee574985cd..294e6a4609b 100644 --- a/internal/contourconfig/contourconfiguration_test.go +++ b/internal/contourconfig/contourconfiguration_test.go @@ -54,8 +54,10 @@ func TestOverlayOnDefaults(t *testing.T) { }, Envoy: &contour_v1alpha1.EnvoyConfig{ Listener: &contour_v1alpha1.EnvoyListenerConfig{ - UseProxyProto: ptr.To(true), - Compression: "brotli", + UseProxyProto: ptr.To(true), + Compression: &contour_v1alpha1.EnvoyCompression{ + Algorithm: contour_v1alpha1.BrotliCompression, + }, MaxRequestsPerConnection: ptr.To(uint32(1)), HTTP2MaxConcurrentStreams: ptr.To(uint32(10)), DisableAllowChunkedLength: ptr.To(true), diff --git a/internal/envoy/v3/listener.go b/internal/envoy/v3/listener.go index 63d71d77340..59dcc233a67 100644 --- a/internal/envoy/v3/listener.go +++ b/internal/envoy/v3/listener.go @@ -16,6 +16,8 @@ package v3 import ( "errors" "fmt" + envoy_compression_brotli_compressor_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/compression/brotli/compressor/v3" + envoy_compression_zstd_compressor_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/compression/zstd/compressor/v3" "sort" "strings" "time" @@ -23,9 +25,7 @@ import ( envoy_config_accesslog_v3 "github.com/envoyproxy/go-control-plane/envoy/config/accesslog/v3" envoy_config_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" envoy_config_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" - envoy_compression_brotli_compressor_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/compression/brotli/compressor/v3" envoy_compression_gzip_compressor_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/compression/gzip/compressor/v3" - envoy_compression_zstd_compressor_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/compression/zstd/compressor/v3" envoy_filter_http_compressor_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/compressor/v3" envoy_filter_http_cors_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/cors/v3" envoy_filter_http_ext_authz_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/ext_authz/v3" @@ -191,7 +191,7 @@ type httpConnectionManagerBuilder struct { maxRequestsPerConnection *uint32 http2MaxConcurrentStreams *uint32 enableWebsockets bool - compression contour_v1alpha1.EnvoyCompressionType + compression *contour_v1alpha1.EnvoyCompression } func (b *httpConnectionManagerBuilder) EnableWebsockets(enable bool) *httpConnectionManagerBuilder { @@ -275,7 +275,7 @@ func (b *httpConnectionManagerBuilder) MergeSlashes(enabled bool) *httpConnectio return b } -func (b *httpConnectionManagerBuilder) Compression(compressor contour_v1alpha1.EnvoyCompressionType) *httpConnectionManagerBuilder { +func (b *httpConnectionManagerBuilder) Compression(compressor *contour_v1alpha1.EnvoyCompression) *httpConnectionManagerBuilder { b.compression = compressor return b } @@ -317,20 +317,22 @@ func (b *httpConnectionManagerBuilder) DefaultFilters() *httpConnectionManagerBu // Add a default set of ordered http filters. // The names are not required to match anything and are // identified by the TypeURL of each filter. - var compressor proto.Message - compressorName := "" - switch b.compression { - case contour_v1alpha1.BrotliCompression: - compressorName = "brotli" - compressor = &envoy_compression_brotli_compressor_v3.Brotli{} - case contour_v1alpha1.DisabledCompression: - compressor = nil - case contour_v1alpha1.ZstdCompression: - compressorName = "zstd" - compressor = &envoy_compression_zstd_compressor_v3.Zstd{} - default: - compressorName = "gzip" - compressor = &envoy_compression_gzip_compressor_v3.Gzip{} + var compressor proto.Message = &envoy_compression_gzip_compressor_v3.Gzip{} + var compressorName = string(contour_v1alpha1.GzipCompression) + if b.compression != nil { + switch b.compression.Algorithm { + case contour_v1alpha1.BrotliCompression: + compressorName = "brotli" + compressor = &envoy_compression_brotli_compressor_v3.Brotli{} + case contour_v1alpha1.DisabledCompression: + compressor = nil + case contour_v1alpha1.ZstdCompression: + compressorName = "zstd" + compressor = &envoy_compression_zstd_compressor_v3.Zstd{} + default: + compressorName = "gzip" + compressor = &envoy_compression_gzip_compressor_v3.Gzip{} + } } if compressor != nil { diff --git a/internal/featuretests/v3/compression_test.go b/internal/featuretests/v3/compression_test.go index a0c941438c8..0535242c487 100644 --- a/internal/featuretests/v3/compression_test.go +++ b/internal/featuretests/v3/compression_test.go @@ -72,7 +72,9 @@ func TestDefaultCompression(t *testing.T) { func TestDisableCompression(t *testing.T) { withDisableCompression := func(conf *xdscache_v3.ListenerConfig) { - conf.Compression = "disabled" + conf.Compression = &contour_v1alpha1.EnvoyCompression{ + Algorithm: contour_v1alpha1.DisabledCompression, + } } rh, c, done := setup(t, withDisableCompression) @@ -104,7 +106,9 @@ func TestDisableCompression(t *testing.T) { httpListener := defaultHTTPListener() httpListener.FilterChains = envoy_v3.FilterChains(envoy_v3.HTTPConnectionManagerBuilder(). - Compression("disabled"). + Compression(&contour_v1alpha1.EnvoyCompression{ + Algorithm: contour_v1alpha1.DisabledCompression, + }). RouteConfigName(xdscache_v3.ENVOY_HTTP_LISTENER). MetricsPrefix(xdscache_v3.ENVOY_HTTP_LISTENER). AccessLoggers(envoy_v3.FileAccessLogEnvoy(xdscache_v3.DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). @@ -120,7 +124,9 @@ func TestDisableCompression(t *testing.T) { func TestBrotliCompression(t *testing.T) { withBrotliCompression := func(conf *xdscache_v3.ListenerConfig) { - conf.Compression = "brotli" + conf.Compression = &contour_v1alpha1.EnvoyCompression{ + Algorithm: contour_v1alpha1.BrotliCompression, + } } rh, c, done := setup(t, withBrotliCompression) @@ -152,7 +158,9 @@ func TestBrotliCompression(t *testing.T) { httpListener := defaultHTTPListener() httpListener.FilterChains = envoy_v3.FilterChains(envoy_v3.HTTPConnectionManagerBuilder(). - Compression("brotli"). + Compression(&contour_v1alpha1.EnvoyCompression{ + Algorithm: contour_v1alpha1.BrotliCompression, + }). RouteConfigName(xdscache_v3.ENVOY_HTTP_LISTENER). MetricsPrefix(xdscache_v3.ENVOY_HTTP_LISTENER). AccessLoggers(envoy_v3.FileAccessLogEnvoy(xdscache_v3.DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). @@ -168,7 +176,9 @@ func TestBrotliCompression(t *testing.T) { func TestZstdCompression(t *testing.T) { withZstdCompression := func(conf *xdscache_v3.ListenerConfig) { - conf.Compression = "zstd" + conf.Compression = &contour_v1alpha1.EnvoyCompression{ + Algorithm: contour_v1alpha1.ZstdCompression, + } } rh, c, done := setup(t, withZstdCompression) @@ -200,7 +210,9 @@ func TestZstdCompression(t *testing.T) { httpListener := defaultHTTPListener() httpListener.FilterChains = envoy_v3.FilterChains(envoy_v3.HTTPConnectionManagerBuilder(). - Compression("zstd"). + Compression(&contour_v1alpha1.EnvoyCompression{ + Algorithm: contour_v1alpha1.ZstdCompression, + }). RouteConfigName(xdscache_v3.ENVOY_HTTP_LISTENER). MetricsPrefix(xdscache_v3.ENVOY_HTTP_LISTENER). AccessLoggers(envoy_v3.FileAccessLogEnvoy(xdscache_v3.DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). diff --git a/internal/xdscache/v3/listener.go b/internal/xdscache/v3/listener.go index 36ad156a32b..b053493861d 100644 --- a/internal/xdscache/v3/listener.go +++ b/internal/xdscache/v3/listener.go @@ -66,10 +66,8 @@ type ListenerConfig struct { // If not set, defaults to false. UseProxyProto bool - // Compression configures which compression, if any, the listener uses in the compression filter as part of the defaultFilters. - // Valid values: `gzip` (default), `brotli`, `zstd`, `disabled`. - // Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response - Compression contour_v1alpha1.EnvoyCompressionType + // Compression defines configuration related to compression in the default HTTP Listener filters. + Compression *contour_v1alpha1.EnvoyCompression // MinimumTLSVersion defines the minimum TLS protocol version the proxy should accept. MinimumTLSVersion string diff --git a/internal/xdscache/v3/listener_test.go b/internal/xdscache/v3/listener_test.go index a7223d48ce3..c4f464ef8c4 100644 --- a/internal/xdscache/v3/listener_test.go +++ b/internal/xdscache/v3/listener_test.go @@ -3076,7 +3076,9 @@ func TestListenerVisit(t *testing.T) { }, "httpproxy with disabled compression set in listener config": { ListenerConfig: ListenerConfig{ - Compression: "disabled", + Compression: &contour_v1alpha1.EnvoyCompression{ + Algorithm: contour_v1alpha1.DisabledCompression, + }, }, objs: []any{ &contour_v1.HTTPProxy{ @@ -3106,7 +3108,9 @@ func TestListenerVisit(t *testing.T) { Address: envoy_v3.SocketAddress("0.0.0.0", 8080), FilterChains: envoy_v3.FilterChains( envoy_v3.HTTPConnectionManagerBuilder(). - Compression("disabled"). + Compression(&contour_v1alpha1.EnvoyCompression{ + Algorithm: contour_v1alpha1.DisabledCompression, + }). RouteConfigName(ENVOY_HTTP_LISTENER). MetricsPrefix(ENVOY_HTTP_LISTENER). AccessLoggers(envoy_v3.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). @@ -3118,7 +3122,9 @@ func TestListenerVisit(t *testing.T) { }, "httpproxy with gzip compression set in listener config": { ListenerConfig: ListenerConfig{ - Compression: "gzip", + Compression: &contour_v1alpha1.EnvoyCompression{ + Algorithm: contour_v1alpha1.GzipCompression, + }, }, objs: []any{ &contour_v1.HTTPProxy{ @@ -3148,7 +3154,9 @@ func TestListenerVisit(t *testing.T) { Address: envoy_v3.SocketAddress("0.0.0.0", 8080), FilterChains: envoy_v3.FilterChains( envoy_v3.HTTPConnectionManagerBuilder(). - Compression("gzip"). + Compression(&contour_v1alpha1.EnvoyCompression{ + Algorithm: contour_v1alpha1.GzipCompression, + }). RouteConfigName(ENVOY_HTTP_LISTENER). MetricsPrefix(ENVOY_HTTP_LISTENER). AccessLoggers(envoy_v3.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). @@ -3160,7 +3168,9 @@ func TestListenerVisit(t *testing.T) { }, "httpproxy with brotli compression set in listener config": { ListenerConfig: ListenerConfig{ - Compression: "brotli", + Compression: &contour_v1alpha1.EnvoyCompression{ + Algorithm: contour_v1alpha1.BrotliCompression, + }, }, objs: []any{ &contour_v1.HTTPProxy{ @@ -3190,7 +3200,9 @@ func TestListenerVisit(t *testing.T) { Address: envoy_v3.SocketAddress("0.0.0.0", 8080), FilterChains: envoy_v3.FilterChains( envoy_v3.HTTPConnectionManagerBuilder(). - Compression("brotli"). + Compression(&contour_v1alpha1.EnvoyCompression{ + Algorithm: contour_v1alpha1.BrotliCompression, + }). RouteConfigName(ENVOY_HTTP_LISTENER). MetricsPrefix(ENVOY_HTTP_LISTENER). AccessLoggers(envoy_v3.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). @@ -3202,7 +3214,9 @@ func TestListenerVisit(t *testing.T) { }, "httpproxy with zstd compression set in listener config": { ListenerConfig: ListenerConfig{ - Compression: "zstd", + Compression: &contour_v1alpha1.EnvoyCompression{ + Algorithm: contour_v1alpha1.ZstdCompression, + }, }, objs: []any{ &contour_v1.HTTPProxy{ @@ -3232,7 +3246,9 @@ func TestListenerVisit(t *testing.T) { Address: envoy_v3.SocketAddress("0.0.0.0", 8080), FilterChains: envoy_v3.FilterChains( envoy_v3.HTTPConnectionManagerBuilder(). - Compression("zstd"). + Compression(&contour_v1alpha1.EnvoyCompression{ + Algorithm: contour_v1alpha1.ZstdCompression, + }). RouteConfigName(ENVOY_HTTP_LISTENER). MetricsPrefix(ENVOY_HTTP_LISTENER). AccessLoggers(envoy_v3.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). @@ -3244,7 +3260,9 @@ func TestListenerVisit(t *testing.T) { }, "httpproxy with invalid compression set in listener config": { ListenerConfig: ListenerConfig{ - Compression: "invalid value", + Compression: &contour_v1alpha1.EnvoyCompression{ + Algorithm: "invalid value", + }, }, objs: []any{ &contour_v1.HTTPProxy{ @@ -3274,7 +3292,9 @@ func TestListenerVisit(t *testing.T) { Address: envoy_v3.SocketAddress("0.0.0.0", 8080), FilterChains: envoy_v3.FilterChains( envoy_v3.HTTPConnectionManagerBuilder(). - Compression("gzip"). + Compression(&contour_v1alpha1.EnvoyCompression{ + Algorithm: contour_v1alpha1.GzipCompression, + }). RouteConfigName(ENVOY_HTTP_LISTENER). MetricsPrefix(ENVOY_HTTP_LISTENER). AccessLoggers(envoy_v3.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). diff --git a/pkg/config/parameters.go b/pkg/config/parameters.go index d349c632a4b..1b4d3c7d064 100644 --- a/pkg/config/parameters.go +++ b/pkg/config/parameters.go @@ -651,11 +651,9 @@ type Parameters struct { // which strips duplicate slashes from request URL paths. DisableMergeSlashes bool `yaml:"disableMergeSlashes,omitempty"` - // Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. - // Values: `gzip` (default), `brotli`, `zstd`, `disabled`. - // Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response + // Compression defines configuration relating to compression in the default HTTP filter chain. // +optional - Compression EnvoyCompressionType `yaml:"compression,omitempty"` + Compression *CompressionParameters `yaml:"compression,omitempty"` // Defines the action to be applied to the Server header on the response path. // When configured as overwrite, overwrites any Server header with "envoy". @@ -972,17 +970,31 @@ const ( LogLevelDisabled AccessLogLevel = "disabled" ) -type EnvoyCompressionType string +// CompressionParameters holds various configurable compression related values. +type CompressionParameters struct { -func (c EnvoyCompressionType) Validate() error { - return contour_v1alpha1.EnvoyCompressionType(c).Validate() + // Algorithm configures which compression algorithm, if any, to use in the default HTTP listener filter chain. + // Valid options are 'gzip' (default), 'brotli', 'zstd' and 'disabled'. + // +optional + Algorithm CompressionAlgorithm `yaml:"algorithm,omitempty"` +} + +func (c CompressionParameters) Validate() error { + return c.Algorithm.Validate() +} + +type CompressionAlgorithm string + +func (c CompressionAlgorithm) Validate() error { + return contour_v1alpha1.CompressionAlgorithm(c).Validate() } const ( - CompressionGzip EnvoyCompressionType = "gzip" - CompressionBrotli EnvoyCompressionType = "brotli" - CompressionDisabled EnvoyCompressionType = "disabled" - CompressionZstd EnvoyCompressionType = "zstd" + CompressionGzip CompressionAlgorithm = "gzip" + CompressionBrotli CompressionAlgorithm = "brotli" + CompressionDisabled CompressionAlgorithm = "disabled" + CompressionZstd CompressionAlgorithm = "zstd" + CompressionDefault = CompressionGzip ) // Validate verifies that the parameter values do not have any syntax errors. @@ -1052,8 +1064,8 @@ func (p *Parameters) Validate() error { return p.Listener.Validate() } -// DefaultCompressionFilter is the compression mechanism in the default HTTP filter chain -const DefaultCompressionFilter = CompressionGzip +// DefaultCompressionAlgorithm is the compression mechanism in the default HTTP filter chain +const DefaultCompressionAlgorithm = CompressionGzip // Defaults returns the default set of parameters. func Defaults() Parameters { @@ -1074,7 +1086,6 @@ func Defaults() Parameters { DisablePermitInsecure: false, DisableAllowChunkedLength: false, DisableMergeSlashes: false, - Compression: DefaultCompressionFilter, ServerHeaderTransformation: OverwriteServerHeader, Timeouts: TimeoutParameters{ // This is chosen as a rough default to stop idle connections wasting resources, diff --git a/site/content/docs/main/config/api-reference.html b/site/content/docs/main/config/api-reference.html index aa21e8084c8..340f09b7967 100644 --- a/site/content/docs/main/config/api-reference.html +++ b/site/content/docs/main/config/api-reference.html @@ -5851,6 +5851,40 @@

ClusterParameters +

CompressionAlgorithm +(string alias)

+

+(Appears on: +EnvoyCompression) +

+

+

CompressionAlgorithm defines the type of compression algorithm applied in default HTTP listener filter chain. +Allowable values are defined as names of well known compression algorithms (plus “disabled”).

+

+ + + + + + + + + + + + + + + + + + +
ValueDescription

"brotli"

BrotliCompression specifies brotli as the default HTTP filter chain compression mechanism

+

"gzip"

DefaultCompression specifies which of the compression algorithms is used by default

+

"disabled"

DisabledCompression specifies that there will be no compression in the default HTTP filter chain

+

"gzip"

GzipCompression specifies gzip as the default HTTP filter chain compression mechanism

+

"zstd"

ZstdCompression specifies zstd as the default HTTP filter chain compression mechanism

+

ContourConfigurationSpec

@@ -6595,34 +6629,41 @@

DeploymentSettings -

EnvoyCompressionType -(string alias)

+

EnvoyCompression +

(Appears on: EnvoyListenerConfig)

+

EnvoyCompression defines configuration related to compression in the default HTTP Listener filter chain.

- + - - - - - - + + - - - + +
ValueField Description

"brotli"

BrotliCompression specifies brotli as the default HTTP filter chain compression mechanism

-

"disabled"

DisabledCompression specifies that there will be no compression in the default HTTP filter chain

-

"gzip"

GzipCompression specifies gzip as the default HTTP filter chain compression mechanism

+
+algorithm +
+ + +CompressionAlgorithm + +

"zstd"

ZstdCompression specifies zstd as the default HTTP filter chain compression mechanism

+
+(Optional) +

Algorithm selects the compression type applied in the compression HTTP filter of the default Listener filters. +Values: gzip (default), brotli, zstd, disabled. +Setting this to disabled will make Envoy skip “Accept-Encoding: gzip,deflate” request header and always return uncompressed response

EnvoyConfig

@@ -6932,16 +6973,14 @@

EnvoyListenerConfig compression
- -EnvoyCompressionType + +EnvoyCompression (Optional) -

Compression selects the compression type applied in the compression HTTP filter of the default Listener filters. -Values: gzip (default), brotli, zstd, disabled. -Setting this to disabled will make Envoy skip “Accept-Encoding: gzip,deflate” request header and always return uncompressed response

+

Compression defines configuration related to compression in the default HTTP Listener filters.

diff --git a/test/e2e/fixtures.go b/test/e2e/fixtures.go index 6d819bc1174..4cc20831bf6 100644 --- a/test/e2e/fixtures.go +++ b/test/e2e/fixtures.go @@ -583,7 +583,6 @@ func DefaultContourConfiguration() *contour_v1alpha1.ContourConfiguration { }, Listener: &contour_v1alpha1.EnvoyListenerConfig{ UseProxyProto: ptr.To(false), - Compression: "gzip", DisableAllowChunkedLength: ptr.To(false), ConnectionBalancer: "", TLS: &contour_v1alpha1.EnvoyTLS{ diff --git a/test/e2e/httpproxy/httpproxy_test.go b/test/e2e/httpproxy/httpproxy_test.go index c8e85cef70e..7a45b8f62e9 100644 --- a/test/e2e/httpproxy/httpproxy_test.go +++ b/test/e2e/httpproxy/httpproxy_test.go @@ -395,8 +395,12 @@ var _ = Describe("HTTPProxy", func() { f.NamespacedTest("httpproxy-disable-compression", func(namespace string) { Context("with compression disabled", func() { BeforeEach(func() { - contourConfig.Compression = "disabled" - contourConfiguration.Spec.Envoy.Listener.Compression = "disabled" + contourConfig.Compression = &config.CompressionParameters{ + Algorithm: config.CompressionDisabled, + } + contourConfiguration.Spec.Envoy.Listener.Compression = &contour_v1alpha1.EnvoyCompression{ + Algorithm: contour_v1alpha1.DisabledCompression, + } }) testEnvoyDisableCompression(namespace, "gzip", "gzip", true) }) @@ -405,8 +409,12 @@ var _ = Describe("HTTPProxy", func() { f.NamespacedTest("httpproxy-brotli-compression", func(namespace string) { Context("with brotli compression", func() { BeforeEach(func() { - contourConfig.Compression = "brotli" - contourConfiguration.Spec.Envoy.Listener.Compression = "brotli" + contourConfig.Compression = &config.CompressionParameters{ + Algorithm: config.CompressionBrotli, + } + contourConfiguration.Spec.Envoy.Listener.Compression = &contour_v1alpha1.EnvoyCompression{ + Algorithm: contour_v1alpha1.BrotliCompression, + } }) testEnvoyDisableCompression(namespace, "br", "br", false) }) @@ -415,8 +423,12 @@ var _ = Describe("HTTPProxy", func() { f.NamespacedTest("httpproxy-zstd-compression", func(namespace string) { Context("with zstd compression", func() { BeforeEach(func() { - contourConfig.Compression = "zstd" - contourConfiguration.Spec.Envoy.Listener.Compression = "zstd" + contourConfig.Compression = &config.CompressionParameters{ + Algorithm: config.CompressionZstd, + } + contourConfiguration.Spec.Envoy.Listener.Compression = &contour_v1alpha1.EnvoyCompression{ + Algorithm: contour_v1alpha1.ZstdCompression, + } }) testEnvoyDisableCompression(namespace, "zstd", "zstd", false) }) From 3d833945f44018d9cc5f0226340baae212e1511f Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Wed, 23 Oct 2024 18:04:50 +0100 Subject: [PATCH 15/30] lint fixes Signed-off-by: Geoff Macartney --- internal/envoy/v3/listener.go | 6 +++--- pkg/config/parameters.go | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/internal/envoy/v3/listener.go b/internal/envoy/v3/listener.go index 59dcc233a67..5b15021d4da 100644 --- a/internal/envoy/v3/listener.go +++ b/internal/envoy/v3/listener.go @@ -16,8 +16,6 @@ package v3 import ( "errors" "fmt" - envoy_compression_brotli_compressor_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/compression/brotli/compressor/v3" - envoy_compression_zstd_compressor_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/compression/zstd/compressor/v3" "sort" "strings" "time" @@ -25,7 +23,9 @@ import ( envoy_config_accesslog_v3 "github.com/envoyproxy/go-control-plane/envoy/config/accesslog/v3" envoy_config_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" envoy_config_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" + envoy_compression_brotli_compressor_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/compression/brotli/compressor/v3" envoy_compression_gzip_compressor_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/compression/gzip/compressor/v3" + envoy_compression_zstd_compressor_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/compression/zstd/compressor/v3" envoy_filter_http_compressor_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/compressor/v3" envoy_filter_http_cors_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/cors/v3" envoy_filter_http_ext_authz_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/ext_authz/v3" @@ -318,7 +318,7 @@ func (b *httpConnectionManagerBuilder) DefaultFilters() *httpConnectionManagerBu // The names are not required to match anything and are // identified by the TypeURL of each filter. var compressor proto.Message = &envoy_compression_gzip_compressor_v3.Gzip{} - var compressorName = string(contour_v1alpha1.GzipCompression) + compressorName := string(contour_v1alpha1.GzipCompression) if b.compression != nil { switch b.compression.Algorithm { case contour_v1alpha1.BrotliCompression: diff --git a/pkg/config/parameters.go b/pkg/config/parameters.go index 1b4d3c7d064..2f6d33d6384 100644 --- a/pkg/config/parameters.go +++ b/pkg/config/parameters.go @@ -972,7 +972,6 @@ const ( // CompressionParameters holds various configurable compression related values. type CompressionParameters struct { - // Algorithm configures which compression algorithm, if any, to use in the default HTTP listener filter chain. // Valid options are 'gzip' (default), 'brotli', 'zstd' and 'disabled'. // +optional From cda9c76ea6b37400c8de2641e587efe1c9036e67 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Thu, 24 Oct 2024 18:00:09 +0100 Subject: [PATCH 16/30] test fix Avoid NPE in parameters.Validate also tidy flag handling in registerServe, don't set compression struct unless parameter is supplied. Signed-off-by: Geoff Macartney --- cmd/contour/serve.go | 15 ++++++++------- pkg/config/parameters.go | 6 ++++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/cmd/contour/serve.go b/cmd/contour/serve.go index 8a4801bd137..49f3adc8647 100644 --- a/cmd/contour/serve.go +++ b/cmd/contour/serve.go @@ -124,15 +124,16 @@ func registerServe(app *kingpin.Application) (*kingpin.CmdClause, *serveContext) return nil } - if ctx.Config.Compression == nil { - ctx.Config.Compression = &config.CompressionParameters{ - Algorithm: config.CompressionDefault, - } - } - serve.Flag("accesslog-format", "Format for Envoy access logs.").PlaceHolder("").StringVar((*string)(&ctx.Config.AccessLogFormat)) - serve.Flag("compression", "Set or disable compression type in default Listener filters.").PlaceHolder("").StringVar((*string)(&ctx.Config.Compression.Algorithm)) + var compressionFlag string + serve.Flag("compression", "Set or disable compression type in default Listener filters.").PlaceHolder("").StringVar(&compressionFlag) + if compressionFlag != "" { + if ctx.Config.Compression == nil { + ctx.Config.Compression = &config.CompressionParameters{} + } + ctx.Config.Compression.Algorithm = config.CompressionAlgorithm(compressionFlag) + } serve.Flag("config-path", "Path to base configuration.").Short('c').PlaceHolder("/path/to/file").Action(parseConfig).ExistingFileVar(&configFile) serve.Flag("contour-cafile", "CA bundle file name for serving gRPC with TLS.").Envar("CONTOUR_CAFILE").StringVar(&ctx.caFile) serve.Flag("contour-cert-file", "Contour certificate file name for serving gRPC over TLS.").PlaceHolder("/path/to/file").Envar("CONTOUR_CERT_FILE").StringVar(&ctx.contourCert) diff --git a/pkg/config/parameters.go b/pkg/config/parameters.go index 2f6d33d6384..4c1da8595e2 100644 --- a/pkg/config/parameters.go +++ b/pkg/config/parameters.go @@ -1026,8 +1026,10 @@ func (p *Parameters) Validate() error { return err } - if err := p.Compression.Validate(); err != nil { - return err + if p.Compression != nil { + if err := p.Compression.Validate(); err != nil { + return err + } } if err := p.TLS.Validate(); err != nil { From ff84c379dc943e3a74286f7766acccdd12adb259 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Mon, 28 Oct 2024 09:24:56 +0000 Subject: [PATCH 17/30] fix flag handling Signed-off-by: Geoff Macartney --- cmd/contour/serve.go | 9 +-------- cmd/contour/servecontext.go | 2 +- pkg/config/parameters.go | 4 ++-- test/e2e/httpproxy/httpproxy_test.go | 6 +++--- 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/cmd/contour/serve.go b/cmd/contour/serve.go index 49f3adc8647..4007437761b 100644 --- a/cmd/contour/serve.go +++ b/cmd/contour/serve.go @@ -126,14 +126,7 @@ func registerServe(app *kingpin.Application) (*kingpin.CmdClause, *serveContext) serve.Flag("accesslog-format", "Format for Envoy access logs.").PlaceHolder("").StringVar((*string)(&ctx.Config.AccessLogFormat)) - var compressionFlag string - serve.Flag("compression", "Set or disable compression type in default Listener filters.").PlaceHolder("").StringVar(&compressionFlag) - if compressionFlag != "" { - if ctx.Config.Compression == nil { - ctx.Config.Compression = &config.CompressionParameters{} - } - ctx.Config.Compression.Algorithm = config.CompressionAlgorithm(compressionFlag) - } + serve.Flag("compression", "Set or disable compression type in default Listener filters.").PlaceHolder("").StringVar((*string)(&ctx.Config.Compression.Algorithm)) serve.Flag("config-path", "Path to base configuration.").Short('c').PlaceHolder("/path/to/file").Action(parseConfig).ExistingFileVar(&configFile) serve.Flag("contour-cafile", "CA bundle file name for serving gRPC with TLS.").Envar("CONTOUR_CAFILE").StringVar(&ctx.caFile) serve.Flag("contour-cert-file", "Contour certificate file name for serving gRPC over TLS.").PlaceHolder("/path/to/file").Envar("CONTOUR_CERT_FILE").StringVar(&ctx.contourCert) diff --git a/cmd/contour/servecontext.go b/cmd/contour/servecontext.go index 3bf62e9a541..6fd2a3643e0 100644 --- a/cmd/contour/servecontext.go +++ b/cmd/contour/servecontext.go @@ -334,7 +334,7 @@ func (ctx *serveContext) convertToContourConfigurationSpec() contour_v1alpha1.Co } var compression *contour_v1alpha1.EnvoyCompression - if ctx.Config.Compression != nil { + if ctx.Config.Compression.Algorithm != "" { var algorithm contour_v1alpha1.CompressionAlgorithm switch ctx.Config.Compression.Algorithm { case config.CompressionBrotli: diff --git a/pkg/config/parameters.go b/pkg/config/parameters.go index 4c1da8595e2..51aa1540a4d 100644 --- a/pkg/config/parameters.go +++ b/pkg/config/parameters.go @@ -653,7 +653,7 @@ type Parameters struct { // Compression defines configuration relating to compression in the default HTTP filter chain. // +optional - Compression *CompressionParameters `yaml:"compression,omitempty"` + Compression CompressionParameters `yaml:"compression,omitempty"` // Defines the action to be applied to the Server header on the response path. // When configured as overwrite, overwrites any Server header with "envoy". @@ -1026,7 +1026,7 @@ func (p *Parameters) Validate() error { return err } - if p.Compression != nil { + if p.Compression.Algorithm != "" { if err := p.Compression.Validate(); err != nil { return err } diff --git a/test/e2e/httpproxy/httpproxy_test.go b/test/e2e/httpproxy/httpproxy_test.go index 7a45b8f62e9..0a838a2294a 100644 --- a/test/e2e/httpproxy/httpproxy_test.go +++ b/test/e2e/httpproxy/httpproxy_test.go @@ -395,7 +395,7 @@ var _ = Describe("HTTPProxy", func() { f.NamespacedTest("httpproxy-disable-compression", func(namespace string) { Context("with compression disabled", func() { BeforeEach(func() { - contourConfig.Compression = &config.CompressionParameters{ + contourConfig.Compression = config.CompressionParameters{ Algorithm: config.CompressionDisabled, } contourConfiguration.Spec.Envoy.Listener.Compression = &contour_v1alpha1.EnvoyCompression{ @@ -409,7 +409,7 @@ var _ = Describe("HTTPProxy", func() { f.NamespacedTest("httpproxy-brotli-compression", func(namespace string) { Context("with brotli compression", func() { BeforeEach(func() { - contourConfig.Compression = &config.CompressionParameters{ + contourConfig.Compression = config.CompressionParameters{ Algorithm: config.CompressionBrotli, } contourConfiguration.Spec.Envoy.Listener.Compression = &contour_v1alpha1.EnvoyCompression{ @@ -423,7 +423,7 @@ var _ = Describe("HTTPProxy", func() { f.NamespacedTest("httpproxy-zstd-compression", func(namespace string) { Context("with zstd compression", func() { BeforeEach(func() { - contourConfig.Compression = &config.CompressionParameters{ + contourConfig.Compression = config.CompressionParameters{ Algorithm: config.CompressionZstd, } contourConfiguration.Spec.Envoy.Listener.Compression = &contour_v1alpha1.EnvoyCompression{ From 5725a53c845599939b82f223b172374b3dcb7246 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Mon, 28 Oct 2024 10:33:27 +0000 Subject: [PATCH 18/30] api lint Signed-off-by: Geoff Macartney --- site/content/docs/main/config/api-reference.html | 3 --- 1 file changed, 3 deletions(-) diff --git a/site/content/docs/main/config/api-reference.html b/site/content/docs/main/config/api-reference.html index 340f09b7967..19c8e70e9bd 100644 --- a/site/content/docs/main/config/api-reference.html +++ b/site/content/docs/main/config/api-reference.html @@ -5871,9 +5871,6 @@

CompressionAlgorithm

"brotli"

BrotliCompression specifies brotli as the default HTTP filter chain compression mechanism

-

"gzip"

-

DefaultCompression specifies which of the compression algorithms is used by default

-

"disabled"

DisabledCompression specifies that there will be no compression in the default HTTP filter chain

From 630541e96d598108a23f6f639d71e2cd57b0919e Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Mon, 28 Oct 2024 10:58:33 +0000 Subject: [PATCH 19/30] parameters_test Signed-off-by: Geoff Macartney --- pkg/config/parameters_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/config/parameters_test.go b/pkg/config/parameters_test.go index 5ba18a0fb7c..7f6ad7a7dcd 100644 --- a/pkg/config/parameters_test.go +++ b/pkg/config/parameters_test.go @@ -75,7 +75,6 @@ json-fields: - grpc_status - grpc_status_number accesslog-level: info -compression: gzip serverHeaderTransformation: overwrite timeouts: connection-idle-timeout: 60s From 4610b8013497b570748771ce395a263065e5defd Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Mon, 28 Oct 2024 12:29:37 +0000 Subject: [PATCH 20/30] update comment Signed-off-by: Geoff Macartney --- pkg/config/parameters.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/config/parameters.go b/pkg/config/parameters.go index 51aa1540a4d..174a5077dd0 100644 --- a/pkg/config/parameters.go +++ b/pkg/config/parameters.go @@ -970,7 +970,8 @@ const ( LogLevelDisabled AccessLogLevel = "disabled" ) -// CompressionParameters holds various configurable compression related values. +// CompressionParameters is a type defining configurable compression related values. +// At present this is just the compression algorithm but this could be extended later with algorithm specific config. type CompressionParameters struct { // Algorithm configures which compression algorithm, if any, to use in the default HTTP listener filter chain. // Valid options are 'gzip' (default), 'brotli', 'zstd' and 'disabled'. From 45ea94642cf953f2e433dfd18a7fdfac29056fa0 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Mon, 28 Oct 2024 17:45:09 +0000 Subject: [PATCH 21/30] fix assertion arg order and bump timeout Signed-off-by: Geoff Macartney --- test/e2e/httpproxy/envoy_compression_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/httpproxy/envoy_compression_test.go b/test/e2e/httpproxy/envoy_compression_test.go index 5b069af8470..6f277815fdd 100644 --- a/test/e2e/httpproxy/envoy_compression_test.go +++ b/test/e2e/httpproxy/envoy_compression_test.go @@ -78,7 +78,7 @@ func testEnvoyDisableCompression(namespace, acceptEncoding, contentEncoding stri assert.NotEqual(c, contentEncodingHeaderValue, contentEncoding, "expected plain text") return } - assert.Equal(c, contentEncodingHeaderValue, contentEncoding, "expected plain text") - }, 15*time.Second, f.RetryInterval) + assert.Equal(c, contentEncoding, contentEncodingHeaderValue, "expected plain text") + }, 20*time.Second, f.RetryInterval) }) } From 98225fc48e703a6d9360ff358b9c3ddd97fe1129 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Mon, 25 Nov 2024 15:04:20 +0000 Subject: [PATCH 22/30] add some servecontext tests Signed-off-by: Geoff Macartney --- cmd/contour/servecontext_test.go | 287 +++++++++++++++++-------------- 1 file changed, 157 insertions(+), 130 deletions(-) diff --git a/cmd/contour/servecontext_test.go b/cmd/contour/servecontext_test.go index cf205d81a46..644edc6d68e 100644 --- a/cmd/contour/servecontext_test.go +++ b/cmd/contour/servecontext_test.go @@ -363,149 +363,150 @@ func TestParseHTTPVersions(t *testing.T) { } } -func TestConvertServeContext(t *testing.T) { - defaultContext := func() *serveContext { - ctx := newServeContext() - ctx.ServerConfig = ServerConfig{ - xdsAddr: "127.0.0.1", - xdsPort: 8001, - caFile: "/certs/ca.crt", - contourCert: "/certs/cert.crt", - contourKey: "/certs/cert.key", - } - return ctx +func defaultContext() *serveContext { + ctx := newServeContext() + ctx.ServerConfig = ServerConfig{ + xdsAddr: "127.0.0.1", + xdsPort: 8001, + caFile: "/certs/ca.crt", + contourCert: "/certs/cert.crt", + contourKey: "/certs/cert.key", } + return ctx +} - defaultContourConfiguration := func() contour_v1alpha1.ContourConfigurationSpec { - return contour_v1alpha1.ContourConfigurationSpec{ - XDSServer: &contour_v1alpha1.XDSServerConfig{ - Type: contour_v1alpha1.EnvoyServerType, - Address: "127.0.0.1", - Port: 8001, - TLS: &contour_v1alpha1.TLS{ - CAFile: "/certs/ca.crt", - CertFile: "/certs/cert.crt", - KeyFile: "/certs/cert.key", - Insecure: ptr.To(false), - }, - }, - Ingress: &contour_v1alpha1.IngressConfig{ - ClassNames: nil, - StatusAddress: "", - }, - Debug: &contour_v1alpha1.DebugConfig{ - Address: "127.0.0.1", - Port: 6060, +func defaultContourConfiguration() contour_v1alpha1.ContourConfigurationSpec { + return contour_v1alpha1.ContourConfigurationSpec{ + XDSServer: &contour_v1alpha1.XDSServerConfig{ + Type: contour_v1alpha1.EnvoyServerType, + Address: "127.0.0.1", + Port: 8001, + TLS: &contour_v1alpha1.TLS{ + CAFile: "/certs/ca.crt", + CertFile: "/certs/cert.crt", + KeyFile: "/certs/cert.key", + Insecure: ptr.To(false), }, - Health: &contour_v1alpha1.HealthConfig{ - Address: "0.0.0.0", - Port: 8000, + }, + Ingress: &contour_v1alpha1.IngressConfig{ + ClassNames: nil, + StatusAddress: "", + }, + Debug: &contour_v1alpha1.DebugConfig{ + Address: "127.0.0.1", + Port: 6060, + }, + Health: &contour_v1alpha1.HealthConfig{ + Address: "0.0.0.0", + Port: 8000, + }, + Envoy: &contour_v1alpha1.EnvoyConfig{ + Service: &contour_v1alpha1.NamespacedName{ + Name: "envoy", + Namespace: "projectcontour", }, - Envoy: &contour_v1alpha1.EnvoyConfig{ - Service: &contour_v1alpha1.NamespacedName{ - Name: "envoy", - Namespace: "projectcontour", - }, - Listener: &contour_v1alpha1.EnvoyListenerConfig{ - UseProxyProto: ptr.To(false), - DisableAllowChunkedLength: ptr.To(false), - DisableMergeSlashes: ptr.To(false), - ServerHeaderTransformation: contour_v1alpha1.OverwriteServerHeader, - TLS: &contour_v1alpha1.EnvoyTLS{ - MinimumProtocolVersion: "", - MaximumProtocolVersion: "", - }, - SocketOptions: &contour_v1alpha1.SocketOptions{ - TOS: 0, - TrafficClass: 0, - }, - }, - HTTPListener: &contour_v1alpha1.EnvoyListener{ - Address: "0.0.0.0", - Port: 8080, - AccessLog: "/dev/stdout", - }, - HTTPSListener: &contour_v1alpha1.EnvoyListener{ - Address: "0.0.0.0", - Port: 8443, - AccessLog: "/dev/stdout", - }, - Health: &contour_v1alpha1.HealthConfig{ - Address: "0.0.0.0", - Port: 8002, - }, - Metrics: &contour_v1alpha1.MetricsConfig{ - Address: "0.0.0.0", - Port: 8002, - }, - ClientCertificate: nil, - Logging: &contour_v1alpha1.EnvoyLogging{ - AccessLogFormat: contour_v1alpha1.EnvoyAccessLog, - AccessLogFormatString: "", - AccessLogLevel: contour_v1alpha1.LogLevelInfo, - AccessLogJSONFields: contour_v1alpha1.AccessLogJSONFields([]string{ - "@timestamp", - "authority", - "bytes_received", - "bytes_sent", - "downstream_local_address", - "downstream_remote_address", - "duration", - "method", - "path", - "protocol", - "request_id", - "requested_server_name", - "response_code", - "response_flags", - "uber_trace_id", - "upstream_cluster", - "upstream_host", - "upstream_local_address", - "upstream_service_time", - "user_agent", - "x_forwarded_for", - "grpc_status", - "grpc_status_number", - }), - }, - DefaultHTTPVersions: nil, - Timeouts: &contour_v1alpha1.TimeoutParameters{ - ConnectionIdleTimeout: ptr.To("60s"), - ConnectTimeout: ptr.To("2s"), - }, - Cluster: &contour_v1alpha1.ClusterParameters{ - DNSLookupFamily: contour_v1alpha1.AutoClusterDNSFamily, - GlobalCircuitBreakerDefaults: nil, - UpstreamTLS: &contour_v1alpha1.EnvoyTLS{ - MinimumProtocolVersion: "", - MaximumProtocolVersion: "", - }, + Listener: &contour_v1alpha1.EnvoyListenerConfig{ + UseProxyProto: ptr.To(false), + DisableAllowChunkedLength: ptr.To(false), + DisableMergeSlashes: ptr.To(false), + ServerHeaderTransformation: contour_v1alpha1.OverwriteServerHeader, + TLS: &contour_v1alpha1.EnvoyTLS{ + MinimumProtocolVersion: "", + MaximumProtocolVersion: "", }, - Network: &contour_v1alpha1.NetworkParameters{ - EnvoyAdminPort: ptr.To(9001), - XffNumTrustedHops: ptr.To(uint32(0)), + SocketOptions: &contour_v1alpha1.SocketOptions{ + TOS: 0, + TrafficClass: 0, }, }, - Gateway: nil, - HTTPProxy: &contour_v1alpha1.HTTPProxyConfig{ - DisablePermitInsecure: ptr.To(false), - FallbackCertificate: nil, + HTTPListener: &contour_v1alpha1.EnvoyListener{ + Address: "0.0.0.0", + Port: 8080, + AccessLog: "/dev/stdout", }, - EnableExternalNameService: ptr.To(false), - RateLimitService: nil, - GlobalExternalAuthorization: nil, - Policy: &contour_v1alpha1.PolicyConfig{ - RequestHeadersPolicy: &contour_v1alpha1.HeadersPolicy{}, - ResponseHeadersPolicy: &contour_v1alpha1.HeadersPolicy{}, - ApplyToIngress: ptr.To(false), + HTTPSListener: &contour_v1alpha1.EnvoyListener{ + Address: "0.0.0.0", + Port: 8443, + AccessLog: "/dev/stdout", + }, + Health: &contour_v1alpha1.HealthConfig{ + Address: "0.0.0.0", + Port: 8002, }, Metrics: &contour_v1alpha1.MetricsConfig{ Address: "0.0.0.0", - Port: 8000, + Port: 8002, + }, + ClientCertificate: nil, + Logging: &contour_v1alpha1.EnvoyLogging{ + AccessLogFormat: contour_v1alpha1.EnvoyAccessLog, + AccessLogFormatString: "", + AccessLogLevel: contour_v1alpha1.LogLevelInfo, + AccessLogJSONFields: contour_v1alpha1.AccessLogJSONFields([]string{ + "@timestamp", + "authority", + "bytes_received", + "bytes_sent", + "downstream_local_address", + "downstream_remote_address", + "duration", + "method", + "path", + "protocol", + "request_id", + "requested_server_name", + "response_code", + "response_flags", + "uber_trace_id", + "upstream_cluster", + "upstream_host", + "upstream_local_address", + "upstream_service_time", + "user_agent", + "x_forwarded_for", + "grpc_status", + "grpc_status_number", + }), + }, + DefaultHTTPVersions: nil, + Timeouts: &contour_v1alpha1.TimeoutParameters{ + ConnectionIdleTimeout: ptr.To("60s"), + ConnectTimeout: ptr.To("2s"), + }, + Cluster: &contour_v1alpha1.ClusterParameters{ + DNSLookupFamily: contour_v1alpha1.AutoClusterDNSFamily, + GlobalCircuitBreakerDefaults: nil, + UpstreamTLS: &contour_v1alpha1.EnvoyTLS{ + MinimumProtocolVersion: "", + MaximumProtocolVersion: "", + }, }, - } + Network: &contour_v1alpha1.NetworkParameters{ + EnvoyAdminPort: ptr.To(9001), + XffNumTrustedHops: ptr.To(uint32(0)), + }, + }, + Gateway: nil, + HTTPProxy: &contour_v1alpha1.HTTPProxyConfig{ + DisablePermitInsecure: ptr.To(false), + FallbackCertificate: nil, + }, + EnableExternalNameService: ptr.To(false), + RateLimitService: nil, + GlobalExternalAuthorization: nil, + Policy: &contour_v1alpha1.PolicyConfig{ + RequestHeadersPolicy: &contour_v1alpha1.HeadersPolicy{}, + ResponseHeadersPolicy: &contour_v1alpha1.HeadersPolicy{}, + ApplyToIngress: ptr.To(false), + }, + Metrics: &contour_v1alpha1.MetricsConfig{ + Address: "0.0.0.0", + Port: 8000, + }, } +} + +func TestConvertServeContext(t *testing.T) { cases := map[string]struct { getServeContext func(ctx *serveContext) *serveContext @@ -912,3 +913,29 @@ func TestConvertServeContext(t *testing.T) { }) } } + +func TestServeContextCompressionOptions(t *testing.T) { + cases := map[string]struct { + serveCompression config.CompressionAlgorithm + configCompression contour_v1alpha1.CompressionAlgorithm + }{ + "Brotli": {config.CompressionBrotli, contour_v1alpha1.BrotliCompression}, + "Disabled": {config.CompressionDisabled, contour_v1alpha1.DisabledCompression}, + "Gzip": {config.CompressionGzip, contour_v1alpha1.GzipCompression}, + "Zstd": {config.CompressionZstd, contour_v1alpha1.ZstdCompression}, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + testServeContext := defaultContext() + testServeContext.Config.Compression.Algorithm = tc.serveCompression + + want := defaultContourConfiguration() + want.Envoy.Listener.Compression = &contour_v1alpha1.EnvoyCompression{ + Algorithm: tc.configCompression, + } + + assert.Equal(t, want, testServeContext.convertToContourConfigurationSpec()) + }) + } +} From 661b5520b3e18928830d191ff6c4144f29ae08cb Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Mon, 25 Nov 2024 17:13:15 +0000 Subject: [PATCH 23/30] add some parameters tests Signed-off-by: Geoff Macartney --- pkg/config/parameters_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pkg/config/parameters_test.go b/pkg/config/parameters_test.go index 7f6ad7a7dcd..f83f112f2c3 100644 --- a/pkg/config/parameters_test.go +++ b/pkg/config/parameters_test.go @@ -325,6 +325,14 @@ func TestTLSParametersValidation(t *testing.T) { }.Validate()) } +func TestCompressionValidation(t *testing.T) { + require.NoError(t, CompressionParameters{CompressionBrotli}.Validate()) + require.NoError(t, CompressionParameters{CompressionDisabled}.Validate()) + require.NoError(t, CompressionParameters{CompressionGzip}.Validate()) + require.NoError(t, CompressionParameters{CompressionZstd}.Validate()) + require.True(t, strings.Contains(CompressionParameters{"bogus"}.Validate().Error(), "invalid compression type")) +} + func TestConfigFileValidation(t *testing.T) { check := func(yamlIn string) { t.Helper() From 75f8b7b909e8d4c518c8fec1ac7fc0b4dab8cce0 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Tue, 26 Nov 2024 12:37:30 +0000 Subject: [PATCH 24/30] Update internal/featuretests/v3/compression_test.go Co-authored-by: Tero Saarni Signed-off-by: Geoff Macartney --- internal/featuretests/v3/compression_test.go | 212 ++++--------------- 1 file changed, 40 insertions(+), 172 deletions(-) diff --git a/internal/featuretests/v3/compression_test.go b/internal/featuretests/v3/compression_test.go index 0535242c487..b374ed92e1c 100644 --- a/internal/featuretests/v3/compression_test.go +++ b/internal/featuretests/v3/compression_test.go @@ -27,62 +27,20 @@ import ( xdscache_v3 "github.com/projectcontour/contour/internal/xdscache/v3" ) -func TestDefaultCompression(t *testing.T) { - rh, c, done := setup(t) - defer done() - - s1 := fixture.NewService("backend"). - WithPorts(core_v1.ServicePort{Name: "http", Port: 80}) - rh.OnAdd(s1) - - hp1 := &contour_v1.HTTPProxy{ - ObjectMeta: meta_v1.ObjectMeta{ - Name: "simple", - Namespace: s1.Namespace, - }, - Spec: contour_v1.HTTPProxySpec{ - VirtualHost: &contour_v1.VirtualHost{ - Fqdn: "example.com", - }, - Routes: []contour_v1.Route{{ - Conditions: matchconditions(prefixMatchCondition("/")), - Services: []contour_v1.Service{{ - Name: s1.Name, - Port: 80, - }}, - }}, - }, +func TestCompression(t *testing.T) { + tests := map[string]struct { + algorithm contour_v1alpha1.CompressionAlgorithm + want contour_v1alpha1.CompressionAlgorithm + }{ + "default": {algorithm: "", want: contour_v1alpha1.GzipCompression}, + "disabled": {algorithm: contour_v1alpha1.DisabledCompression, want: contour_v1alpha1.DisabledCompression}, + "brotli": {algorithm: contour_v1alpha1.BrotliCompression, want: contour_v1alpha1.BrotliCompression}, + "zstd": {algorithm: contour_v1alpha1.ZstdCompression, want: contour_v1alpha1.ZstdCompression}, + "gzip": {algorithm: contour_v1alpha1.GzipCompression, want: contour_v1alpha1.GzipCompression}, } - rh.OnAdd(hp1) - - httpListener := defaultHTTPListener() - httpListener.FilterChains = envoy_v3.FilterChains(envoy_v3.HTTPConnectionManagerBuilder(). - RouteConfigName(xdscache_v3.ENVOY_HTTP_LISTENER). - MetricsPrefix(xdscache_v3.ENVOY_HTTP_LISTENER). - AccessLoggers(envoy_v3.FileAccessLogEnvoy(xdscache_v3.DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). - DefaultFilters(). - Get(), - ) - - c.Request(listenerType, xdscache_v3.ENVOY_HTTP_LISTENER).Equals(&envoy_service_discovery_v3.DiscoveryResponse{ - TypeUrl: listenerType, - Resources: resources(t, httpListener), - }) -} - -func TestDisableCompression(t *testing.T) { - withDisableCompression := func(conf *xdscache_v3.ListenerConfig) { - conf.Compression = &contour_v1alpha1.EnvoyCompression{ - Algorithm: contour_v1alpha1.DisabledCompression, - } - } - - rh, c, done := setup(t, withDisableCompression) - defer done() s1 := fixture.NewService("backend"). WithPorts(core_v1.ServicePort{Name: "http", Port: 80}) - rh.OnAdd(s1) hp1 := &contour_v1.HTTPProxy{ ObjectMeta: meta_v1.ObjectMeta{ @@ -102,126 +60,36 @@ func TestDisableCompression(t *testing.T) { }}, }, } - rh.OnAdd(hp1) - httpListener := defaultHTTPListener() - httpListener.FilterChains = envoy_v3.FilterChains(envoy_v3.HTTPConnectionManagerBuilder(). - Compression(&contour_v1alpha1.EnvoyCompression{ - Algorithm: contour_v1alpha1.DisabledCompression, - }). - RouteConfigName(xdscache_v3.ENVOY_HTTP_LISTENER). - MetricsPrefix(xdscache_v3.ENVOY_HTTP_LISTENER). - AccessLoggers(envoy_v3.FileAccessLogEnvoy(xdscache_v3.DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). - DefaultFilters(). - Get(), - ) - - c.Request(listenerType, xdscache_v3.ENVOY_HTTP_LISTENER).Equals(&envoy_service_discovery_v3.DiscoveryResponse{ - TypeUrl: listenerType, - Resources: resources(t, httpListener), - }) -} - -func TestBrotliCompression(t *testing.T) { - withBrotliCompression := func(conf *xdscache_v3.ListenerConfig) { - conf.Compression = &contour_v1alpha1.EnvoyCompression{ - Algorithm: contour_v1alpha1.BrotliCompression, - } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + rh, c, done := setup(t, func(conf *xdscache_v3.ListenerConfig) { + if tc.algorithm != "" { + conf.Compression = &contour_v1alpha1.EnvoyCompression{ + Algorithm: tc.algorithm, + } + } + }) + defer done() + + rh.OnAdd(s1) + rh.OnAdd(hp1) + httpListener := defaultHTTPListener() + httpListener.FilterChains = envoy_v3.FilterChains(envoy_v3.HTTPConnectionManagerBuilder(). + Compression(&contour_v1alpha1.EnvoyCompression{ + Algorithm: tc.want, + }). + RouteConfigName(xdscache_v3.ENVOY_HTTP_LISTENER). + MetricsPrefix(xdscache_v3.ENVOY_HTTP_LISTENER). + AccessLoggers(envoy_v3.FileAccessLogEnvoy(xdscache_v3.DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). + DefaultFilters(). + Get(), + ) + + c.Request(listenerType, xdscache_v3.ENVOY_HTTP_LISTENER).Equals(&envoy_service_discovery_v3.DiscoveryResponse{ + TypeUrl: listenerType, + Resources: resources(t, httpListener), + }) + }) } - - rh, c, done := setup(t, withBrotliCompression) - defer done() - - s1 := fixture.NewService("backend"). - WithPorts(core_v1.ServicePort{Name: "http", Port: 80}) - rh.OnAdd(s1) - - hp1 := &contour_v1.HTTPProxy{ - ObjectMeta: meta_v1.ObjectMeta{ - Name: "simple", - Namespace: s1.Namespace, - }, - Spec: contour_v1.HTTPProxySpec{ - VirtualHost: &contour_v1.VirtualHost{ - Fqdn: "example.com", - }, - Routes: []contour_v1.Route{{ - Conditions: matchconditions(prefixMatchCondition("/")), - Services: []contour_v1.Service{{ - Name: s1.Name, - Port: 80, - }}, - }}, - }, - } - rh.OnAdd(hp1) - - httpListener := defaultHTTPListener() - httpListener.FilterChains = envoy_v3.FilterChains(envoy_v3.HTTPConnectionManagerBuilder(). - Compression(&contour_v1alpha1.EnvoyCompression{ - Algorithm: contour_v1alpha1.BrotliCompression, - }). - RouteConfigName(xdscache_v3.ENVOY_HTTP_LISTENER). - MetricsPrefix(xdscache_v3.ENVOY_HTTP_LISTENER). - AccessLoggers(envoy_v3.FileAccessLogEnvoy(xdscache_v3.DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). - DefaultFilters(). - Get(), - ) - - c.Request(listenerType, xdscache_v3.ENVOY_HTTP_LISTENER).Equals(&envoy_service_discovery_v3.DiscoveryResponse{ - TypeUrl: listenerType, - Resources: resources(t, httpListener), - }) -} - -func TestZstdCompression(t *testing.T) { - withZstdCompression := func(conf *xdscache_v3.ListenerConfig) { - conf.Compression = &contour_v1alpha1.EnvoyCompression{ - Algorithm: contour_v1alpha1.ZstdCompression, - } - } - - rh, c, done := setup(t, withZstdCompression) - defer done() - - s1 := fixture.NewService("backend"). - WithPorts(core_v1.ServicePort{Name: "http", Port: 80}) - rh.OnAdd(s1) - - hp1 := &contour_v1.HTTPProxy{ - ObjectMeta: meta_v1.ObjectMeta{ - Name: "simple", - Namespace: s1.Namespace, - }, - Spec: contour_v1.HTTPProxySpec{ - VirtualHost: &contour_v1.VirtualHost{ - Fqdn: "example.com", - }, - Routes: []contour_v1.Route{{ - Conditions: matchconditions(prefixMatchCondition("/")), - Services: []contour_v1.Service{{ - Name: s1.Name, - Port: 80, - }}, - }}, - }, - } - rh.OnAdd(hp1) - - httpListener := defaultHTTPListener() - httpListener.FilterChains = envoy_v3.FilterChains(envoy_v3.HTTPConnectionManagerBuilder(). - Compression(&contour_v1alpha1.EnvoyCompression{ - Algorithm: contour_v1alpha1.ZstdCompression, - }). - RouteConfigName(xdscache_v3.ENVOY_HTTP_LISTENER). - MetricsPrefix(xdscache_v3.ENVOY_HTTP_LISTENER). - AccessLoggers(envoy_v3.FileAccessLogEnvoy(xdscache_v3.DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). - DefaultFilters(). - Get(), - ) - - c.Request(listenerType, xdscache_v3.ENVOY_HTTP_LISTENER).Equals(&envoy_service_discovery_v3.DiscoveryResponse{ - TypeUrl: listenerType, - Resources: resources(t, httpListener), - }) } From 351a8200712b3b0cfeaed2010969e478cf31b123 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Tue, 26 Nov 2024 12:38:05 +0000 Subject: [PATCH 25/30] Update changelogs/unreleased/6546-chaosbox-small.md Co-authored-by: Tero Saarni Signed-off-by: Geoff Macartney --- changelogs/unreleased/6546-chaosbox-small.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelogs/unreleased/6546-chaosbox-small.md b/changelogs/unreleased/6546-chaosbox-small.md index 6017d1b0588..9cde1d1c957 100644 --- a/changelogs/unreleased/6546-chaosbox-small.md +++ b/changelogs/unreleased/6546-chaosbox-small.md @@ -1 +1 @@ -Add "compression" object to define settings in default HTTP filters, initially just supporting changing/disabling compression algorithm. +The HTTP compression algorithm can now be configured using the `compression.algorithm` field in the configuration file or the `spec.envoy.listener.compression.algorithm` field in the `ContourConfiguration` CRD. The available values are `gzip` (default), `brotli`, `zstd`, and `disabled`. From 95d38aff60981a92bda748bbccbb3630cacdfa35 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Tue, 26 Nov 2024 12:44:30 +0000 Subject: [PATCH 26/30] remove command flag from review comment: Let's remove the command line option and make configuration available only through config file and ContourConfiguration CRD. The command line options currently are a bit of a mess, so we previously agreed to avoid introducing new options there unless absolutely necessary. Signed-off-by: Geoff Macartney --- cmd/contour/serve.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/contour/serve.go b/cmd/contour/serve.go index 4007437761b..e24d7a403a3 100644 --- a/cmd/contour/serve.go +++ b/cmd/contour/serve.go @@ -126,7 +126,6 @@ func registerServe(app *kingpin.Application) (*kingpin.CmdClause, *serveContext) serve.Flag("accesslog-format", "Format for Envoy access logs.").PlaceHolder("").StringVar((*string)(&ctx.Config.AccessLogFormat)) - serve.Flag("compression", "Set or disable compression type in default Listener filters.").PlaceHolder("").StringVar((*string)(&ctx.Config.Compression.Algorithm)) serve.Flag("config-path", "Path to base configuration.").Short('c').PlaceHolder("/path/to/file").Action(parseConfig).ExistingFileVar(&configFile) serve.Flag("contour-cafile", "CA bundle file name for serving gRPC with TLS.").Envar("CONTOUR_CAFILE").StringVar(&ctx.caFile) serve.Flag("contour-cert-file", "Contour certificate file name for serving gRPC over TLS.").PlaceHolder("/path/to/file").Envar("CONTOUR_CERT_FILE").StringVar(&ctx.contourCert) From 366f48ddc4a19f6be1ad2a180eeef39b40ee75a1 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Tue, 26 Nov 2024 13:46:11 +0000 Subject: [PATCH 27/30] treat empty string as valid CompressionAlgorithm From review: Would it be cleaner to treat an empty string as a valid value here, rather than completely bypassing validation in Parameters.Validate()? While algorithm is the only field currently, that might change. Signed-off-by: Geoff Macartney --- apis/projectcontour/v1alpha1/compression.go | 2 +- apis/projectcontour/v1alpha1/compression_test.go | 2 +- pkg/config/parameters.go | 6 ++---- pkg/config/parameters_test.go | 1 + 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/apis/projectcontour/v1alpha1/compression.go b/apis/projectcontour/v1alpha1/compression.go index 3ae14097acf..f3f00b3f7c3 100644 --- a/apis/projectcontour/v1alpha1/compression.go +++ b/apis/projectcontour/v1alpha1/compression.go @@ -31,7 +31,7 @@ type EnvoyCompression struct { func (a CompressionAlgorithm) Validate() error { switch a { - case BrotliCompression, DisabledCompression, GzipCompression, ZstdCompression: + case BrotliCompression, DisabledCompression, GzipCompression, ZstdCompression, "": return nil default: return fmt.Errorf("invalid compression type: %q", a) diff --git a/apis/projectcontour/v1alpha1/compression_test.go b/apis/projectcontour/v1alpha1/compression_test.go index 0251c4d97eb..a2df6266790 100644 --- a/apis/projectcontour/v1alpha1/compression_test.go +++ b/apis/projectcontour/v1alpha1/compression_test.go @@ -22,9 +22,9 @@ import ( ) func TestValidateEnvoyCompressionAlgorithmType(t *testing.T) { - require.Error(t, contour_v1alpha1.CompressionAlgorithm("").Validate()) require.Error(t, contour_v1alpha1.CompressionAlgorithm("foo").Validate()) + require.NoError(t, contour_v1alpha1.CompressionAlgorithm("").Validate()) require.NoError(t, contour_v1alpha1.BrotliCompression.Validate()) require.NoError(t, contour_v1alpha1.DisabledCompression.Validate()) require.NoError(t, contour_v1alpha1.GzipCompression.Validate()) diff --git a/pkg/config/parameters.go b/pkg/config/parameters.go index 174a5077dd0..7c9e0360364 100644 --- a/pkg/config/parameters.go +++ b/pkg/config/parameters.go @@ -1027,10 +1027,8 @@ func (p *Parameters) Validate() error { return err } - if p.Compression.Algorithm != "" { - if err := p.Compression.Validate(); err != nil { - return err - } + if err := p.Compression.Validate(); err != nil { + return err } if err := p.TLS.Validate(); err != nil { diff --git a/pkg/config/parameters_test.go b/pkg/config/parameters_test.go index f83f112f2c3..5b4bc717417 100644 --- a/pkg/config/parameters_test.go +++ b/pkg/config/parameters_test.go @@ -326,6 +326,7 @@ func TestTLSParametersValidation(t *testing.T) { } func TestCompressionValidation(t *testing.T) { + require.NoError(t, CompressionParameters{""}.Validate()) require.NoError(t, CompressionParameters{CompressionBrotli}.Validate()) require.NoError(t, CompressionParameters{CompressionDisabled}.Validate()) require.NoError(t, CompressionParameters{CompressionGzip}.Validate()) From 1a6465f38da9b0563ff708187bdfe9bcb99a6581 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Tue, 26 Nov 2024 16:57:39 +0000 Subject: [PATCH 28/30] update configuration docs per new types Signed-off-by: Geoff Macartney --- site/content/docs/main/configuration.md | 71 ++++++++++++++----------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/site/content/docs/main/configuration.md b/site/content/docs/main/configuration.md index 8e2a3e168c4..a914ffeba65 100644 --- a/site/content/docs/main/configuration.md +++ b/site/content/docs/main/configuration.md @@ -72,38 +72,38 @@ The Contour configuration file is optional. In its absence, Contour will operate with reasonable defaults. Where Contour settings can also be specified with command-line flags, the command-line value takes precedence over the configuration file. -| Field Name | Type | Default | Description | -|----------------------------|------------------------|------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| accesslog-format | string | `envoy` | This key sets the global [access log format][2] for Envoy. Valid options are `envoy` or `json`. | -| accesslog-format-string | string | None | If present, this specifies custom access log format for Envoy. See [Envoy documentation](https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage) for more information about the syntax. This field only has effect if `accesslog-format` is `envoy` | -| accesslog-level | string | `info` | This field specifies the verbosity level of the access log. Valid options are `info` (default, all requests are logged), `error` (all non-success, i.e. 300+ response code, requests are logged), `critical` (all server error, i.e. 500+ response code, requests are logged) and `disabled`. | -| debug | boolean | `false` | Enables debug logging. | -| default-http-versions | string array | HTTP/1.1
HTTP/2 | This array specifies the HTTP versions that Contour should program Envoy to serve. HTTP versions are specified as strings of the form "HTTP/x", where "x" represents the version number. | -| disableAllowChunkedLength | boolean | `false` | If this field is true, Contour will disable the RFC-compliant Envoy behavior to strip the `Content-Length` header if `Transfer-Encoding: chunked` is also set. This is an emergency off-switch to revert back to Envoy's default behavior in case of failures. | -| compression | string | `gzip` | Sets the compression type applied in the compression HTTP filter of the default Listener filters. Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response. Values:`gzip` (default), `brotli`, `zstd`, `disabled`. | -| disableMergeSlashes | boolean | `false` | This field disables Envoy's non-standard merge_slashes path transformation behavior that strips duplicate slashes from request URL paths. | -| serverHeaderTransformation | string | `overwrite` | This field defines the action to be applied to the Server header on the response path. Values: `overwrite` (default), `append_if_absent`, `pass_through` | -| disablePermitInsecure | boolean | `false` | If this field is true, Contour will ignore `PermitInsecure` field in HTTPProxy documents. | -| envoy-service-name | string | `envoy` | This sets the service name that will be inspected for address details to be applied to Ingress objects. | -| envoy-service-namespace | string | `projectcontour` | This sets the namespace of the service that will be inspected for address details to be applied to Ingress objects. If the `CONTOUR_NAMESPACE` environment variable is present, Contour will populate this field with its value. | -| ingress-status-address | string | None | If present, this specifies the address that will be copied into the Ingress status for each Ingress that Contour manages. It is exclusive with `envoy-service-name` and `envoy-service-namespace`. | -| incluster | boolean | `false` | This field specifies that Contour is running in a Kubernetes cluster and should use the in-cluster client access configuration. | -| json-fields | string array | [fields][5] | This is the list the field names to include in the JSON [access log format][2]. This field only has effect if `accesslog-format` is `json`. | -| kubeconfig | string | `$HOME/.kube/config` | Path to a Kubernetes [kubeconfig file][3] for when Contour is executed outside a cluster. | -| kubernetesClientQPS | float32 | | QPS allowed for the Kubernetes client. | -| kubernetesClientBurst | int | | Burst allowed for the Kubernetes client. | -| policy | PolicyConfig | | The default [policy configuration](#policy-configuration). | -| tls | TLS | | The default [TLS configuration](#tls-configuration). | -| timeouts | TimeoutConfig | | The [timeout configuration](#timeout-configuration). | -| cluster | ClusterConfig | | The [cluster configuration](#cluster-configuration). | -| network | NetworkConfig | | The [network configuration](#network-configuration). | -| listener | ListenerConfig | | The [listener configuration](#listener-configuration). | -| server | ServerConfig | | The [server configuration](#server-configuration) for `contour serve` command. | -| gateway | GatewayConfig | | The [gateway-api Gateway configuration](#gateway-configuration). | -| rateLimitService | RateLimitServiceConfig | | The [rate limit service configuration](#rate-limit-service-configuration). | -| enableExternalNameService | boolean | `false` | Enable ExternalName Service processing. Enabling this has security implications. Please see the [advisory](https://github.com/projectcontour/contour/security/advisories/GHSA-5ph6-qq5x-7jwc) for more details. | -| metrics | MetricsParameters | | The [metrics configuration](#metrics-configuration) | -| featureFlags | string array | `[]` | Defines the toggle to enable new contour features. Available toggles are:
1. `useEndpointSlices` - configures contour to fetch endpoint data from k8s endpoint slices. | +| Field Name | Type | Default | Description | +|----------------------------|------------------------|------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| accesslog-format | string | `envoy` | This key sets the global [access log format][2] for Envoy. Valid options are `envoy` or `json`. | +| accesslog-format-string | string | None | If present, this specifies custom access log format for Envoy. See [Envoy documentation](https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage) for more information about the syntax. This field only has effect if `accesslog-format` is `envoy` | +| accesslog-level | string | `info` | This field specifies the verbosity level of the access log. Valid options are `info` (default, all requests are logged), `error` (all non-success, i.e. 300+ response code, requests are logged), `critical` (all server error, i.e. 500+ response code, requests are logged) and `disabled`. | +| debug | boolean | `false` | Enables debug logging. | +| default-http-versions | string array | HTTP/1.1
HTTP/2 | This array specifies the HTTP versions that Contour should program Envoy to serve. HTTP versions are specified as strings of the form "HTTP/x", where "x" represents the version number. | +| disableAllowChunkedLength | boolean | `false` | If this field is true, Contour will disable the RFC-compliant Envoy behavior to strip the `Content-Length` header if `Transfer-Encoding: chunked` is also set. This is an emergency off-switch to revert back to Envoy's default behavior in case of failures. | +| compression | CompressionParameters | | Sets the compression configuration applied in the compression HTTP filter of the default Listener filters. | +| disableMergeSlashes | boolean | `false` | This field disables Envoy's non-standard merge_slashes path transformation behavior that strips duplicate slashes from request URL paths. | +| serverHeaderTransformation | string | `overwrite` | This field defines the action to be applied to the Server header on the response path. Values: `overwrite` (default), `append_if_absent`, `pass_through` | +| disablePermitInsecure | boolean | `false` | If this field is true, Contour will ignore `PermitInsecure` field in HTTPProxy documents. | +| envoy-service-name | string | `envoy` | This sets the service name that will be inspected for address details to be applied to Ingress objects. | +| envoy-service-namespace | string | `projectcontour` | This sets the namespace of the service that will be inspected for address details to be applied to Ingress objects. If the `CONTOUR_NAMESPACE` environment variable is present, Contour will populate this field with its value. | +| ingress-status-address | string | None | If present, this specifies the address that will be copied into the Ingress status for each Ingress that Contour manages. It is exclusive with `envoy-service-name` and `envoy-service-namespace`. | +| incluster | boolean | `false` | This field specifies that Contour is running in a Kubernetes cluster and should use the in-cluster client access configuration. | +| json-fields | string array | [fields][5] | This is the list the field names to include in the JSON [access log format][2]. This field only has effect if `accesslog-format` is `json`. | +| kubeconfig | string | `$HOME/.kube/config` | Path to a Kubernetes [kubeconfig file][3] for when Contour is executed outside a cluster. | +| kubernetesClientQPS | float32 | | QPS allowed for the Kubernetes client. | +| kubernetesClientBurst | int | | Burst allowed for the Kubernetes client. | +| policy | PolicyConfig | | The default [policy configuration](#policy-configuration). | +| tls | TLS | | The default [TLS configuration](#tls-configuration). | +| timeouts | TimeoutConfig | | The [timeout configuration](#timeout-configuration). | +| cluster | ClusterConfig | | The [cluster configuration](#cluster-configuration). | +| network | NetworkConfig | | The [network configuration](#network-configuration). | +| listener | ListenerConfig | | The [listener configuration](#listener-configuration). | +| server | ServerConfig | | The [server configuration](#server-configuration) for `contour serve` command. | +| gateway | GatewayConfig | | The [gateway-api Gateway configuration](#gateway-configuration). | +| rateLimitService | RateLimitServiceConfig | | The [rate limit service configuration](#rate-limit-service-configuration). | +| enableExternalNameService | boolean | `false` | Enable ExternalName Service processing. Enabling this has security implications. Please see the [advisory](https://github.com/projectcontour/contour/security/advisories/GHSA-5ph6-qq5x-7jwc) for more details. | +| metrics | MetricsParameters | | The [metrics configuration](#metrics-configuration) | +| featureFlags | string array | `[]` | Defines the toggle to enable new contour features. Available toggles are:
1. `useEndpointSlices` - configures contour to fetch endpoint data from k8s endpoint slices. | ### TLS Configuration @@ -302,6 +302,13 @@ Metrics and health endpoints cannot have the same port number when metrics are s | max-requests | int | 0 | The maximum parallel requests a single Envoy instance allows to the Kubernetes Service; defaults to 1024 | | max-retries | int | 0 | The maximum number of parallel retries a single Envoy instance allows to the Kubernetes Service; defaults to 3. This setting only makes sense if the cluster is configured to do retries.| +### Compression Parameters + +| Field Name | Type | Default | Description | +|------------|--------|--------|-------------------------| +| algorithm | string | "gzip" | Compression algorithm. Setting this to `disabled` will make Envoy skip "Accept-Encoding: gzip,deflate" request header and always return uncompressed response. Values:`gzip` (default), `brotli`, `zstd`, `disabled`. | + + ### Configuration Example The following is an example ConfigMap with configuration file included: From 43f6598e64d2be399eae7812f20823850cda4761 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Wed, 27 Nov 2024 14:10:07 +0000 Subject: [PATCH 29/30] lint Signed-off-by: Geoff Macartney --- cmd/contour/servecontext_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/contour/servecontext_test.go b/cmd/contour/servecontext_test.go index 644edc6d68e..ce7665ef4d2 100644 --- a/cmd/contour/servecontext_test.go +++ b/cmd/contour/servecontext_test.go @@ -507,7 +507,6 @@ func defaultContourConfiguration() contour_v1alpha1.ContourConfigurationSpec { } func TestConvertServeContext(t *testing.T) { - cases := map[string]struct { getServeContext func(ctx *serveContext) *serveContext getContourConfiguration func(cfg contour_v1alpha1.ContourConfigurationSpec) contour_v1alpha1.ContourConfigurationSpec From 2f5e15730ff1b54fb204446d8fecd31f519f5eb0 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Thu, 5 Dec 2024 09:25:12 +0000 Subject: [PATCH 30/30] rename builder method for clarity a better name is SetDefaultFilterCompression Signed-off-by: Geoff Macartney --- internal/envoy/v3/listener.go | 4 +++- internal/featuretests/v3/compression_test.go | 2 +- internal/xdscache/v3/listener.go | 6 +++--- internal/xdscache/v3/listener_test.go | 10 +++++----- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/internal/envoy/v3/listener.go b/internal/envoy/v3/listener.go index 5b15021d4da..da152e4f225 100644 --- a/internal/envoy/v3/listener.go +++ b/internal/envoy/v3/listener.go @@ -275,7 +275,9 @@ func (b *httpConnectionManagerBuilder) MergeSlashes(enabled bool) *httpConnectio return b } -func (b *httpConnectionManagerBuilder) Compression(compressor *contour_v1alpha1.EnvoyCompression) *httpConnectionManagerBuilder { +// SetDefaultFilterCompression configures the builder to set the compression method applied by DefaultFilters() to the +// given value `compressor`. When chaining builder method calls, this method should be called before DefaultFilters(). +func (b *httpConnectionManagerBuilder) SetDefaultFilterCompression(compressor *contour_v1alpha1.EnvoyCompression) *httpConnectionManagerBuilder { b.compression = compressor return b } diff --git a/internal/featuretests/v3/compression_test.go b/internal/featuretests/v3/compression_test.go index b374ed92e1c..9b1cf7cf53e 100644 --- a/internal/featuretests/v3/compression_test.go +++ b/internal/featuretests/v3/compression_test.go @@ -76,7 +76,7 @@ func TestCompression(t *testing.T) { rh.OnAdd(hp1) httpListener := defaultHTTPListener() httpListener.FilterChains = envoy_v3.FilterChains(envoy_v3.HTTPConnectionManagerBuilder(). - Compression(&contour_v1alpha1.EnvoyCompression{ + SetDefaultFilterCompression(&contour_v1alpha1.EnvoyCompression{ Algorithm: tc.want, }). RouteConfigName(xdscache_v3.ENVOY_HTTP_LISTENER). diff --git a/internal/xdscache/v3/listener.go b/internal/xdscache/v3/listener.go index b053493861d..9b19e3d5e92 100644 --- a/internal/xdscache/v3/listener.go +++ b/internal/xdscache/v3/listener.go @@ -396,7 +396,7 @@ func (c *ListenerCache) OnChange(root *dag.DAG) { // order for the HTTPS virtualhosts. if len(listener.VirtualHosts) > 0 { cm := envoy_v3.HTTPConnectionManagerBuilder(). - Compression(cfg.Compression). + SetDefaultFilterCompression(cfg.Compression). Codec(envoy_v3.CodecForVersions(cfg.DefaultHTTPVersions...)). DefaultFilters(). RouteConfigName(httpRouteConfigName(listener)). @@ -469,7 +469,7 @@ func (c *ListenerCache) OnChange(root *dag.DAG) { // Contour versions since the metrics prefix will be // coded into monitoring dashboards. cm := envoy_v3.HTTPConnectionManagerBuilder(). - Compression(cfg.Compression). + SetDefaultFilterCompression(cfg.Compression). Codec(envoy_v3.CodecForVersions(cfg.DefaultHTTPVersions...)). AddFilter(envoy_v3.FilterMisdirectedRequests(vh.VirtualHost.Name)). DefaultFilters(). @@ -554,7 +554,7 @@ func (c *ListenerCache) OnChange(root *dag.DAG) { } cm := envoy_v3.HTTPConnectionManagerBuilder(). - Compression(cfg.Compression). + SetDefaultFilterCompression(cfg.Compression). DefaultFilters(). AddFilter(authzFilter). RouteConfigName(fallbackCertRouteConfigName(listener)). diff --git a/internal/xdscache/v3/listener_test.go b/internal/xdscache/v3/listener_test.go index c4f464ef8c4..63c80d54cdb 100644 --- a/internal/xdscache/v3/listener_test.go +++ b/internal/xdscache/v3/listener_test.go @@ -3108,7 +3108,7 @@ func TestListenerVisit(t *testing.T) { Address: envoy_v3.SocketAddress("0.0.0.0", 8080), FilterChains: envoy_v3.FilterChains( envoy_v3.HTTPConnectionManagerBuilder(). - Compression(&contour_v1alpha1.EnvoyCompression{ + SetDefaultFilterCompression(&contour_v1alpha1.EnvoyCompression{ Algorithm: contour_v1alpha1.DisabledCompression, }). RouteConfigName(ENVOY_HTTP_LISTENER). @@ -3154,7 +3154,7 @@ func TestListenerVisit(t *testing.T) { Address: envoy_v3.SocketAddress("0.0.0.0", 8080), FilterChains: envoy_v3.FilterChains( envoy_v3.HTTPConnectionManagerBuilder(). - Compression(&contour_v1alpha1.EnvoyCompression{ + SetDefaultFilterCompression(&contour_v1alpha1.EnvoyCompression{ Algorithm: contour_v1alpha1.GzipCompression, }). RouteConfigName(ENVOY_HTTP_LISTENER). @@ -3200,7 +3200,7 @@ func TestListenerVisit(t *testing.T) { Address: envoy_v3.SocketAddress("0.0.0.0", 8080), FilterChains: envoy_v3.FilterChains( envoy_v3.HTTPConnectionManagerBuilder(). - Compression(&contour_v1alpha1.EnvoyCompression{ + SetDefaultFilterCompression(&contour_v1alpha1.EnvoyCompression{ Algorithm: contour_v1alpha1.BrotliCompression, }). RouteConfigName(ENVOY_HTTP_LISTENER). @@ -3246,7 +3246,7 @@ func TestListenerVisit(t *testing.T) { Address: envoy_v3.SocketAddress("0.0.0.0", 8080), FilterChains: envoy_v3.FilterChains( envoy_v3.HTTPConnectionManagerBuilder(). - Compression(&contour_v1alpha1.EnvoyCompression{ + SetDefaultFilterCompression(&contour_v1alpha1.EnvoyCompression{ Algorithm: contour_v1alpha1.ZstdCompression, }). RouteConfigName(ENVOY_HTTP_LISTENER). @@ -3292,7 +3292,7 @@ func TestListenerVisit(t *testing.T) { Address: envoy_v3.SocketAddress("0.0.0.0", 8080), FilterChains: envoy_v3.FilterChains( envoy_v3.HTTPConnectionManagerBuilder(). - Compression(&contour_v1alpha1.EnvoyCompression{ + SetDefaultFilterCompression(&contour_v1alpha1.EnvoyCompression{ Algorithm: contour_v1alpha1.GzipCompression, }). RouteConfigName(ENVOY_HTTP_LISTENER).