diff --git a/apis/projectcontour/v1/httpproxy.go b/apis/projectcontour/v1/httpproxy.go index 8e407a02b7c..82a92ac5eff 100644 --- a/apis/projectcontour/v1/httpproxy.go +++ b/apis/projectcontour/v1/httpproxy.go @@ -1142,6 +1142,12 @@ type TimeoutPolicy struct { // +optional // +kubebuilder:validation:Pattern=`^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$` IdleConnection string `json:"idleConnection,omitempty"` + + // Maximum allowed duration a streaming request can run for. + // If not supplied, the global setting is used. + // +optional + // +kubebuilder:validation:Pattern=`^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$` + MaxStreamDuration string `json:"maxStreamDuration,omitempty"` } // RetryOn is a string type alias with validation to ensure that the value is valid. diff --git a/apis/projectcontour/v1alpha1/contourconfig.go b/apis/projectcontour/v1alpha1/contourconfig.go index 0c193b0641f..70a402ed2d9 100644 --- a/apis/projectcontour/v1alpha1/contourconfig.go +++ b/apis/projectcontour/v1alpha1/contourconfig.go @@ -585,6 +585,15 @@ type TimeoutParameters struct { // +optional MaxConnectionDuration *string `json:"maxConnectionDuration,omitempty"` + // MaxStreamDuration defines the maximum duration a HTTP stream is kept alive. + // The stream will be reset if the time limit is reached. Omit or set to "infinity" for + // no max duration. + // + // See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-stream-duration + // for more information. + // +optional + MaxStreamDuration *string `json:"maxStreamDuration,omitempty"` + // DelayedCloseTimeout defines how long envoy will wait, once connection // close processing has been initiated, for the downstream peer to close // the connection before Envoy closes the socket associated with the connection. diff --git a/apis/projectcontour/v1alpha1/zz_generated.deepcopy.go b/apis/projectcontour/v1alpha1/zz_generated.deepcopy.go index ba974b98aa0..aa2fb24911c 100644 --- a/apis/projectcontour/v1alpha1/zz_generated.deepcopy.go +++ b/apis/projectcontour/v1alpha1/zz_generated.deepcopy.go @@ -1264,6 +1264,11 @@ func (in *TimeoutParameters) DeepCopyInto(out *TimeoutParameters) { *out = new(string) **out = **in } + if in.MaxStreamDuration != nil { + in, out := &in.MaxStreamDuration, &out.MaxStreamDuration + *out = new(string) + **out = **in + } if in.DelayedCloseTimeout != nil { in, out := &in.DelayedCloseTimeout, &out.DelayedCloseTimeout *out = new(string) diff --git a/changelogs/unreleased/6895-nickburgin-small.md b/changelogs/unreleased/6895-nickburgin-small.md new file mode 100644 index 00000000000..c548e3e471c --- /dev/null +++ b/changelogs/unreleased/6895-nickburgin-small.md @@ -0,0 +1 @@ +Add support for Envoys MaxStreamDuration setting Globally and on Routes diff --git a/cmd/contour/servecontext.go b/cmd/contour/servecontext.go index 64bae0a281a..fcae2c32579 100644 --- a/cmd/contour/servecontext.go +++ b/cmd/contour/servecontext.go @@ -358,6 +358,9 @@ func (ctx *serveContext) convertToContourConfigurationSpec() contour_v1alpha1.Co if len(ctx.Config.Timeouts.MaxConnectionDuration) > 0 { timeoutParams.MaxConnectionDuration = ptr.To(ctx.Config.Timeouts.MaxConnectionDuration) } + if len(ctx.Config.Timeouts.MaxStreamDuration) > 0 { + timeoutParams.MaxStreamDuration = ptr.To(ctx.Config.Timeouts.MaxStreamDuration) + } if len(ctx.Config.Timeouts.DelayedCloseTimeout) > 0 { timeoutParams.DelayedCloseTimeout = ptr.To(ctx.Config.Timeouts.DelayedCloseTimeout) } diff --git a/cmd/contour/servecontext_test.go b/cmd/contour/servecontext_test.go index 852cc3f6cdd..9f5c42ad834 100644 --- a/cmd/contour/servecontext_test.go +++ b/cmd/contour/servecontext_test.go @@ -686,6 +686,34 @@ func TestConvertServeContext(t *testing.T) { return cfg }, }, + "timeout parameters": { + getServeContext: func(ctx *serveContext) *serveContext { + ctx.Config.Timeouts = config.TimeoutParameters{ + RequestTimeout: "1", + ConnectionIdleTimeout: "2", + StreamIdleTimeout: "3", + MaxConnectionDuration: "4", + MaxStreamDuration: "5", + DelayedCloseTimeout: "6", + ConnectionShutdownGracePeriod: "7", + ConnectTimeout: "8", + } + return ctx + }, + getContourConfiguration: func(cfg contour_v1alpha1.ContourConfigurationSpec) contour_v1alpha1.ContourConfigurationSpec { + cfg.Envoy.Timeouts = &contour_v1alpha1.TimeoutParameters{ + RequestTimeout: ptr.To("1"), + ConnectionIdleTimeout: ptr.To("2"), + StreamIdleTimeout: ptr.To("3"), + MaxConnectionDuration: ptr.To("4"), + MaxStreamDuration: ptr.To("5"), + DelayedCloseTimeout: ptr.To("6"), + ConnectionShutdownGracePeriod: ptr.To("7"), + ConnectTimeout: ptr.To("8"), + } + return cfg + }, + }, "access log": { getServeContext: func(ctx *serveContext) *serveContext { ctx.Config.AccessLogFormat = config.JSONAccessLog diff --git a/examples/contour/01-crds.yaml b/examples/contour/01-crds.yaml index 2bd91065cd6..1c4b55fd9ab 100644 --- a/examples/contour/01-crds.yaml +++ b/examples/contour/01-crds.yaml @@ -583,6 +583,14 @@ spec: See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-connection-duration for more information. type: string + maxStreamDuration: + description: |- + MaxStreamDuration defines the maximum duration a HTTP stream is kept alive. + The stream will be reset if the time limit is reached. Omit or set to "infinity" for + no max duration. + See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-stream-duration + for more information. + type: string requestTimeout: description: |- RequestTimeout sets the client request timeout globally for Contour. Note that @@ -4399,6 +4407,14 @@ spec: See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-connection-duration for more information. type: string + maxStreamDuration: + description: |- + MaxStreamDuration defines the maximum duration a HTTP stream is kept alive. + The stream will be reset if the time limit is reached. Omit or set to "infinity" for + no max duration. + See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-stream-duration + for more information. + type: string requestTimeout: description: |- RequestTimeout sets the client request timeout globally for Contour. Note that @@ -5274,6 +5290,12 @@ spec: If not supplied, Envoy's default value of 1h applies. pattern: ^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$ type: string + maxStreamDuration: + description: |- + Maximum allowed duration a streaming request can run for. + If not supplied, the global setting is used. + pattern: ^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$ + type: string response: description: |- Timeout for receiving a response from the server after processing a request from client. @@ -7021,6 +7043,12 @@ spec: If not supplied, Envoy's default value of 1h applies. pattern: ^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$ type: string + maxStreamDuration: + description: |- + Maximum allowed duration a streaming request can run for. + If not supplied, the global setting is used. + pattern: ^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$ + type: string response: description: |- Timeout for receiving a response from the server after processing a request from client. diff --git a/examples/render/contour-deployment.yaml b/examples/render/contour-deployment.yaml index 3a979fa3881..cd0d9c307f6 100644 --- a/examples/render/contour-deployment.yaml +++ b/examples/render/contour-deployment.yaml @@ -798,6 +798,14 @@ spec: See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-connection-duration for more information. type: string + maxStreamDuration: + description: |- + MaxStreamDuration defines the maximum duration a HTTP stream is kept alive. + The stream will be reset if the time limit is reached. Omit or set to "infinity" for + no max duration. + See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-stream-duration + for more information. + type: string requestTimeout: description: |- RequestTimeout sets the client request timeout globally for Contour. Note that @@ -4614,6 +4622,14 @@ spec: See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-connection-duration for more information. type: string + maxStreamDuration: + description: |- + MaxStreamDuration defines the maximum duration a HTTP stream is kept alive. + The stream will be reset if the time limit is reached. Omit or set to "infinity" for + no max duration. + See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-stream-duration + for more information. + type: string requestTimeout: description: |- RequestTimeout sets the client request timeout globally for Contour. Note that @@ -5489,6 +5505,12 @@ spec: If not supplied, Envoy's default value of 1h applies. pattern: ^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$ type: string + maxStreamDuration: + description: |- + Maximum allowed duration a streaming request can run for. + If not supplied, the global setting is used. + pattern: ^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$ + type: string response: description: |- Timeout for receiving a response from the server after processing a request from client. @@ -7236,6 +7258,12 @@ spec: If not supplied, Envoy's default value of 1h applies. pattern: ^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$ type: string + maxStreamDuration: + description: |- + Maximum allowed duration a streaming request can run for. + If not supplied, the global setting is used. + pattern: ^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$ + type: string response: description: |- Timeout for receiving a response from the server after processing a request from client. diff --git a/examples/render/contour-gateway-provisioner.yaml b/examples/render/contour-gateway-provisioner.yaml index 579495e6aa9..0600df47870 100644 --- a/examples/render/contour-gateway-provisioner.yaml +++ b/examples/render/contour-gateway-provisioner.yaml @@ -594,6 +594,14 @@ spec: See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-connection-duration for more information. type: string + maxStreamDuration: + description: |- + MaxStreamDuration defines the maximum duration a HTTP stream is kept alive. + The stream will be reset if the time limit is reached. Omit or set to "infinity" for + no max duration. + See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-stream-duration + for more information. + type: string requestTimeout: description: |- RequestTimeout sets the client request timeout globally for Contour. Note that @@ -4410,6 +4418,14 @@ spec: See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-connection-duration for more information. type: string + maxStreamDuration: + description: |- + MaxStreamDuration defines the maximum duration a HTTP stream is kept alive. + The stream will be reset if the time limit is reached. Omit or set to "infinity" for + no max duration. + See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-stream-duration + for more information. + type: string requestTimeout: description: |- RequestTimeout sets the client request timeout globally for Contour. Note that @@ -5285,6 +5301,12 @@ spec: If not supplied, Envoy's default value of 1h applies. pattern: ^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$ type: string + maxStreamDuration: + description: |- + Maximum allowed duration a streaming request can run for. + If not supplied, the global setting is used. + pattern: ^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$ + type: string response: description: |- Timeout for receiving a response from the server after processing a request from client. @@ -7032,6 +7054,12 @@ spec: If not supplied, Envoy's default value of 1h applies. pattern: ^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$ type: string + maxStreamDuration: + description: |- + Maximum allowed duration a streaming request can run for. + If not supplied, the global setting is used. + pattern: ^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$ + type: string response: description: |- Timeout for receiving a response from the server after processing a request from client. diff --git a/examples/render/contour-gateway.yaml b/examples/render/contour-gateway.yaml index b270884aaa0..40c4870e75d 100644 --- a/examples/render/contour-gateway.yaml +++ b/examples/render/contour-gateway.yaml @@ -619,6 +619,14 @@ spec: See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-connection-duration for more information. type: string + maxStreamDuration: + description: |- + MaxStreamDuration defines the maximum duration a HTTP stream is kept alive. + The stream will be reset if the time limit is reached. Omit or set to "infinity" for + no max duration. + See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-stream-duration + for more information. + type: string requestTimeout: description: |- RequestTimeout sets the client request timeout globally for Contour. Note that @@ -4435,6 +4443,14 @@ spec: See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-connection-duration for more information. type: string + maxStreamDuration: + description: |- + MaxStreamDuration defines the maximum duration a HTTP stream is kept alive. + The stream will be reset if the time limit is reached. Omit or set to "infinity" for + no max duration. + See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-stream-duration + for more information. + type: string requestTimeout: description: |- RequestTimeout sets the client request timeout globally for Contour. Note that @@ -5310,6 +5326,12 @@ spec: If not supplied, Envoy's default value of 1h applies. pattern: ^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$ type: string + maxStreamDuration: + description: |- + Maximum allowed duration a streaming request can run for. + If not supplied, the global setting is used. + pattern: ^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$ + type: string response: description: |- Timeout for receiving a response from the server after processing a request from client. @@ -7057,6 +7079,12 @@ spec: If not supplied, Envoy's default value of 1h applies. pattern: ^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$ type: string + maxStreamDuration: + description: |- + Maximum allowed duration a streaming request can run for. + If not supplied, the global setting is used. + pattern: ^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$ + type: string response: description: |- Timeout for receiving a response from the server after processing a request from client. diff --git a/examples/render/contour.yaml b/examples/render/contour.yaml index 86a2caf02e8..48b5196e4a9 100644 --- a/examples/render/contour.yaml +++ b/examples/render/contour.yaml @@ -798,6 +798,14 @@ spec: See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-connection-duration for more information. type: string + maxStreamDuration: + description: |- + MaxStreamDuration defines the maximum duration a HTTP stream is kept alive. + The stream will be reset if the time limit is reached. Omit or set to "infinity" for + no max duration. + See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-stream-duration + for more information. + type: string requestTimeout: description: |- RequestTimeout sets the client request timeout globally for Contour. Note that @@ -4614,6 +4622,14 @@ spec: See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-connection-duration for more information. type: string + maxStreamDuration: + description: |- + MaxStreamDuration defines the maximum duration a HTTP stream is kept alive. + The stream will be reset if the time limit is reached. Omit or set to "infinity" for + no max duration. + See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-stream-duration + for more information. + type: string requestTimeout: description: |- RequestTimeout sets the client request timeout globally for Contour. Note that @@ -5489,6 +5505,12 @@ spec: If not supplied, Envoy's default value of 1h applies. pattern: ^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$ type: string + maxStreamDuration: + description: |- + Maximum allowed duration a streaming request can run for. + If not supplied, the global setting is used. + pattern: ^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$ + type: string response: description: |- Timeout for receiving a response from the server after processing a request from client. @@ -7236,6 +7258,12 @@ spec: If not supplied, Envoy's default value of 1h applies. pattern: ^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$ type: string + maxStreamDuration: + description: |- + Maximum allowed duration a streaming request can run for. + If not supplied, the global setting is used. + pattern: ^(((\d*(\.\d*)?h)|(\d*(\.\d*)?m)|(\d*(\.\d*)?s)|(\d*(\.\d*)?ms)|(\d*(\.\d*)?us)|(\d*(\.\d*)?µs)|(\d*(\.\d*)?ns))+|infinity|infinite)$ + type: string response: description: |- Timeout for receiving a response from the server after processing a request from client. diff --git a/internal/contourconfig/contourconfiguration.go b/internal/contourconfig/contourconfiguration.go index 44539247e0f..7c7a2879974 100644 --- a/internal/contourconfig/contourconfiguration.go +++ b/internal/contourconfig/contourconfiguration.go @@ -114,6 +114,7 @@ func Defaults() contour_v1alpha1.ContourConfigurationSpec { ConnectionIdleTimeout: nil, StreamIdleTimeout: nil, MaxConnectionDuration: nil, + MaxStreamDuration: nil, DelayedCloseTimeout: nil, ConnectionShutdownGracePeriod: nil, ConnectTimeout: nil, @@ -157,6 +158,7 @@ type Timeouts struct { ConnectionIdle timeout.Setting StreamIdle timeout.Setting MaxConnectionDuration timeout.Setting + MaxStreamDuration timeout.Setting DelayedClose timeout.Setting ConnectionShutdownGracePeriod timeout.Setting ConnectTimeout time.Duration // Since "infinite" is not valid ConnectTimeout value, use time.Duration instead of timeout.Setting. @@ -196,6 +198,12 @@ func ParseTimeoutPolicy(timeoutParameters *contour_v1alpha1.TimeoutParameters) ( return Timeouts{}, fmt.Errorf("failed to parse max connection duration: %s", err) } } + if timeoutParameters.MaxStreamDuration != nil { + timeouts.MaxStreamDuration, err = timeout.Parse(*timeoutParameters.MaxStreamDuration) + if err != nil { + return Timeouts{}, fmt.Errorf("failed to parse max stream duration: %s", err) + } + } if timeoutParameters.DelayedCloseTimeout != nil { timeouts.DelayedClose, err = timeout.Parse(*timeoutParameters.DelayedCloseTimeout) if err != nil { diff --git a/internal/contourconfig/contourconfiguration_test.go b/internal/contourconfig/contourconfiguration_test.go index 8b7c6fb6495..6e8139cb84c 100644 --- a/internal/contourconfig/contourconfiguration_test.go +++ b/internal/contourconfig/contourconfiguration_test.go @@ -115,9 +115,10 @@ func TestOverlayOnDefaults(t *testing.T) { ConnectionIdleTimeout: ptr.To("2s"), StreamIdleTimeout: ptr.To("3s"), MaxConnectionDuration: ptr.To("4s"), - DelayedCloseTimeout: ptr.To("5s"), - ConnectionShutdownGracePeriod: ptr.To("6s"), - ConnectTimeout: ptr.To("7s"), + MaxStreamDuration: ptr.To("5s"), + DelayedCloseTimeout: ptr.To("6s"), + ConnectionShutdownGracePeriod: ptr.To("7s"), + ConnectTimeout: ptr.To("8s"), }, Cluster: &contour_v1alpha1.ClusterParameters{ DNSLookupFamily: contour_v1alpha1.IPv4ClusterDNSFamily, @@ -244,6 +245,7 @@ func TestParseTimeoutPolicy(t *testing.T) { ConnectionIdle: timeout.DefaultSetting(), StreamIdle: timeout.DefaultSetting(), MaxConnectionDuration: timeout.DefaultSetting(), + MaxStreamDuration: timeout.DefaultSetting(), DelayedClose: timeout.DefaultSetting(), ConnectionShutdownGracePeriod: timeout.DefaultSetting(), ConnectTimeout: 0, @@ -256,6 +258,7 @@ func TestParseTimeoutPolicy(t *testing.T) { ConnectionIdle: timeout.DefaultSetting(), StreamIdle: timeout.DefaultSetting(), MaxConnectionDuration: timeout.DefaultSetting(), + MaxStreamDuration: timeout.DefaultSetting(), DelayedClose: timeout.DefaultSetting(), ConnectionShutdownGracePeriod: timeout.DefaultSetting(), ConnectTimeout: 0, @@ -267,6 +270,7 @@ func TestParseTimeoutPolicy(t *testing.T) { ConnectionIdleTimeout: ptr.To("2s"), StreamIdleTimeout: ptr.To("3s"), MaxConnectionDuration: ptr.To("infinity"), + MaxStreamDuration: ptr.To("infinity"), DelayedCloseTimeout: ptr.To("5s"), ConnectionShutdownGracePeriod: ptr.To("6s"), ConnectTimeout: ptr.To("8s"), @@ -276,6 +280,7 @@ func TestParseTimeoutPolicy(t *testing.T) { ConnectionIdle: timeout.DurationSetting(time.Second * 2), StreamIdle: timeout.DurationSetting(time.Second * 3), MaxConnectionDuration: timeout.DisabledSetting(), + MaxStreamDuration: timeout.DisabledSetting(), DelayedClose: timeout.DurationSetting(time.Second * 5), ConnectionShutdownGracePeriod: timeout.DurationSetting(time.Second * 6), ConnectTimeout: 8 * time.Second, @@ -305,6 +310,12 @@ func TestParseTimeoutPolicy(t *testing.T) { }, errorMsg: "failed to parse max connection duration", }, + "max stream duration invalid": { + config: &contour_v1alpha1.TimeoutParameters{ + MaxStreamDuration: ptr.To("xxx"), + }, + errorMsg: "failed to parse max stream duration", + }, "delayed close timeout invalid": { config: &contour_v1alpha1.TimeoutParameters{ DelayedCloseTimeout: ptr.To("xxx"), diff --git a/internal/dag/dag.go b/internal/dag/dag.go index 0e75755abfd..1bc4d390ac7 100644 --- a/internal/dag/dag.go +++ b/internal/dag/dag.go @@ -403,6 +403,11 @@ type RouteTimeoutPolicy struct { // IdleStreamTimeout is the timeout applied to idle connection during single request-response. // Stream is HTTP/2 and HTTP/3 concept, for HTTP/1 it refers to single request-response within connection. IdleStreamTimeout timeout.Setting + + // MaxStreamDuration is the maximum duration allowed for streams on the Route. + // If not set, the globally defined maximum stream duration will be used. + // If set to 0, the maximum will be disabled for this route. + MaxStreamDuration timeout.Setting } // ClusterTimeoutPolicy defines the timeout policy for a cluster. diff --git a/internal/dag/policy.go b/internal/dag/policy.go index fd94c1749c6..ca42b683ef2 100644 --- a/internal/dag/policy.go +++ b/internal/dag/policy.go @@ -452,6 +452,7 @@ func timeoutPolicy(tp *contour_v1.TimeoutPolicy, connectTimeout time.Duration) ( return RouteTimeoutPolicy{ ResponseTimeout: timeout.DefaultSetting(), IdleStreamTimeout: timeout.DefaultSetting(), + MaxStreamDuration: timeout.DefaultSetting(), }, ClusterTimeoutPolicy{ IdleConnectionTimeout: timeout.DefaultSetting(), ConnectTimeout: connectTimeout, @@ -474,9 +475,15 @@ func timeoutPolicy(tp *contour_v1.TimeoutPolicy, connectTimeout time.Duration) ( return RouteTimeoutPolicy{}, ClusterTimeoutPolicy{}, fmt.Errorf("error parsing idle connection timeout: %w", err) } + maxStreamDuration, err := timeout.Parse(tp.MaxStreamDuration) + if err != nil { + return RouteTimeoutPolicy{}, ClusterTimeoutPolicy{}, fmt.Errorf("error parsing max stream duration: %w", err) + } + return RouteTimeoutPolicy{ ResponseTimeout: responseTimeout, IdleStreamTimeout: idleStreamTimeout, + MaxStreamDuration: maxStreamDuration, }, ClusterTimeoutPolicy{ IdleConnectionTimeout: idleConnectionTimeout, ConnectTimeout: connectTimeout, diff --git a/internal/dag/policy_test.go b/internal/dag/policy_test.go index ab006db9b57..12a9120694c 100644 --- a/internal/dag/policy_test.go +++ b/internal/dag/policy_test.go @@ -241,6 +241,28 @@ func TestTimeoutPolicy(t *testing.T) { IdleStreamTimeout: timeout.DurationSetting(900 * time.Second), }, }, + "maximum stream duration": { + tp: &contour_v1.TimeoutPolicy{ + MaxStreamDuration: "5m", + }, + wantRouteTimeoutPolicy: RouteTimeoutPolicy{ + MaxStreamDuration: timeout.DurationSetting(5 * time.Minute), + }, + }, + "infinite maximum stream duration": { + tp: &contour_v1.TimeoutPolicy{ + MaxStreamDuration: "infinite", + }, + wantRouteTimeoutPolicy: RouteTimeoutPolicy{ + MaxStreamDuration: timeout.DisabledSetting(), + }, + }, + "invalid maximum stream duration": { + tp: &contour_v1.TimeoutPolicy{ + MaxStreamDuration: "invalid value", + }, + wantErr: true, + }, "idle connection timeout": { tp: &contour_v1.TimeoutPolicy{ IdleConnection: "900s", diff --git a/internal/envoy/v3/route.go b/internal/envoy/v3/route.go index 3bcc2297a38..16da1b66223 100644 --- a/internal/envoy/v3/route.go +++ b/internal/envoy/v3/route.go @@ -433,6 +433,12 @@ func routeRoute(r *dag.Route) *envoy_config_route_v3.Route_Route { } } + if !r.TimeoutPolicy.MaxStreamDuration.UseDefault() { + ra.MaxStreamDuration = &envoy_config_route_v3.RouteAction_MaxStreamDuration{ + MaxStreamDuration: envoy.Timeout(r.TimeoutPolicy.MaxStreamDuration), + } + } + if r.RateLimitPolicy != nil && r.RateLimitPolicy.Global != nil { ra.RateLimits = GlobalRateLimits(r.RateLimitPolicy.Global.Descriptors) } diff --git a/internal/envoy/v3/route_test.go b/internal/envoy/v3/route_test.go index b569a1e6a80..8c483e44af4 100644 --- a/internal/envoy/v3/route_test.go +++ b/internal/envoy/v3/route_test.go @@ -386,6 +386,42 @@ func TestRouteRoute(t *testing.T) { }, }, }, + "max stream duration 5m": { + route: &dag.Route{ + TimeoutPolicy: dag.RouteTimeoutPolicy{ + MaxStreamDuration: timeout.DurationSetting(5 * time.Minute), + }, + Clusters: []*dag.Cluster{c1}, + }, + want: &envoy_config_route_v3.Route_Route{ + Route: &envoy_config_route_v3.RouteAction{ + ClusterSpecifier: &envoy_config_route_v3.RouteAction_Cluster{ + Cluster: "default/kuard/8080/da39a3ee5e", + }, + MaxStreamDuration: &envoy_config_route_v3.RouteAction_MaxStreamDuration{ + MaxStreamDuration: durationpb.New(300 * time.Second), + }, + }, + }, + }, + "max stream duration infinity": { + route: &dag.Route{ + TimeoutPolicy: dag.RouteTimeoutPolicy{ + MaxStreamDuration: timeout.DisabledSetting(), + }, + Clusters: []*dag.Cluster{c1}, + }, + want: &envoy_config_route_v3.Route_Route{ + Route: &envoy_config_route_v3.RouteAction{ + ClusterSpecifier: &envoy_config_route_v3.RouteAction_Cluster{ + Cluster: "default/kuard/8080/da39a3ee5e", + }, + MaxStreamDuration: &envoy_config_route_v3.RouteAction_MaxStreamDuration{ + MaxStreamDuration: durationpb.New(0), + }, + }, + }, + }, "single service w/ a cookie hash policy (session affinity)": { route: &dag.Route{ Clusters: []*dag.Cluster{c2}, diff --git a/pkg/config/parameters.go b/pkg/config/parameters.go index e6fa67302d1..14f31034edf 100644 --- a/pkg/config/parameters.go +++ b/pkg/config/parameters.go @@ -266,6 +266,15 @@ type TimeoutParameters struct { // for more information. MaxConnectionDuration string `yaml:"max-connection-duration,omitempty"` + // MaxStreamDuration defines the maximum duration a HTTP stream is kept alive. + // The stream will be reset if the time limit is reached. Omit or set to "infinity" for + // no max duration. + // + // See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-stream-duration + // for more information. + // +optional + MaxStreamDuration string `yaml:"max-stream-duration,omitempty"` + // DelayedCloseTimeout defines how long envoy will wait, once connection // close processing has been initiated, for the downstream peer to close // the connection before Envoy closes the socket associated with the connection. @@ -326,6 +335,10 @@ func (t TimeoutParameters) Validate() error { return fmt.Errorf("max connection duration %q: %w", t.MaxConnectionDuration, err) } + if err := v(t.MaxStreamDuration); err != nil { + return fmt.Errorf("max stream duration %q: %w", t.MaxStreamDuration, err) + } + if err := v(t.DelayedCloseTimeout); err != nil { return fmt.Errorf("delayed close timeout %q: %w", t.DelayedCloseTimeout, err) } diff --git a/pkg/config/parameters_test.go b/pkg/config/parameters_test.go index 3580f0a36d4..2e6d906d36b 100644 --- a/pkg/config/parameters_test.go +++ b/pkg/config/parameters_test.go @@ -212,6 +212,7 @@ func TestValidateTimeoutParams(t *testing.T) { ConnectionIdleTimeout: "infinite", StreamIdleTimeout: "infinite", MaxConnectionDuration: "infinite", + MaxStreamDuration: "infinite", DelayedCloseTimeout: "infinite", ConnectionShutdownGracePeriod: "infinite", ConnectTimeout: "2s", @@ -221,6 +222,7 @@ func TestValidateTimeoutParams(t *testing.T) { ConnectionIdleTimeout: "infinity", StreamIdleTimeout: "infinity", MaxConnectionDuration: "infinity", + MaxStreamDuration: "infinity", DelayedCloseTimeout: "infinity", ConnectionShutdownGracePeriod: "infinity", ConnectTimeout: "2s", @@ -230,6 +232,7 @@ func TestValidateTimeoutParams(t *testing.T) { require.Error(t, TimeoutParameters{ConnectionIdleTimeout: "bar"}.Validate()) require.Error(t, TimeoutParameters{StreamIdleTimeout: "baz"}.Validate()) require.Error(t, TimeoutParameters{MaxConnectionDuration: "boop"}.Validate()) + require.Error(t, TimeoutParameters{MaxStreamDuration: "bleep"}.Validate()) require.Error(t, TimeoutParameters{DelayedCloseTimeout: "bebop"}.Validate()) require.Error(t, TimeoutParameters{ConnectionShutdownGracePeriod: "bong"}.Validate()) require.Error(t, TimeoutParameters{ConnectTimeout: "infinite"}.Validate()) diff --git a/site/content/docs/main/config/api-reference.html b/site/content/docs/main/config/api-reference.html index 4e858b99569..5bdf1b62c74 100644 --- a/site/content/docs/main/config/api-reference.html +++ b/site/content/docs/main/config/api-reference.html @@ -4696,6 +4696,20 @@

TimeoutPolicy If not supplied, Envoy’s default value of 1h applies.

+ + +maxStreamDuration +
+ +string + + + +(Optional) +

Maximum allowed duration a streaming request can run for. +If not supplied, the global setting is used.

+ +

UpstreamValidation @@ -8887,6 +8901,23 @@

TimeoutParameters +maxStreamDuration +
+ +string + + + +(Optional) +

MaxStreamDuration defines the maximum duration a HTTP stream is kept alive. +The stream will be reset if the time limit is reached. Omit or set to “infinity” for +no max duration.

+

See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-max-stream-duration +for more information.

+ + + + delayedCloseTimeout