Skip to content

Commit

Permalink
Adds "disableCompression" as a feature to turnon/off Envoy's GZIP res…
Browse files Browse the repository at this point in the history
…ponse compression

Signed-off-by: chaosbox <[email protected]>
  • Loading branch information
chaosbox committed Jul 9, 2024
1 parent b4d5b67 commit 081a47c
Show file tree
Hide file tree
Showing 17 changed files with 389 additions and 26 deletions.
6 changes: 6 additions & 0 deletions apis/projectcontour/v1alpha1/contourconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions cmd/contour/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions cmd/contour/servecontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions cmd/contour/servecontext_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
},
},
Expand Down
12 changes: 12 additions & 0 deletions examples/contour/01-crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions examples/render/contour-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions examples/render/contour-gateway-provisioner.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions examples/render/contour-gateway.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions examples/render/contour.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
62 changes: 36 additions & 26 deletions internal/envoy/v3/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ type httpConnectionManagerBuilder struct {
maxRequestsPerConnection *uint32
http2MaxConcurrentStreams *uint32
enableWebsockets bool
disableCompression bool
}

func (b *httpConnectionManagerBuilder) EnableWebsockets(enable bool) *httpConnectionManagerBuilder {
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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{
Expand Down
121 changes: 121 additions & 0 deletions internal/featuretests/v3/compression_test.go
Original file line number Diff line number Diff line change
@@ -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) {

Check failure on line 30 in internal/featuretests/v3/compression_test.go

View workflow job for this annotation

GitHub Actions / lint

unused-parameter: parameter 'conf' seems to be unused, consider removing or renaming it as _ (revive)
}

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),
})
}
Loading

0 comments on commit 081a47c

Please sign in to comment.