From ee8ebeea0bbdf390ae28e61d96bdf94dfd3940ae Mon Sep 17 00:00:00 2001
From: Nick Burgin
Date: Tue, 11 Feb 2025 16:38:18 +1100
Subject: [PATCH 1/2] configuration: Add support for Envoys MaxStreamDuration
configuration
Fixes #6873
Signed-off-by: Nick Burgin
---
apis/projectcontour/v1/httpproxy.go | 6 ++++
apis/projectcontour/v1alpha1/contourconfig.go | 9 +++++
.../v1alpha1/zz_generated.deepcopy.go | 5 +++
.../unreleased/6895-nickburgin-small.md | 1 +
cmd/contour/servecontext.go | 3 ++
examples/contour/01-crds.yaml | 28 +++++++++++++++
examples/render/contour-deployment.yaml | 28 +++++++++++++++
.../render/contour-gateway-provisioner.yaml | 28 +++++++++++++++
examples/render/contour-gateway.yaml | 28 +++++++++++++++
examples/render/contour.yaml | 28 +++++++++++++++
.../contourconfig/contourconfiguration.go | 8 +++++
.../contourconfiguration_test.go | 17 +++++++--
internal/dag/dag.go | 5 +++
internal/dag/policy.go | 7 ++++
internal/dag/policy_test.go | 22 ++++++++++++
internal/envoy/v3/route.go | 6 ++++
internal/envoy/v3/route_test.go | 36 +++++++++++++++++++
pkg/config/parameters.go | 13 +++++++
pkg/config/parameters_test.go | 3 ++
.../docs/main/config/api-reference.html | 31 ++++++++++++++++
20 files changed, 309 insertions(+), 3 deletions(-)
create mode 100644 changelogs/unreleased/6895-nickburgin-small.md
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/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
From 18151c3eb06c7ddfdc7f4a77924318a43714d69a Mon Sep 17 00:00:00 2001
From: Nick Burgin
Date: Thu, 13 Feb 2025 15:34:58 +1100
Subject: [PATCH 2/2] fixup! configuration: Add support for Envoys
MaxStreamDuration configuration
Adds entirely missing test coverage for the timeouts configuration section in servecontext
Signed-off-by: Nick Burgin
---
cmd/contour/servecontext_test.go | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
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
|