diff --git a/internal/gatewayapi/clienttrafficpolicy.go b/internal/gatewayapi/clienttrafficpolicy.go index 83d38cd5a08..0ee2c28a4a3 100644 --- a/internal/gatewayapi/clienttrafficpolicy.go +++ b/internal/gatewayapi/clienttrafficpolicy.go @@ -386,7 +386,8 @@ func translateHTTP1Settings(http1Settings *egv1a1.HTTP1Settings, httpIR *ir.HTTP return } httpIR.HTTP1 = &ir.HTTP1Settings{ - EnableTrailers: ptr.Deref(http1Settings.EnableTrailers, false), + EnableTrailers: ptr.Deref(http1Settings.EnableTrailers, false), + PreserveHeaderCase: ptr.Deref(http1Settings.PreserveHeaderCase, false), } } diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-preserve-case.in.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-preserve-case.in.yaml new file mode 100644 index 00000000000..5a5711f32ed --- /dev/null +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-preserve-case.in.yaml @@ -0,0 +1,36 @@ +clientTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: ClientTrafficPolicy + metadata: + namespace: envoy-gateway + name: target-gateway-1 + spec: + http1: + enableTrailers: true + preserveHeaderCase: true + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http-1 + protocol: HTTP + port: 80 + allowedRoutes: + namespaces: + from: Same + - name: http-2 + protocol: HTTP + port: 8080 + allowedRoutes: + namespaces: + from: Same diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-preserve-case.out.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-preserve-case.out.yaml new file mode 100644 index 00000000000..c291e36929d --- /dev/null +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-preserve-case.out.yaml @@ -0,0 +1,146 @@ +clientTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: ClientTrafficPolicy + metadata: + creationTimestamp: null + name: target-gateway-1 + namespace: envoy-gateway + spec: + http1: + enableTrailers: true + preserveHeaderCase: true + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + status: + conditions: + - lastTransitionTime: null + message: ClientTrafficPolicy has been accepted. + reason: Accepted + status: "True" + type: Accepted +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + creationTimestamp: null + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: Same + name: http-1 + port: 80 + protocol: HTTP + - allowedRoutes: + namespaces: + from: Same + name: http-2 + port: 8080 + protocol: HTTP + status: + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http-1 + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http-2 + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +infraIR: + envoy-gateway/gateway-1: + proxy: + listeners: + - address: null + name: envoy-gateway/gateway-1/http-1 + ports: + - containerPort: 10080 + name: http-1 + protocol: HTTP + servicePort: 80 + - address: null + name: envoy-gateway/gateway-1/http-2 + ports: + - containerPort: 8080 + name: http-2 + protocol: HTTP + servicePort: 8080 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + name: envoy-gateway/gateway-1 +xdsIR: + envoy-gateway/gateway-1: + accessLog: + text: + - path: /dev/stdout + http: + - address: 0.0.0.0 + hostnames: + - '*' + http1: + enableTrailers: true + preserveHeaderCase: true + isHTTP2: false + name: envoy-gateway/gateway-1/http-1 + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + - address: 0.0.0.0 + hostnames: + - '*' + http1: + enableTrailers: true + preserveHeaderCase: true + isHTTP2: false + name: envoy-gateway/gateway-1/http-2 + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 8080 diff --git a/internal/ir/infra.go b/internal/ir/infra.go index 27813573648..dc41bbe7c88 100644 --- a/internal/ir/infra.go +++ b/internal/ir/infra.go @@ -76,7 +76,8 @@ type HTTP3Settings struct { // HTTP1Settings provides HTTP/1 configuration on the listener. // +k8s:deepcopy-gen=true type HTTP1Settings struct { - EnableTrailers bool `json:"enableTrailers,omitempty" yaml:"enableTrailers,omitempty"` + EnableTrailers bool `json:"enableTrailers,omitempty" yaml:"enableTrailers,omitempty"` + PreserveHeaderCase bool `json:"preserveHeaderCase,omitempty" yaml:"preserveHeaderCase,omitempty"` } // ListenerPort defines a network port of a listener. diff --git a/internal/xds/translator/cluster.go b/internal/xds/translator/cluster.go index f3a6eb24266..74cb01c9101 100644 --- a/internal/xds/translator/cluster.go +++ b/internal/xds/translator/cluster.go @@ -14,6 +14,7 @@ import ( clusterv3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" corev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" endpointv3 "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" + preservecasev3 "github.com/envoyproxy/go-control-plane/envoy/extensions/http/header_formatters/preserve_case/v3" proxyprotocolv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/proxy_protocol/v3" rawbufferv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/raw_buffer/v3" httpv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/upstreams/http/v3" @@ -23,6 +24,7 @@ import ( "google.golang.org/protobuf/types/known/anypb" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/wrapperspb" + "k8s.io/utils/ptr" "github.com/envoyproxy/gateway/internal/ir" ) @@ -42,7 +44,7 @@ type xdsClusterArgs struct { proxyProtocol *ir.ProxyProtocol circuitBreaker *ir.CircuitBreaker healthCheck *ir.HealthCheck - enableTrailers bool + http1Settings *ir.HTTP1Settings } type EndpointType int @@ -96,7 +98,8 @@ func buildXdsCluster(args *xdsClusterArgs) *clusterv3.Cluster { break } } - cluster.TypedExtensionProtocolOptions = buildTypedExtensionProtocolOptions(isHTTP2, args.enableTrailers) + cluster.TypedExtensionProtocolOptions = buildTypedExtensionProtocolOptions(isHTTP2, + ptr.Deref(args.http1Settings, ir.HTTP1Settings{})) // Set Load Balancer policy //nolint:gocritic @@ -314,44 +317,51 @@ func buildXdsClusterLoadAssignment(clusterName string, destSettings []*ir.Destin return &endpointv3.ClusterLoadAssignment{ClusterName: clusterName, Endpoints: localities} } -func buildTypedExtensionProtocolOptions(http2, http1Trailers bool) map[string]*anypb.Any { +func buildTypedExtensionProtocolOptions(http2 bool, http1Opts ir.HTTP1Settings) map[string]*anypb.Any { + if !http2 && !http1Opts.EnableTrailers && !http1Opts.PreserveHeaderCase { + return nil + } var anyProtocolOptions *anypb.Any + protocolOptions := httpv3.HttpProtocolOptions{} if http2 { - protocolOptions := httpv3.HttpProtocolOptions{ - UpstreamProtocolOptions: &httpv3.HttpProtocolOptions_ExplicitHttpConfig_{ - ExplicitHttpConfig: &httpv3.HttpProtocolOptions_ExplicitHttpConfig{ - ProtocolConfig: &httpv3.HttpProtocolOptions_ExplicitHttpConfig_Http2ProtocolOptions{}, - }, + protocolOptions.UpstreamProtocolOptions = &httpv3.HttpProtocolOptions_ExplicitHttpConfig_{ + ExplicitHttpConfig: &httpv3.HttpProtocolOptions_ExplicitHttpConfig{ + ProtocolConfig: &httpv3.HttpProtocolOptions_ExplicitHttpConfig_Http2ProtocolOptions{}, }, } - - anyProtocolOptions, _ = anypb.New(&protocolOptions) - } else if http1Trailers { - // TODO: If the cluster is TLS enabled, use AutoHTTPConfig instead of ExplicitHttpConfig - // so that when ALPN is supported enabling trailers doesn't force HTTP/1.1 - protocolOptions := httpv3.HttpProtocolOptions{ - UpstreamProtocolOptions: &httpv3.HttpProtocolOptions_ExplicitHttpConfig_{ - ExplicitHttpConfig: &httpv3.HttpProtocolOptions_ExplicitHttpConfig{ - ProtocolConfig: &httpv3.HttpProtocolOptions_ExplicitHttpConfig_HttpProtocolOptions{ - HttpProtocolOptions: &corev3.Http1ProtocolOptions{ - EnableTrailers: http1Trailers, - }, + } else if http1Opts.EnableTrailers || http1Opts.PreserveHeaderCase { + opts := &corev3.Http1ProtocolOptions{ + EnableTrailers: http1Opts.EnableTrailers, + } + if http1Opts.PreserveHeaderCase { + preservecaseAny, _ := anypb.New(&preservecasev3.PreserveCaseFormatterConfig{}) + opts.HeaderKeyFormat = &corev3.Http1ProtocolOptions_HeaderKeyFormat{ + HeaderFormat: &corev3.Http1ProtocolOptions_HeaderKeyFormat_StatefulFormatter{ + StatefulFormatter: &corev3.TypedExtensionConfig{ + Name: "preserve_case", + TypedConfig: preservecaseAny, }, }, + } + } + // TODO: If the cluster is TLS enabled, use AutoHTTPConfig instead of ExplicitHttpConfig + // so that when ALPN is supported setting HTTP/1.1 options doesn't force HTTP/1.1 + protocolOptions.UpstreamProtocolOptions = &httpv3.HttpProtocolOptions_ExplicitHttpConfig_{ + ExplicitHttpConfig: &httpv3.HttpProtocolOptions_ExplicitHttpConfig{ + ProtocolConfig: &httpv3.HttpProtocolOptions_ExplicitHttpConfig_HttpProtocolOptions{ + HttpProtocolOptions: opts, + }, }, } - anyProtocolOptions, _ = anypb.New(&protocolOptions) } + anyProtocolOptions, _ = anypb.New(&protocolOptions) - if anyProtocolOptions != nil { - extensionOptions := map[string]*anypb.Any{ - extensionOptionsKey: anyProtocolOptions, - } - - return extensionOptions + extensionOptions := map[string]*anypb.Any{ + extensionOptionsKey: anyProtocolOptions, } - return nil + + return extensionOptions } // buildClusterName returns a cluster name for the given `host` and `port`. diff --git a/internal/xds/translator/listener.go b/internal/xds/translator/listener.go index e3ad6cadc49..5cde4d7a708 100644 --- a/internal/xds/translator/listener.go +++ b/internal/xds/translator/listener.go @@ -16,6 +16,7 @@ import ( hcmv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3" tcpv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/tcp_proxy/v3" udpv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/udp/udp_proxy/v3" + preservecasev3 "github.com/envoyproxy/go-control-plane/envoy/extensions/http/header_formatters/preserve_case/v3" quicv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/quic/v3" tlsv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3" "github.com/envoyproxy/go-control-plane/pkg/resource/v3" @@ -44,12 +45,24 @@ func http1ProtocolOptions(opts *ir.HTTP1Settings) *corev3.Http1ProtocolOptions { if opts == nil { return nil } - if opts.EnableTrailers { - return &corev3.Http1ProtocolOptions{ - EnableTrailers: opts.EnableTrailers, + if !opts.EnableTrailers && !opts.PreserveHeaderCase { + return nil + } + r := &corev3.Http1ProtocolOptions{ + EnableTrailers: opts.EnableTrailers, + } + if opts.PreserveHeaderCase { + preservecaseAny, _ := anypb.New(&preservecasev3.PreserveCaseFormatterConfig{}) + r.HeaderKeyFormat = &corev3.Http1ProtocolOptions_HeaderKeyFormat{ + HeaderFormat: &corev3.Http1ProtocolOptions_HeaderKeyFormat_StatefulFormatter{ + StatefulFormatter: &corev3.TypedExtensionConfig{ + Name: "preserve_case", + TypedConfig: preservecaseAny, + }, + }, } } - return nil + return r } func http2ProtocolOptions() *corev3.Http2ProtocolOptions { diff --git a/internal/xds/translator/testdata/in/xds-ir/http1-preserve-case.yaml b/internal/xds/translator/testdata/in/xds-ir/http1-preserve-case.yaml new file mode 100644 index 00000000000..f857ac8f854 --- /dev/null +++ b/internal/xds/translator/testdata/in/xds-ir/http1-preserve-case.yaml @@ -0,0 +1,40 @@ +http: +- name: "first-listener" + address: "0.0.0.0" + port: 10080 + hostnames: + - "*" + http1: + preserveHeaderCase: true + path: + mergeSlashes: true + escapedSlashesAction: UnescapeAndRedirect + routes: + - name: "first-route" + hostname: "*" + destination: + name: "first-route-dest" + settings: + - endpoints: + - host: "1.2.3.4" + port: 50000 +- name: "second-listener" + address: "0.0.0.0" + port: 10081 + hostnames: + - "*" + http1: + preserveHeaderCase: true + enableTrailers: true + path: + mergeSlashes: true + escapedSlashesAction: UnescapeAndRedirect + routes: + - name: "second-route" + hostname: "*" + destination: + name: "second-route-dest" + settings: + - endpoints: + - host: "1.2.3.5" + port: 50000 diff --git a/internal/xds/translator/testdata/out/xds-ir/http1-preserve-case.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/http1-preserve-case.clusters.yaml new file mode 100644 index 00000000000..3799e281ee2 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/http1-preserve-case.clusters.yaml @@ -0,0 +1,49 @@ +- commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: first-route-dest + lbPolicy: LEAST_REQUEST + name: first-route-dest + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + httpProtocolOptions: + headerKeyFormat: + statefulFormatter: + name: preserve_case + typedConfig: + '@type': type.googleapis.com/envoy.extensions.http.header_formatters.preserve_case.v3.PreserveCaseFormatterConfig +- commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: second-route-dest + lbPolicy: LEAST_REQUEST + name: second-route-dest + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + httpProtocolOptions: + enableTrailers: true + headerKeyFormat: + statefulFormatter: + name: preserve_case + typedConfig: + '@type': type.googleapis.com/envoy.extensions.http.header_formatters.preserve_case.v3.PreserveCaseFormatterConfig diff --git a/internal/xds/translator/testdata/out/xds-ir/http1-preserve-case.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/http1-preserve-case.endpoints.yaml new file mode 100644 index 00000000000..28a57caf3b5 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/http1-preserve-case.endpoints.yaml @@ -0,0 +1,24 @@ +- clusterName: first-route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.2.3.4 + portValue: 50000 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: first-route-dest/backend/0 +- clusterName: second-route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.2.3.5 + portValue: 50000 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: second-route-dest/backend/0 diff --git a/internal/xds/translator/testdata/out/xds-ir/http1-preserve-case.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/http1-preserve-case.listeners.yaml new file mode 100644 index 00000000000..8827d4b75fa --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/http1-preserve-case.listeners.yaml @@ -0,0 +1,79 @@ +- address: + socketAddress: + address: 0.0.0.0 + portValue: 10080 + defaultFilterChain: + filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + commonHttpProtocolOptions: + headersWithUnderscoresAction: REJECT_REQUEST + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 + maxConcurrentStreams: 100 + httpFilters: + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + httpProtocolOptions: + headerKeyFormat: + statefulFormatter: + name: preserve_case + typedConfig: + '@type': type.googleapis.com/envoy.extensions.http.header_formatters.preserve_case.v3.PreserveCaseFormatterConfig + mergeSlashes: true + normalizePath: true + pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT + rds: + configSource: + ads: {} + resourceApiVersion: V3 + routeConfigName: first-listener + statPrefix: http + upgradeConfigs: + - upgradeType: websocket + useRemoteAddress: true + name: first-listener + perConnectionBufferLimitBytes: 32768 +- address: + socketAddress: + address: 0.0.0.0 + portValue: 10081 + defaultFilterChain: + filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + commonHttpProtocolOptions: + headersWithUnderscoresAction: REJECT_REQUEST + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 + maxConcurrentStreams: 100 + httpFilters: + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + httpProtocolOptions: + enableTrailers: true + headerKeyFormat: + statefulFormatter: + name: preserve_case + typedConfig: + '@type': type.googleapis.com/envoy.extensions.http.header_formatters.preserve_case.v3.PreserveCaseFormatterConfig + mergeSlashes: true + normalizePath: true + pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT + rds: + configSource: + ads: {} + resourceApiVersion: V3 + routeConfigName: second-listener + statPrefix: http + upgradeConfigs: + - upgradeType: websocket + useRemoteAddress: true + name: second-listener + perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/http1-preserve-case.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/http1-preserve-case.routes.yaml new file mode 100644 index 00000000000..d36b9824e31 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/http1-preserve-case.routes.yaml @@ -0,0 +1,24 @@ +- ignorePortInHostMatching: true + name: first-listener + virtualHosts: + - domains: + - '*' + name: first-listener/* + routes: + - match: + prefix: / + name: first-route + route: + cluster: first-route-dest +- ignorePortInHostMatching: true + name: second-listener + virtualHosts: + - domains: + - '*' + name: second-listener/* + routes: + - match: + prefix: / + name: second-route + route: + cluster: second-route-dest diff --git a/internal/xds/translator/translator.go b/internal/xds/translator/translator.go index ab10da49cb1..3eb87eb6b6c 100644 --- a/internal/xds/translator/translator.go +++ b/internal/xds/translator/translator.go @@ -20,7 +20,6 @@ import ( matcherv3 "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3" resourcev3 "github.com/envoyproxy/go-control-plane/pkg/resource/v3" "google.golang.org/protobuf/types/known/wrapperspb" - "k8s.io/utils/ptr" extensionTypes "github.com/envoyproxy/gateway/internal/extension/types" "github.com/envoyproxy/gateway/internal/ir" @@ -260,8 +259,7 @@ func (t *Translator) processHTTPListenerXdsTranslation( vHost.Routes = append(vHost.Routes, xdsRoute) if httpRoute.Destination != nil { - trailers := ptr.Deref(httpListener.HTTP1, ir.HTTP1Settings{}).EnableTrailers - if err = processXdsCluster(tCtx, httpRoute, trailers); err != nil { + if err = processXdsCluster(tCtx, httpRoute, httpListener.HTTP1); err != nil { errs = errors.Join(errs, err) } } @@ -486,7 +484,7 @@ func findXdsEndpoint(tCtx *types.ResourceVersionTable, name string) *endpointv3. } // processXdsCluster processes a xds cluster by its endpoint address type. -func processXdsCluster(tCtx *types.ResourceVersionTable, httpRoute *ir.HTTPRoute, enableTrailers bool) error { +func processXdsCluster(tCtx *types.ResourceVersionTable, httpRoute *ir.HTTPRoute, http1Settings *ir.HTTP1Settings) error { // Get endpoint address type for xds cluster by returning the first DestinationSetting's AddressType, // since there's no Mixed AddressType among all the DestinationSettings. addrTypeState := httpRoute.Destination.Settings[0].AddressType @@ -507,7 +505,7 @@ func processXdsCluster(tCtx *types.ResourceVersionTable, httpRoute *ir.HTTPRoute proxyProtocol: httpRoute.ProxyProtocol, circuitBreaker: httpRoute.CircuitBreaker, healthCheck: httpRoute.HealthCheck, - enableTrailers: enableTrailers, + http1Settings: http1Settings, }); err != nil && !errors.Is(err, ErrXdsClusterExists) { return err } diff --git a/internal/xds/translator/translator_test.go b/internal/xds/translator/translator_test.go index ca8e39c7aa9..7d534d456ae 100644 --- a/internal/xds/translator/translator_test.go +++ b/internal/xds/translator/translator_test.go @@ -240,6 +240,9 @@ func TestTranslateXds(t *testing.T) { { name: "http1-trailers", }, + { + name: "http1-preserve-case", + }, } for _, tc := range testCases {